code_braking_phpmagic

题目是p神的code-breaking中的phpmagic。

先?read-source=1可以读到源码

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
<?php
if(isset($_GET['read-source'])) {
exit(show_source(__FILE__));
}

define('DATA_DIR', dirname(__FILE__) . '/data/' . md5($_SERVER['REMOTE_ADDR']));

if(!is_dir(DATA_DIR)) {
mkdir(DATA_DIR, 0755, true);
}
chdir(DATA_DIR);

$domain = isset($_POST['domain']) ? $_POST['domain'] : '';
$log_name = isset($_POST['log']) ? $_POST['log'] : date('-Y-m-d');
if(!empty($_POST) && $domain):
$command = sprintf("dig -t A -q %s", escapeshellarg($domain));
$output = shell_exec($command);
$output = htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES);

$log_name = $_SERVER['SERVER_NAME'] . $log_name;
if(!in_array(pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {
file_put_contents($log_name, $output);
}
echo $output;
endif;
?>

分析源码,首先创建了一个文件夹
路径为./data/md5($_SERVER['REMOTE_ADDR'])/

1
2
$command = sprintf("dig -t A -q %s", escapeshellarg($domain));
$output = shell_exec($command);

这里使用shell_exec执行了命令,但输入的domain被escapeshellarg处理过,没有其他条件,难以利用。

escapeshellarg($string) 把字符串转码为可以在shell命令里使用的参数 (确保用户只传递一个参数给命令)

1
2
3
4
5
$log_name = $_SERVER['SERVER_NAME'] . $log_name;
if(!in_array(pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {
file_put_contents($log_name, $output);
}
echo $output;

这里有写文件的操作,output被打印出来了的
在这里插入图片描述
这个命令会把我们传入的值输出出来,但在之前使用了htmlspecialchars这个函数,使得所有的标签都被转化了。

1
$output = htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES);

我们可以使用php伪协议来写入文件,这样就不用担心标签字符失效了

这里还使用了pathinfo函数来取文件后缀,之后判断时候再黑名单中。
而pathinfo这个函数是可以被绕过的。

pathinfo函数只是取最后一个小数点之后的字符作为文件的后缀,因此很容易被绕过

这里用a.php/.a就能绕过,而且php://filter伪协议还能将其看做a.php
(详细可以看看:http://wonderkun.cc/index.html/?p=626)

我们要用php伪协议来写文件,所以文件名log_name一定是php://filter开头的。
log_name的赋值过程:

1
2
$log_name = isset($_POST['log']) ? $_POST['log'] : date('-Y-m-d');
$log_name = $_SERVER['SERVER_NAME'] . $log_name;

这里将log_name开头写成了$_SERVER[‘SERVER_NAME’]
查找资料,发现当我们使用ip访问的时候,$_SERVER[‘SERVER_NAME’]是可以伪造的。

到此,我们就可以构造payload了
<?php eval($_GET[1]); ?> base64==> PD9waHAgZXZhbCgkX0dFVFsxXSk7ICA/Pg==
因为我们输入的参数是在$output的中间部分,所以base64后的等号不能要,不然解base64时会出错
最后,
在这里插入图片描述

最后看上传的位置, ./data/md5($_SERVER['REMOTE_ADDR'])/
$_SERVER[‘REMOTE_ADDR’]是我们自己的ip地址
这里我的路径是 /data/dd546ac20717cd31b1ceaad3eb9911c1/
访问/data/dd546ac20717cd31b1ceaad3eb9911c1/shell.php,之后即可读取flag
在这里插入图片描述

知识点:

① php://filter可用来base64 bypass写入内容
② pathinfo可以用/.来绕过
③ $_SERVER[‘SERVER_NAME’]可通过Host进行伪造

文章作者: Dar1in9
文章链接: http://dar1in9s.github.io/2020/01/19/writeup/code_braking_phpmagic/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Dar1in9's Blog