# 打造自己的php半自动化代码审计工具

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2016-01-04T02:00:00Z
Canonical: https://wepostx.com/topics/1280

> 乌云历史资料归档
>
> **原始作者：** Matt
> **原始编号：** superkieran-wooyundrops:980
> **原始发布时间：** 2016-01-04 10:00
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 PHP扩展进行代码分析（动态分析）

### 一.基础环境

```text
#!bash apt-get install php5 apt-get install php5-dev apt-get install apache apt-get install mysql
```

### 二.使用PHPTracert

```text
#!bash mkdir godhead wget https://github.com/Qihoo360/phptrace/archive/v0.3.0.zip unzip v0.3.0.zip cd ./phptrace-0.3.0/extension phpize5 ./configure --with-php-config=/usr/bin/php-config make & make install cd ../cmdtool make
```
编辑php.ini，增加:

```text
#!bash extension=trace.so
```

### 三.测试

```text
#!php <?php for($i=0;$i<100;$i++){ echo $I; sleep(1); } ?>
```
CLI

```text
#!shell php test.php & ps -axu|grep php ./phptrace -p pid
```
apache

```text
#!bash curl 127.0.0.1/test.php ps -aux|grep apache ./phptrace -p pid
```

### 四.phptrace分析
执行的代码如下:

```text
#!php <?php function c(){ echo 1; } function b(){ c(); } function a(){ b(); } a(); ?>
```
执行顺序是:

```text
#!bash a>b>c>echo
```
参数含义:
名称值意义
seqint|执行的函数的次数
type1/21是代表调用函数，2是代表该函数返回
level-10执行深度，比如a函数调用b，那么a的level就是1，b的level就是2，依次递增
funceval调用的函数名称
st1448387651119460时间戳
paramsstring函数的参数
filec.php执行的文件
lineno1此函数对应的行号
日志输出:

```text
#!js {"seq":0, "type":1, "level":1, "func":"{main}", "st":1448387651119445, "params":"", "file":"/var/www/html/2.php", "lineno":11 } {"seq":1, "type":1, "level":2, "func":"a", "st":1448387651119451, "params":"", "file":"/var/www/html/2.php", "lineno":11 } {"seq":2, "type":1, "level":3, "func":"b", "st":1448387651119452, "params":"", "file":"/var/www/html/2.php", "lineno":9 } {"seq":3, "type":1, "level":4, "func":"c", "st":1448387651119453, "params":"", "file":"/var/www/html/2.php", "lineno":6 } {"seq":4, "type":2, "level":4, "func":"c, "st":1448387651119457, "return":"NULL", "wt":4, "ct":4, "mem":48, "pmem":144 } {"seq":5, "type":2, "level":3, "func":"b, "st":1448387651119459, "return":"NULL", "wt":7, "ct":6, "mem":48, "pmem":144 } {"seq":6, "type":2, "level":2, "func":"a, "st":1448387651119459, "return":"NULL", "wt":8, "ct":8, "mem":80, "pmem":176 } {"seq":7, "type":2, "level":1, "func":"{main}, "st":1448387651119460, "return":"1", "wt":15, "ct":14, "mem":112, "pmem":208 }
```

### 五.逻辑分析
1.解析监控进程
开一个后台进程一直刷新进程列表，如果出现没有tracer的进程就立即进行托管
2.json提取
通过对每一个文件的json进行提取，提取过程如下:

- 便利所有文件

- 读读取文件

- 提取json，按照seq排序

- 提取type=2的与type=1的进行合并

- 按照level梳理上下级关系存储同一个字典

- 按照seq排序，取出头函数进行输出

- 提取恶意函数往上提取level直到level=0
函数对应如下:

```text
#!python list1={ level1:[seq,type,func,param,return] level2:[seq,type,func,param,return] level3:[seq,type,func,param,return] #eval level4:[seq,type,func,param,return] } list2=
```
3.数据查看
通过追踪危险函数，然后将其函数执行之前的关系梳理出来进行输出，然后再进行人工审查。
放上demo

