Skip to content

Commit

Permalink
PHP-Audit-Labs
Browse files Browse the repository at this point in the history
  • Loading branch information
Mochazz committed Aug 7, 2018
1 parent 45a0524 commit 7876f2e
Show file tree
Hide file tree
Showing 55 changed files with 473 additions and 13 deletions.
Binary file added PHP-Audit-Labs题解/Day1-4/files/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PHP-Audit-Labs题解/Day1-4/files/9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
142 changes: 142 additions & 0 deletions PHP-Audit-Labs题解/Day1-4/files/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
## 前言

大家好,我们是红日安全-代码审计小组。最近我们小组正在做一个PHP代码审计的项目,供大家学习交流,我们给这个项目起了一个名字叫 **PHP-Audit-Labs** 。我们已经发表的系列文章如下:

[[红日安全]代码审计Day1 - in_array函数缺陷](https://xz.aliyun.com/t/2451)

[[红日安全]代码审计Day2 - filter_var函数缺陷](https://xz.aliyun.com/t/2457)

[[红日安全]代码审计Day3 - 实例化任意对象漏洞](https://xz.aliyun.com/t/2459)

[[红日安全]代码审计Day4 - strpos使用不当引发漏洞](https://xz.aliyun.com/t/2467)

在每篇文章的最后,我们都留了一道CTF题目,供大家练习。下面是 **Day1-Day4** 的题解:

## Day1题解:(By 七月火)

题目如下:

![1](1.png)

![2](2.png)

实际上这道题目考察的是 **in_array** 绕过和不能使用拼接函数的 **updatexml** 注入,我们先来看一下 **in_array** 的绕过。在下图第11~13行处,程序把用户的ID值存储在 **$whitelist** 数组中,然后将用户传入的 **id** 参数先经过stop_hack函数过滤,然后再用 **in_array** 来判断用户传入的 **id** 参数是否在 **$whitelist** 数组中。这里 **in_array** 函数没有使用强匹配,所以是可以绕过的,例如: **id=1'** 是可以成功绕过 **in_array** 函数的。

![3](3.png)

然后在说说 **updatexml** 注入,这题的注入场景也是在真实环境中遇到的。当 **updatexml** 中存在特殊字符或字母时,会出现报错,报错信息为特殊字符、字母及之后的内容,也就是说如果我们想要查询的数据是数字开头,例如 **7701HongRi** ,那么查询结果只会显示 **HongRi** 。所以我们会看到很多 **updatexml** 注入的 **payload** 是长这样的 **and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)** ,在所要查询的数据前面凭借一个特殊符号(这里的 **0x7e** 为符号 **'~'** )。

回到题目,我们看一下 **stop_hack** 函数过滤了什么。可以发现该方法过滤了字符串拼接函数(下图第2行),所以我们就要用其他方法来绕过。

![4](4.png)

我们直接来看一下本题的 **payload**

```http
http://localhost/index.php?id=4 and (select updatexml(1,make_set(3,'~',(select flag from flag)),1))
```

![5](5.png)

实际上,绕过的思路还是将特殊字符或字母拼接在我们想要的数据的前面,让数据的第一个字符为字母或符号即可,这里给出我以前写的分析 [**文章**](https://xz.aliyun.com/t/2160) ,供大家参考学习。

## Day2题解:(By 七月火)

题目如下:

![6](6.png)

这道CTF题目,实际上考察的是 **filter_var** 函数的绕过与远程命令执行。在题目 **第6行** ,程序使用 **exec** 函数来执行 **curl** 命令,这就很容易让人联系到命令执行。所以我们看看用于拼接命令的 **$site_info['host']** 从何而来。在题目 **第2-4行** ,可以看到 **$site_info** 变量是从用户传来的 **url** 参数经过 **filter_var****parse_url** 两个函数过滤而来。之后,又规定当 **url** 参数的值以 **sec-redclub.com** 结尾时,才会执行 **exec** 函数。

所以让我们先来绕过 **filter_var****FILTER_VALIDATE_URL** 过滤器,这里提供几个绕过方法,如下:

```bash
http://localhost/index.php?url=http://[email protected]
http://localhost/index.php?url=http://demo.com&sec-redclub.com
http://localhost/index.php?url=http://demo.com?sec-redclub.com
http://localhost/index.php?url=http://demo.com/sec-redclub.com
http://localhost/index.php?url=demo://demo.com,sec-redclub.com
http://localhost/index.php?url=demo://demo.com:80;sec-redclub.com:80/
http://localhost/index.php?url=http://demo.com#sec-redclub.com
PS:最后一个payload的#符号,请换成对应的url编码 %23
```

接着要绕过 **parse_url** 函数,并且满足 **$site_info['host']** 的值以 **sec-redclub.com** 结尾,payload如下:

```bash
http://localhost/index.php?url=demo://%22;ls;%23;sec-redclub.com:80/
```

![7](7.png)

当我们直接用 **cat f1agi3hEre.php** 命令的时候,过不了 **filter_var** 函数检测,因为包含空格,具体payload如下:

```bash
http://localhost/index.php?url=demo://%22;cat%20f1agi3hEre.php;%23;sec-redclub.com:80/
```

所以我们可以换成 **cat<f1agi3hEre.php** 命令,即可成功获取flag:

![8](8.png)

关于 **filter_var** 函数绕过更多的细节,大家可以参考这篇文章:[SSRF技巧之如何绕过filter_var( )](https://www.anquanke.com/post/id/101058) ,关于命令执行绕过技巧,大家可以参考这篇文章:[浅谈CTF中命令执行与绕过的小技巧](http://www.freebuf.com/articles/web/137923.html)

## Day3题解:(By 七月火)

题目如下:

![9](9.png)

这道题目考察的是实例化漏洞结合XXE漏洞。我们在上图第18行处可以看到使用了 **class_exists** 函数来判断类是否存在,如果不存在的话,就会调用程序中的 **__autoload** 函数,但是这里没有 **__autoload** 函数,而是用 [**spl_autoload_register**](http://php.net/manual/en/function.spl-autoload-register.php) 注册了一个类似 **__autoload** 作用的函数,即这里输出404信息。

我们这里直接利用PHP的内置类,先用 **GlobIterator** 类搜索 **flag文件** 名字,来看一下PHP手册对 **GlobIterator** 类的 构造函数的定义:

>public **GlobIterator::__construct** ( string `$pattern` [, int `$flags` = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO ] )
第一个参数为要搜索的文件名,第二个参数为选择文件的哪个信息作为键名,这里我选择用 **FilesystemIterator::CURRENT_AS_FILEINFO** ,其对应的常量值为0,你可以在 [这里](http://php.net/manual/en/globiterator.construct.php) 找到这些常量的值,所以最终搜索文件的 **payload** 如下:

```bash
http://localhost/CTF/index.php?name=GlobIterator&param=./*.php&param2=0
```

![10](10.png)

我们将会发现flag的文件名为 **f1agi3hEre.php** ,接下来我们使用内置类 **SimpleXMLElement** 读取 **f1agi3hEre.php** 文件的内容,,这里我们要结合使用PHP流的使用,因为当文件中存在: **< > & ' "** 这5个符号时,会导致XML文件解析错误,所以我们这里利用PHP文件流,将要读取的文件内容经过 **base64编码** 后输出即可,具体payload如下:

```bash
http://localhost/CTF/index.php?name=SimpleXMLElement&param=<?xml version="1.0"?><!DOCTYPE ANY [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/CTF/f1agi3hEre.php">]><x>%26xxe;</x>&param2=2
```

![11](11.png)

上面payload中的param2=2,实际上这里2对应的模式是 **LIBXML_NOENT** ,具体可以参考 [这里](http://php.net/manual/en/simplexmlelement.construct.php)

## Day4题解:(By 七月火)

本次题目为QCTF 2018中的一道题目,由于代码太多,这里就不贴出原图片。题目的场景为:一个彩票系统,每位用户初始情况下有20$,由用户输入一个7位数,系统也会随机生成一个7位数。然后逐位数字进行比较,位数相同的个数越多,奖励的前也越多。当你的钱足够买flag的时候,系统就会给你flag。

![12](12.png)

我们来看一下后台代码是如何进行比较的,比较代码在 **buy.php** 文件中:

![13](13.png)

在上图中看到表单的部分( **代码4-8行** ),调用了 **js/buy.js** 文件,应该是用来处理上面的表单的,我们具体看一下 **js** 代码:

![14](14.png)

**第10行** 处看到,程序将表单数据以 **json** 格式提交到服务器端,提交页面为 **api.php** ,我们转到该文件看看。

![15](15.png)

这里主要是对数字进行比较,注意 **第13行** 用的是 **==** 操作符对数据进行比较,这里会引发安全问题。因为用户的数据是以 **json** 格式传上来的,如果我们传一个数组,里面包含7个 **true** 元素,这样在比较的时候也是能相等的。因为 **==** 运算符只会判断两边数据的值是否相等,并不会判断数据的类型。而语言定义,除了 **0、false、null** 以外均为 **true** ,所以使用 **true** 和数字进行比较,返回的值肯定是 **true 。只要后台生成的随机数没有数字0,我们传入的payload就能绕过每位数字的比较。我们发送几次payload后,就可以买到flag了。

![16](16.png)

在看官方WP的时候,还发现另外一种解法,也是一种不错的思路。

>另外比赛过程中发现有的选手用了暴力重复注册然后买彩票的方法。考虑了一下这种方法花费的时间并不比直接审计代码短,为了给广大彩民一点希望,可以留作一种备选的非预期解,就没有改题加验证码或者提高flag价格。
## 总结

我们的项目会慢慢完善,如果大家喜欢可以关注 [ **PHP-Audit-Labs** ](https://github.com/hongriSec/PHP-Audit-Labs) 。大家若是有什么更好的解法,可以在文章底下留言,祝大家玩的愉快!
Binary file added Part1/Day6/.DS_Store
Binary file not shown.
Binary file added Part1/Day6/files/.DS_Store
Binary file not shown.
Binary file added Part1/Day6/files/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Part1/Day6/files/5.png
Binary file added Part1/Day6/files/6.png
Binary file added Part1/Day6/files/7.png
Binary file added Part1/Day6/files/8.png
Binary file added Part1/Day6/files/9.png
134 changes: 134 additions & 0 deletions Part1/Day6/files/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
本文由红日安全成员: **水清云影** 编写,如有不当,还望斧正。

## 前言

大家好,我们是红日安全-代码审计小组。最近我们小组正在做一个PHP代码审计的项目,供大家学习交流,我们给这个项目起了一个名字叫 [**PHP-Audit-Labs**](https://github.com/hongriSec/PHP-Audit-Labs) 。现在大家所看到的系列文章,属于项目 **第一阶段** 的内容,本阶段的内容题目均来自 [PHP SECURITY CALENDAR 2017](https://www.ripstech.com/php-security-calendar-2017/) 。对于每一道题目,我们均给出对应的分析,并结合实际CMS进行解说。在文章的最后,我们还会留一道CTF题目,供大家练习,希望大家喜欢。下面是 **第6篇** 代码审计文章:

## Day6 - Forst Pattern

题目叫福斯特模式,代码如下

![1](1.png)

**漏洞解析**

这一关考察的内容是由正则表达式不严谨导致的任意文件删除漏洞, 导致这一漏洞的原因在 **第21行****preg_replace** 中的 **pattern** 部分 ,该正则表达式并未起到过滤目录路径字符的作用。`[^a-z.-_]` 表示匹配除了 **a** 字符到 **z** 字符、**.** 字符到 **_** 字符之间的所有字符。因此,攻击者还是可以使用点和斜杠符号进行路径穿越,最终删除任意文件,例如使用 **payload**`action = delete&data = ../../ config.php`,便可删除 **config.php** 文件。

>[**preg_replace**](http://php.net/manual/zh/function.preg-replace.php):(PHP 4, PHP 5, PHP 7)
>
>**功能** : 函数执行一个正则表达式的搜索和替换
>
>**定义**`mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )`
>
>搜索 **subject** 中匹配 **pattern** 的部分, 如果匹配成功将其替换成 **replacement**
##实例分析

本次实例分析,我们选取的是 **WeEngine0.8** 版本。漏洞入口文件为 **web/source/site/category.ctrl.php** ,我们可以看到下图 **14行** 处调用了 **file_delete** 函数,而这是一个文件删除相关操作,我们可以看一下该函数的具体定义。下图是入口文件代码:

![2](2.png)

**file_delete** 这一函数可以在 **framework/function/file.func.php** 文件中找到,该方法功能用于检测文件是否存在,如果存在,则删除文件。但是查看上下文发现,程序并没有对文件名 **$file** 变量进行过滤,所以文件名就可以存在类似 **../** 这种字符,这样也就引发任意文件删除漏洞,**file_delete** 函数代码如下:

![3](3.png)

现在我们在回溯回去,看看 **$file** 变量从何处来。实际上,上图的 **$file** 变量对应的是 **$row['icon']** 的值,也就是说如果我们可以控制 **$row['icon']** 的值,就可以删除任意文件。那么我们来看看 **$row** 变量从何而来。该变量就在我们刚刚分析的第一张图片中( **web/source/site/category.ctrl.php** 文件),该值为变量 **$navs** 中的元素值,具体代码如下:

![4](4.png)

我们再往上看,即可找到 **$navs** 变量的取值情况。可以看到 **$navs** 变量的是是重数据库 **site_nav** 表中取出的,包含了 **icon****id** 两个字段,具体代码如下:

```php
$navs = pdo_fetchall("SELECT icon, id FROM ".tablename('site_nav')." WHERE id IN (SELECT nid FROM ".tablename('site_category')." WHERE id = {$id} OR parentid = '$id')", array(), 'id');
```

现在我们要做的,就是找找看数据库中的这两个字段是否可以被用户控制。我们继续往前查找,发现了如下代码:![5](5.png)

**site_nav** 表中的数据,对应的是 **$nav** 变量。我们继续往上寻找 **$nav** 变量,发现 **$nav['icon']** 变量是从 **$_GPC['iconfile']** 来的,即可被用户控制( 下图 **第21行** )。这里的 **$nav['icon']** 变量,其实就是我们文章开头分析的传入 **file_delete** 函数的参数,具体代码如下:

![6](6.png)

由于 **$nav['icon']** 变量可被用户控制,程序有没有对其进行消毒处理,直接就传入了 **file_delete** 函数,最终导致了文件删除漏洞。至此,我们分析完了整个漏洞的发生过程,接下看看如何进行攻击。

##漏洞验证

访问url:http://xxx.xxx.xxx.xxx/WeEngine/web/index.php?c=account&a=display ,点击管理公众号:

![](7.png)

找到分类设置,点击添加文章分类。这里对应的url为:http://xxx.xxx.xxx.xxx/WeEngine/web/index.php?c=site&a=category,实际上表示 **site** 控制器的 **category** 模块,即对应 **category.ctrl.php** 文件。

![8](8.png)

选择对应的内容,进入 **if($isnav)** 判断:

![9](9.png)


在上传图标位置输入要删除文件的路径

![10](10.png)

我们建立 **delete.txt** 文件,用于测试任意文件删除:

![11](11.png)

我们点击删除时,就会调用 **file_delete** 函数,同时就会删除掉我们插入到数据库中的图片名:

![12](12.png)

![13](13.png)

这个类型任意文件删除有点类似于二次注入,在添加分类时先把要删除的文件名称插入到数据库中,然后点击删除分类时,会从数据库中取出要删除的文件名。

##修复建议

漏洞是没有对 `$row['icon']` 参数进行过滤,可以将文件名内容加入目录阶层字符,造成任意文件删除漏洞,所以我们要在传入的参数中过滤"../"等目录阶层字符,避免目录穿越,删除其他文件夹下文件。我们在修复中可以过滤掉 `$row['icon']` 中的目录穿越字符,引入我们自定义的一个函数 `checkstr` 函数。同时 `$row['icon']` 只是文件的名称,并非是一个路径,因此过滤字符并不会影响到实际功能,对此修复意见我们提供如下代码:

![14](14.png)

## 结语

看完了上述分析,不知道大家是否对 **路径穿越问题** 有了更加深入的理解,文中用到的CMS可以从 [这里](https://pan.baidu.com/s/1dwZgXLBK_7It6qTVkamB_w ) 下载(密码:hgjm) 下载,当然文中若有不当之处,还望各位斧正。如果你对我们的项目感兴趣,欢迎发送邮件到 **[email protected]** 联系我们。**Day6** 的分析文章就到这里,我们最后留了一道CTF题目给大家练手,题目如下:

```php
// 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__);
?>
```

```php
// flag.php
<?php $flag = "HRCTF{Pr3g_R3plac3_1s_Int3r3sting}";?>
```



Binary file added Part1/Day7/.DS_Store
Binary file not shown.
Binary file added Part1/Day7/files/.DS_Store
Binary file not shown.
Binary file added Part1/Day7/files/1.png
Binary file added Part1/Day7/files/10.png
Binary file added Part1/Day7/files/11.png
Binary file added Part1/Day7/files/13.png
Binary file added Part1/Day7/files/14.png
Binary file added Part1/Day7/files/15.png
Binary file added Part1/Day7/files/16.png
Binary file added Part1/Day7/files/17.png
Binary file added Part1/Day7/files/18.png
Binary file added Part1/Day7/files/2.png
Binary file added Part1/Day7/files/3.png
Binary file added Part1/Day7/files/4.png
Binary file added Part1/Day7/files/5.png
Binary file added Part1/Day7/files/6.png
Binary file added Part1/Day7/files/7.png
Binary file added Part1/Day7/files/8.png
Binary file added Part1/Day7/files/9.png
Loading

0 comments on commit 7876f2e

Please sign in to comment.