代码审计常见的三种方法(PHP篇)

0x00 前言

之前也做过一些代码审计,主要语言是PHP,大部分情况下,都是东一榔头西一棒,非常不优雅,甚至有时为了找一个功能点的代码,翻来倒去很久,浪费时间。偶然看见国光0rz的php代码审计环境的搭建,在搭建完之后,我又尝试对国光大佬0rz分析过了的一个企业建站系统进行简单复现,得益于代码审计环境尤其是PHP调试环境的搭建,我很快就可以定位到功能点的具体代码,大大缩短寻找功能点代码的时间,提高审计效率。于是记录一下现在的一个审计过程。文章偏小白,大佬轻喷0rz。

0x01 环境准备

环境准备方面,前人之述备矣。参考:

macOS 下优雅地配置 PHP 代码审计环境

环境解决之后,接下来本菜鸡将以新秀企业建站系统为例简述现在的代码审计流程。

参考链接:PHP代码审计初次尝试之新秀企业网站系统

0x02 从代码本身找漏洞

不知道大家在进行白盒测试的时候,一般使用什么样的方式。我之前一般就比较无脑,直接seay师傅的代码审计工具一上,然后对其检测出来的问题点,挨个查看,再找相应的功能点进行验证。这种方式可能确实能发现很多问题,但是由于seay代码审计工具,是通过找危险函数来判断是否为漏洞点,所以存在误报率很高的问题。另一方面,通过代码,想去反过来找到对应的功能点位置,实际上是比较的。

同样的自动化代码审计工具有:

  • Seay源代码审计系统
  • Fortify SCA
  • RIPS

以Seay源代码审计系统为例:

由于Seay审计工具以及类似产品的原理是通过规则匹配,查找可能存在问题和漏洞的点,比较好的是可以很快的给我列出很多可能存在漏洞的点。

但是有两个问题比较难以解决:

  1. 如何通过这些代码的位置定位到功能点的位置。
  2. 规则匹配导致输出的漏洞点数量远远大于实际的风险漏洞的数量,需要消耗大量的精力复现和筛选,大部分时间都浪费在人工消除误报。

基于以上两个原因,我开始尝试从功能点+调试的方式来找漏洞

0x03 从功能点调试的方式找漏洞

所谓从功能点来找漏洞,顾名思义,就是通过搭建一个完整的环境(比如CMS等建站系统的环境),然后对常见的功能点进行测试,通过调试的方式来找到对应功能点的源码。在对源码进行审计,这样我们可以较为轻松的定位功能点和具体代码的对应关系,对整个代码的逻辑有更为清楚的认识

以新秀企业建站系统为例,讲一讲如何通过调试方式对特定功能点进行检查,确认其是否存在漏洞。

3.1 admin页面是否存在SQL注入

admin页面,通过MySQLMonitor监听SQL语句的执行情况,找到账号登录时的SQL语句。

通过对这个SQL语句的一部分进行全project搜索,找到相应的代码点。

注意:此时的代码可能不是最终的SQL语句执行的代码点,但是没有关系,我们可以在这里下断点,然后在浏览器里执行相应的操作,比如我们这里是输入账号密码,登录。

之后,因为下了断点,开启xdebug监听,我们可以step in,然后之后找到相应的SQL语句的位置,再对其源码进行审计。

此处,明显还是使用了SQL语句的拼接,这个可能是存在问题的,但是是否存在SQL注入漏洞,我们还需要进一步验证。

比如我们这样:

username = admin' and sleep(2)#
password = 123

结果发现好像'被转义了。

我们可以将断点往前面放一点:

发现这个小小的企业建站系统,竟然还做了不错的安全限制。

1.include/function.php:426 safe函数对攻击IP封禁一段时间。

2.include/function.php:74 strict函数将一些危险字符替换成对应的HTML实体,确实可以防护很多的SQL注入攻击。

然后我们就可以确认,admin的登录点不存在SQL注入。

其他的功能点也是一样,可以通过调试方式,非常轻松地定位到代码,然后审计一下代码的逻辑和危险函数的使用是否存在问题,基本上,所有功能点过一遍就差不多了。当然,全部过一遍之后,还可以再结合seay审计工具来查漏补缺一下。

我们再举一两个例子。

3.2 前台搜索功能点SQL注入漏洞

先输入一个关键词,利用MySQLMonitor定位SQL语句。

http://sinsiu:8888/?/search/index.html/key-TEST/

找到测试的关键词,找到相应的SQL语句。

对SQL语句的一部分进行全project的搜索,定位一下:

下断点,执行看看:

发现index/module/search_main.php:2:module_search_main()函数这里是SQL语句直接拼接了,而且不像之前经过过滤。

于是我们就有了这样的结果:

http://sinsiu:8888/?/search/index.html/key-%27UNION%20ALL%20SELECT%20NULL,NULL,database()--%20-

确定这里存在SQL注入之后,就可以通过sqlmap来进行利用。

python3 sqlmap.py -u "http://sinsiu:8888/?/search/index.html/key-%27*%20%23/" -v 3 -D susiu -T php_admin -C adm_id,adm_username,adm_password --dump

我们很轻松的找到(fu xian)了一个漏洞。

3.3 后台语言设置Getshell

看了上面的两个例子,那么问题来了,如果说一个功能点他不直接和数据库交互,我们如何通过功能点来定位代码呢?

我的方法是,搜索一些特定字符串,听上去很傻,但是往往挺有效果的。

比如我们怀疑后台编辑语言文件的位置存在任意文件写入的问题导致getshell。

那我们可以去搜索编辑语言包成功。在搜索一些关键词时,如果直接搜可能找不到,可以使用模糊查询或者正则表达式查询。

前后结合一下,能够找到写文件的位置。之后,设置断点,进行测试,而且比较清晰的看到代码的执行过程。

$path = post('path');
$lang_text = post('lang_text','no_filter');
file_put_contents($path,$lang_text);

$path过了strict过滤器,$lang_text文件内容过了no_filter过滤器。

no_filter过滤器就转义了一下,几乎相当于没有过滤,我们就可以任意文件写入。

//不过滤
function no_filter($str)
{
if(S_MAGIC_QUOTES_GPC)
{
$str = stripslashes($str);
}
return $str;
}

$path也是可控的,所以就可以很轻松的写入shell。

当然,该方法虽然一般情况下的表现不错。但是,相比于通过seay审计工具挨个去看危险函数,该方法对源码的整体性以及漏洞的挖掘程度并不够

0x04 整体阅读代码

这种方法比较硬核。。。

本人尚菜,很少尝试这样去审计一个系统。

当然,对于一个比较小的系统,或者类似于CTF中的代码审计,可能只是有一个场景,整体代码量较小的情况下,会是非常不错的方式。不仅可以较为深入的挖掘漏洞,还可以较为深入的挖掘漏洞的成因,利用方式。比如比较流行的php反序列化的POP利用链

0x05 总结

本文总结了php代码审计的常见三种方法。并以新秀企业建站系统为例,详细实战了功能点调试的方式找漏洞的方法:

  1. 代码本身找漏洞
  2. 通过功能点调试的方式找漏洞
  3. 整体阅读代码找漏洞

希望对读者在代码审计的入门有帮助。祝福各位师傅早日挖到属于自己的洞。

0xFF 参考链接

文章作者: V0WKeep3r
文章链接: http://v0w.top/2020/08/26/CodeAudit-php/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 V0W's Blog
支付宝打赏
微信打赏