前言

玩了下QCTFWeb部分,非职业赛棍学到了不少的东西,Web部分同时感觉并不是很难,可能是因为同样是X-Man选拔赛的原因,Web,RE,Misc等考点比较全面,ORZ。写的时候赛题已经关闭,但还是尽量写清楚。

NewsCenter

嗯,签到题,搜索框的POST参数存在注入,抓包如下:

Web QCTF-WrtieUp-2018-孤独常伴

保存到1.txt,扔进SQLMAP。

直接跑出FLAG

Web QCTF-WrtieUp-2018-孤独常伴

Lottery

这个题目的思路很简单,直接购买FLAG就行,没错,有钱就是可以为所欲为…… ORZ

扫描后发现.git目录,直接使用dvcs-ripper工具进行还原

./rip-git.pl -m -o /root/dvcs-ripper-master/ -v -u http://47.96.118.255:8888/.git/

得到源代码后进行审计,找到问题的处理函数


我们要增加我们的金币,就需要在switch/case这里选择靠后开关,


后直接修改发送请求的内容,就能有足够的钱购买FLAG,为所欲为。。。。

Confusion1

confusion1的描述


进入题目后,把里面的东西都点了点,发现是一个和描述一样的网站,功能不全,点击登陆和注册都是404。

404的页面会把不存在的页面路径作为提示输出在页面,首先想到XSS,但没找到XSS提交点。

还发现了网页注释提示Flag藏在服务器目录下,那这就不该是XSS。

然后网页正中间的图片是蟒蛇缠着大象,那这个题目应该就是和Python有关。

404页面 + Python 很容易就联想到 Flask jinja injection(SSTI)。

于是做了一个测试{% raw %} {{ 12 }} {% endraw %} ,发现页面的提示输出变成了12,这里已经可以确定是SSTI。

以前就有类似的题目,直接用以前的Payload


发现存在简单的过滤,过滤了__class__,__subclasses__,read等关键字

这里我们可以将过滤的属性名变为参数拼接起,就能绕过过滤。

于是我编写了Payload

本地测试通过,能够成功读取文件,但是发现这个题目很奇怪发现是500。

卡了很久,后面发现是getattr函数选择上出现了错误。

当输入{% raw %} {{ geattr }} {% endraw %}后,页面并没有返回<built-in function getattr>信息

题目应该是删除或者过滤了这个函数。

这我们就选择__getattribute__,输入{% raw %} {{ (). __getattribute__ }} {% endraw %},成功返回信息


修改Payload如下,成功获取FLAG


这需要注意的是第三个__getattribute__函数是需要传入两个参数的__getattribute__(object,attribute)

其实这个函数本身就有两个参数,当我们通过(). __getattribute__这种指定对象的方式调用的时候object为self并且自动传入函数, 但是当我们使用__base__基类对象进行调用__getattribute__的时候就需要指定object

Confusion2

confusion2的描述

首先是注册和登陆,有个常规验证码,直接跑出来

注册后登陆

发现Cookie里面存在一个token的键,并且键值为JWT


Decode后如下图

Web QCTF-WrtieUp-2018-孤独常伴

这里比较关键的是生成签名的算法并非标准的JWT算法HS256 ES256等,而是使用的sha256,卡了好久。

以为header里面的"alg": "sha256"只是单纯的改了而已

这里还有就是要用到上面的salt文件的提示,这个文件里存储着salt,值为_Y0uW1llN3verKn0w1t_。

根据这个题目的提示我们可以知道这个salt的位置为最后

第三部分的签名生成格式如下,那么我们就可以伪造JWT了


再看看Payload的内容


data的键值字符串是一串php序列化的字符串

User类,包含user_data这个属性,属性的值为,长度为60

这个值是Python序列化的字符串

这里我们直接联想到Python反序列化的RCE,这里不再赘述。

我们首先构造好Python的RCE的字符串然后,放进PHP的序列化的字符串里面,然后直接根据上文JWT算法算出对应的签名,替换Cookie,就能执行任意命令,Flag通过HTTP外带出来就行了。