![原文图片](/media/2016/06/7d3d3eab7554a166e878df0e8fac953e)

![原文图片](/media/2016/06/68e9e24aabd5e3e7b2d36ae3849fa6e0)

### 六.使用XDEBUG
安装

```text
#!bash apt-get install php5-xdebug
```
修改php.ini

```text
#!bash [xdebug] zend_extension = "/usr/lib/php5/20131226/xdebug.so" xdebug.auto_trace = on xdebug.auto_profile = on xdebug.collect_params = on xdebug.collect_return = on xdebug.profiler_enable = on xdebug.trace_output_dir = "/tmp/ad/xdebug_log" xdebug.profiler_output_dir = "/tmp/ad/xdebug_log"
```
放上几个demo图片:

![原文图片](/media/2016/06/095d54657f52e5e44c713590d859915a)

### 七.优缺点
缺点
人为参与力度较大，无法进行脱离人工的操作进行独立执行。
优点
精准度高，对于面向对象和面向过程的代码都可以进行分析。

# 0x01 语法分析（静态分析）

案例：

- [http://php-grinder.com/](http://php-grinder.com/)

- [http://rips-scanner.sourceforge.net/](http://rips-scanner.sourceforge.net/)

### 一.使用php-parser
介绍：

- [http://www.oschina.net/p/php-parser](http://www.oschina.net/p/php-parser)

- [https://github.com/nikic/PHP-Parser/](https://github.com/nikic/PHP-Parser/)

### 二.安装

```text
#!shell git clone https://github.com/nikic/PHP-Parser.git & cd PHP-Parser curl -sS https://getcomposer.org/installer | php
```
PHP >= 5.3; for parsing PHP 5.2 to PHP 5.6

```text
#!bash php composer.phar require nikic/php-parser
```
PHP >= 5.4; for parsing PHP 5.2 to PHP 7.0

```text
#!bash php composer.phar require nikic/php-parser 2.0.x-dev
```

### 三.测试

```text
#!php <?php include 'autoload.php'; use PhpParser\Error; use PhpParser\ParserFactory; $code = '<?php eval($_POST[c][/c])?>'; $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); try { $stmts = $parser->parse($code); print_r($stmts); // $stmts is an array of statement nodes } catch (Error $e) { echo 'Parse Error: ', $e->getMessage(); }
```
输出如下:

```text
#!js Array ( [0] => PhpParser\Node\Expr\Eval_ Object ( [expr] => PhpParser\Node\Expr\ArrayDimFetch Object ( [var] => PhpParser\Node\Expr\Variable Object ( [name] => _POST [attributes:protected] => Array ( [startLine] => 1 [endLine] => 1 ) ) [dim] => PhpParser\Node\Expr\ConstFetch Object ( [name] => PhpParser\Node\Name Object ( [parts] => Array ( [0] => c ) [attributes:protected] => Array ( [startLine] => 1 [endLine] => 1 ) ) [attributes:protected] => Array ( [startLine] => 1 [endLine] => 1 ) ) [attributes:protected] => Array ( [startLine] => 1 [endLine] => 1 ) ) [attributes:protected] => Array ( [startLine] => 1 [endLine] => 1 ) ) )
```
由此可见，我们需要提取出

```text
#!js [0] => PhpParser\Node\Expr\Eval_ Object [name] => _POST [parts] => Array ( [0] => c )
```
然后进行拼接之后即可发现原始语句是:

```text
#!php eval($_POST[c][/c])
```

### 四.逻辑分析
代码解析

- 通过该库进行语法分析

- 提取结果

- 提取危险函数

- 提取危险函数中存在的变量

- 从上文中提取此变量的赋值方式

- 分析出可控结果

- 输出结果

### 五.优缺点
缺点
对于面向对象的程序进行分析比较弱。
优点
适合大批量的自动化分析，可以脱离人工操作进行独立执行

## Replies
