前言

根据红日安全写的文章,学习PHP代码审计的第五节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完题目会用一道CTF的题目和实例来加深巩固。这是之前写的,有兴趣可以去看看:
PHP代码审计01之in_array()函数缺陷
PHP代码审计02之filter_var()函数缺陷
PHP代码审计03之实例化任意对象漏洞
PHP代码审计04之strpos函数使用不当

漏洞分析

下面看题目,代码如下:
PHP代码审计05之正则使用不当-LMLPHP
题目漏洞是正则使用不严谨导致任意文件删除的漏洞,现在来具体分析,引起漏洞的地方在上面代码的21行,这里用到了preg_replace()函数,我们打开PHP手册来看看对这个函数的定义如下:
PHP代码审计05之正则使用不当-LMLPHP
了解了函数的用法,看上面代码,[^a-z.-_] 表示匹配除了 a 字符到 z 字符和. 字符到 _ 字符之间的所有字符,但是没有考虑到目录路径字符。这就直接可以任意删除文件,例如构造如下参数:
action=delete&data=../../config.php
将删除config.php文件。

CTF练习

通过上面的讲解,来用一道CTF题目来练习一下,也是关于正则的问题,先看代码:

//index.php
<?php
include 'flag.php';
if  ("POST" == $_SERVER['REQUEST_METHOD'])
{
    $password = $_POST['password'];
    if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))
    {
        echo 'Wrong Format';
        exit;
    }
    while (TRUE)
    {
        $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
        if (6 > preg_match_all($reg, $password, $arr))
            break;
        $c = 0;
        $ps = array('punct', 'digit', 'upper', 'lower');
        foreach ($ps as $pt)
        {
            if (preg_match("/[[:$pt:]]+/", $password))
            $c += 1;
        }
        if ($c < 3) break;
        if ("42" == $password) echo $flag;
        else echo 'Wrong password';
        exit;
    }
}
highlight_file(__FILE__);
?>
//flag.php
<?php $flag = "HRCTF{Pr3g_R3plac3_1s_Int3r3sting}";?>

这道题目考察了是否熟悉PHP正则表达的字符类,大体是下面这个表格:

想要更加详细的了解,建议翻阅PHP手册,了解了字符类,下面来分析代码,上面一共三处正则表达,第一处如下:

if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))

它表示的含义是匹配到可打印字符12往上包含12,^表示必须某类字符开头,$表示必须某类字符结尾。
第二处正则如下:


 $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;

它表示的含义是,把连续的字符,数字,大写,小写作为一段,最少分成六段,比如Test+0He 会分为T est + 0 H e六段。
下面看第三处正则:

$ps = array('punct', 'digit', 'upper', 'lower');
 foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
if ("42" == $password) echo $flag;

这里的含义是输入的字符必须包含字符,数字,大写,小写其中的三种往上。最后与42进行弱类型比较,都符合就输出flag,现在都解读清楚了,让咱们构造payload结果如下:
PHP代码审计05之正则使用不当-LMLPHP

实例分析

通过例题和CTF题目的讲解,是不是感觉棒棒的,现在咱们来分析实例吧,实例是LvyeCMS3.1,是基于ThinkPHP3.2.3框架。这个实例存在的漏洞也是函数使用不规范被绕过,导致任意文件删除。下面来具体分析:
先查看入口文件index.php
PHP代码审计05之正则使用不当-LMLPHP
可以看到公共目录,应用目录等一些信息。接下来再看看目录结构:
PHP代码审计05之正则使用不当-LMLPHP
而漏洞在Application/Template/Controller/StyleController.class.php文件中,具体如下:
PHP代码审计05之正则使用不当-LMLPHP
看代码第117行,这里是获取目录路径,参数也是我们可以控制的,再向后看,用到了str_replace()函数,它是个字符串替换函数,具体说明如下:
PHP代码审计05之正则使用不当-LMLPHP
再这里起到的作用就是将'..\', '../', './', '.\'替换为空。但是这里是可以绕过的,如果我们输入.....///呢,会发生什么?是不是正好构造成了../,举个小例子会更清楚,如下:
PHP代码审计05之正则使用不当-LMLPHP
构造出../我们就可以穿越目录了,现在访问install.php文件会提示已安装,如下图:
PHP代码审计05之正则使用不当-LMLPHP
然后尝试删除lvyecms/Application/Install/目录下的 install.lock 文件,构造payload如下:
http://www.xxx.com/index.php?g=Template&m=Style&a=delete&dir=.....///Application/Install/&file=install.lock
PHP代码审计05之正则使用不当-LMLPHP
现在访问install.php,发现确实删除了,如下图:
PHP代码审计05之正则使用不当-LMLPHP

小结

通过这篇文章的学习与讲解,是不是对PHP的正则了解的更多了呢,下一篇文章会对parse_str函数缺陷进行学习和讲解。一起加油吧!

12-30 02:36