背景
这周,给各位带来AWD攻防源码分析。在百越杯CTF比赛中,小学弟通过抓取访问日志得到漏洞利用的方法,于是斗哥决定拿到源码,分析题目的考点,为小伙伴们排忧解难。题目可以直接利用的大致有3个漏洞,登录接口万能密码绕过、任意重置密码漏洞、上传漏洞、以及反序列化。其中有个文件包含和eval()代码执行的没绕过防护规则,所以没有进行分析。
AWD 攻防源码下载:
链接: https://pan.baidu.com/s/1dE3M0X7
密码: 5wvc
万能密码
漏洞文件:
html\lib\User.php(第16-34行)中用户名没用做任何过滤直接传递到数据库查询语句中,因此可以通过构造万能密码
admin'or 1#
或者
'or 1#
绕过登录。
任意密码重置
html\lib\User.php(第91-101行)在重置密码的时候仅需要用户名和新密码即可,所以可以利用这个逻辑漏洞将admin的密码重置为新的密码,从而进行登录。
上传漏洞
相关文件:
html.htaccess(第1行)中将xxx后缀的文件当做PHP来执行。
AddType application/x-httpd-php .html .xxx
html\lib\File.php(第15行)中采用黑名单的过滤方法并没有过滤xxx后缀的文件,因此可以直接上传shell.xxx的webshell文件,且上传功能需要登录后才能访问。
$this->notallow=array("php", "php5", "php3", "php4", "php7", "pht", "phtml", "htaccess","html", "swf", "htm");
html\lib\File.php(第27行)中将上传的名称重命名为用户名_文件名.文件后缀,如
admin_getflag.xxx
username."_".fileinfo["extension"];
因此可以结合万能密码或任意密码重置登录后上传webShell获得Flag。
反序列化漏洞
html\common\home.php(第34-35行)很直接的告诉我们存在反序列化漏洞,且该文件不需要登录可以访问。
_POST['a'];
@unserialize($a);
文件源码:
源码分析:
反序列化时候首先会执行
__wakeup()
魔术方法,然后再执行
__destruct()
方法。其中
__wakeup()
使用了
waf
函数,因此整个
__wakeup()
过滤了空格,回车,换行,tab等字符,
__destruct()
中使用了
call_user_func_array()
通过回调的方式执行
ping
函数,并要求
args
是一个数组。因此可以在
args
中传入
cat /flag
从而执行其他命令获取flag。
解题思考:
问题一:
由于本题使用了private变量,在测试的时候发现有不可视的字符所以直接用base64编码得到序列化的字符PAYLOAD,然后在python中使用base64解码后提交,就可以得到flag;
后面查阅资料,根据如下结论可以知道private变量名前面的home需要在前后加上NULL空字符, 因此只要在请求中使用%00代替NULL字符即可 。
解决方法:
\x00 + 类名 + \x00 + 变量名 反序列化出来的是private变量, \x00 + * + \x00 + 变量名 反序列化出来的是protected变量, 而直接变量名反序列化出来的是public变量
参考自:http://0x48.pw/2016/09/13/0x22/
问题二:
__wakeup()
中使用
waf
函数过滤了空格,导致无法直接执行
cat /flag
,
这个问题首先想到的是绕过
__wakeup()
魔术方法,后面才考虑到之前小密圈中说的利用环境变量绕过一些关键字符的方法。
解决方法一:
当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过
__wakeup
的执行, 如,原本是O:6:”person”:1:,将1改为大于1的值即可,修改后O:6:”person”:2: ,这样就能绕过
__wakeup()
魔术方法,从而不需要考虑空格的问题。需要PHP before 5.6.25 and 7.x before 7.0.10。
参考自:
http://www.cnbraid.com/2016/unserialize.html
https://bugs.php.net/bug.php?id=72663
https://paper.seebug.org/39/
http://www.cnblogs.com/Mrsm1th/p/6835592.html
http://www.freebuf.com/vuls/116705.html