【代码审计】--- php代码审计方法

代码审计需要掌握的点PHP编程语言的特性和基础Web前端编程基础漏洞形成原理代码审计思路不同系统、中间件之间的特性差异代码审计思路方法一 ---- 检查敏感函数的参数,然后回溯变量,判断变量是否可控,并且有没有经过严格的过滤,这是一个逆向追踪的过程方法二 ---- 找出哪些文件在接收外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危函数里面,或者传递的过程是否有逻辑漏洞,这是一种正向追踪的方式方法三 ---- 直接挖掘功能点漏洞,根据自身经验判断该类应用通常在哪些功能中
摘要由CSDN通过智能技术生成

代码审计需要掌握的点

  • PHP编程语言的特性和基础
  • Web前端编程基础
  • 漏洞形成原理
  • 代码审计思路
  • 不同系统、中间件之间的特性差异

代码审计思路

  • 方法一 ---- 检查敏感函数的参数,然后回溯变量,判断变量是否可控,并且有没有经过严格的过滤,这是一个逆向追踪的过程
  • 方法二 ---- 找出哪些文件在接收外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危函数里面,或者传递的过程是否有逻辑漏洞,这是一种正向追踪的方式
  • 方法三 ---- 直接挖掘功能点漏洞,根据自身经验判断该类应用通常在哪些功能中会出现漏洞,直接全篇阅读该功能代码
  • 方法四 ---- 通读全文代码

(1) 方法一

  • 检查敏感函数的参数,然后回溯变量,判断变量是否可控,并且有没有经过严格的过滤,这是一个逆向追踪的过程
  • 说明:由于大多数漏洞都是由于函数的使用不当造成的。而非函数使用不当的漏洞,比如sql注入,也有一些关键字特征:如 select、insert等。再结合fromwhere等关键字,即可以判断其是否是一条sql语句。再有比如说:http头中的HTTP_CLIENT_IPHTTP_X_FORWARDED_FOR字段,有时在没有过滤的情况下就拼接到了sql语句中,并且由于他们是在$_SERVER变量中的,不受GPC的控制。so,我们可以专门去查找http_client_ip 或者 http_x_forwarded_for字段,快速的判断是否有漏洞存在。
  • 优点:只需要搜索关键字,可以快速地挖掘出想要的漏洞,可以定向挖掘漏洞。
  • 缺点:没有通读代码对程序的整体框架不了解,无法挖掘出逻辑漏洞。在挖掘漏洞时定位漏洞利用点会花费一些时间。

下面介绍一个使用方法一挖掘出来的sql注入漏洞(参考了seay大佬的《代码审计》一书)
espcms注入挖掘案例,使用的版本是:ESPCMS V6.6.15.12.09。通过Seay源代码审计系统导入cms的源代码
在这里插入图片描述
进行自动审计
在这里插入图片描述
选择第26条内容进行审计($parentid变量可能存在sql注入漏洞,且通过列表中的漏洞详细信息来看这是一个数字型注入点),双击这一行可以直接定位到代码所在地。选中$parentid变量后在下方可以看到变量的传递信息
在这里插入图片描述
可以看到$parentid通过:$parentid = $this->fun->accept('parentid', 'R'); 这条代码获得。定位accept函数的位置
在这里插入图片描述
跳转到了class_function.php函数中
在这里插入图片描述
其中的代码如下所示
在这里插入图片描述
accept函数的功能是获取通过GETPOST或者COOKIE方法,传递的变量的值。然后通过daddslashes函数(实际上是包装的addslashes函数,功能差不多)对传进来的单引号等值进行转义(我们前面说过这是一个数字型注入点,并不需要闭合单引号,因此这个过滤是没有用的)。再通过htmldecode函数解编码返回传入的数据。这里很明显存在数字型sql注入点。变量的整个传递过程大概是这样的
在这里插入图片描述
确定了存在漏洞之后就要确定漏洞的利用点了。在citylist.php文件中可以看到该语句$parentid = $this->fun->accept('parentid', 'R');位于oncitylist函数中,该函数又位于important类中。
在这里插入图片描述
选中important类,右键点击全局搜索
在这里插入图片描述
可以看到/adminsoft/index.php文件中有实例化该类
在这里插入图片描述
打开查看文件的内容
在这里插入图片描述
主要的代码如下所示

$archive = indexget('archive', 'R'); //indexget函数 用来获取通过GET、POST和COOKIE传递的名为archive的参数
$archive = empty($archive) ? 'adminuser' : $archive;
$action = indexget('action', 'R'); //indexget函数 用来获取通过GET、POST和COOKIE传递的名为action的参数
$action = empty($action) ? 'login' : $action;

include admin_ROOT . adminfile . "/control/$archive.php"; // 由于在获取 $archive变量 时经过了indexdaddslashes的过滤因此无法产生文件包含漏洞。因此我们让其包含citylist.php文件
$control = new important(); // 实例化 important类
$action = 'on' . $action; // 给$action 拼接一个 on ,刚好对应了citylist.php中的important类中的oncitylist函数
if (method_exists($control, $action)) {
    // 检查实例化后的 $control中是否存在oncitylist函数,肯定是存在的
	$control->$action(); 
} else {
   
	exit('错误:系统方法错误!');
}

关键点:

  • 需要通过GET或者POST方式传进来三个参数:archive(用于包含citylist.php文件)action(用于检测实例化后的对象是否存在oncitylist函数)parentid(写注入语句),让archiveaction等于citylist。
  • 构造EXPhttp://localhost/espcms/adminsoft/index.php?archive=citylist&action=citylist&parentid=-1 and 1=1 这样去注入即可

(2) 方法二

  • 找出哪些文件在接收外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危函数里面,或者传递的过程是否有逻辑漏洞,这是一种正向追踪的方式

(3) 方法三

  • 直接挖掘功能点漏洞,根据自身经验判断该类应用通常在哪些功能中会出现漏洞,直接全篇阅读该功能代码
  • 审计方法 ---- 安装好并运行程序,看程序有哪些功能,寻找到实现这些功能的程序文件分别是怎样的。是独立的模块,还是插件,还是写在了一个通用类中。了解了这些功能的存在形式之后,可先找到经常会出现问题的功能点,黑盒测试一下,如果没有发现常见的漏洞,就去读该功能的代码,进行审计。
  • 相关功能点经常会出现的漏洞
    • 文件上传功能:文件上传在很多功能点都会有,如:文件编辑、资料编辑、头像上传、附件上传等。该功能点最常见的漏洞就是任意文件上传漏洞。除了任意文件上传之外还经常发生sql注入漏洞,因为程序员一般都不会注意到对文件名进行过滤,但是文件名有时又会保存到数据库中,所以可以通过文件名实现sql注入攻击。
    • 文件管理功能:在文件管理功能中,如果程序将文件名或者文件路径直接在参数中传递,那就有可能存在任意文件操作漏洞,如任意文件读取,利用../或者..\来跳转路径。还可能存在xss漏洞,程序会在页面中输出文件名,此时如果没有对存入数据库的文件名进行过滤的话就有可能存在xss漏洞。
    • 登录认证功能:程序将当前登录的用户账号的认证信息放到cookie中,当操作需要认证信息时直接从cookie中读取用户信息。如果这段cookie没有加salt一类的东西,就可以导致任意用户登录漏洞,只要知道用户的部分信息,即可生成认证令牌。有的程序甚至会直接把用户名明文放到Cookie中,从而导致越权漏洞
    • 找回密码功能:找回密码功能的漏洞有很多利用场景,常见的是验证码爆破。还有验证凭证的算法,这只有在代码中才能看到,在代码审计时可以看这个算法是否可信。

(4) 方法四

  • 直接通读全文代码
  • 方法:通读全文代码也有一定的技巧,而非抓住一个文件逐句读完就行了。首先我们要看程序的大体代码结构,如:主目录的文件模块目录的文件插件目录的文件。除了看有哪些目录还要看文件的大小创建时间。根据文件名就可以推断出文件实现了哪些功能。
  • 在看程序目录时需要特别注意的几个文件
    • 函数集文件,命名中包含 functions 或者 common等关键字。其中写的是一些公用函数,是给其他文件统一调用的,大部分的文件中都会在开头包含这些文件。寻找这些文件的方法:打开index.php或者一些功能文件,在其头部会包含这些文件。
    • 配置文件,命名中通常包含 config 关键字。从其中可以了解到程序的小部分功能。在看配置文件时要看清楚其中参数的值是使用单引号还是双引号括起来的,如是双引号则可能存在代码执行漏洞
    • 安全过滤文件,命名中有filtersafecheck等关键字。文件的作用是对参数进行过滤。常见的是对:sql注入XSS文件路径执行的系统命令参数的过滤。很多的程序会在参数传入时使用addslashes()进行一次过滤。
    • index文件,他是程序的入口文件,读一遍index文件即可大致了解:程序的架构运行的流程包含的文件核心文件等信息。不同目录的index文件有不同的实现方式,应当将几个核心目录下的index文件都读一遍。

案例:骑士CMS代码审计,版本:3.5.1
第一步:查看应用文件结构
文件目录结构如下所示
在这里插入图片描述
首先要看有那些文件和文件夹,寻找名称中带:api,admin,manage,include关键字的文件,这里有admininclude文件夹
在这里插入图片描述
查看admin文件夹中的内容,其中有一个api文件夹
在这里插入图片描述
再查看include文件夹中的内容,include文件夹很重要,其中一般会保存比较核心的文件,供其他文件包含。在这里插入图片描述
第二步:查看关键文件代码
查看include文件夹下的文件
在这里插入图片描述
其中有很多php文件,可以看到有一个名为common.fun.php的文件。前面说过common关键字多用来命名函数集文件,该文件就是一个定义了许多基础函数的文件。


打开文件第一个函数是addslashes_deep()

function addslashes_deep($value)
{
   
    if (empty($value))
    {
   
        return $value;
    }
    else
    {
   
		if (!get_magic_quotes_gpc()) // 获取magic_quotes_gpc的值
		{
   
		$value=is_array($value) ? array_map('addslashes_deep', $value) : mystrip_tags(addslashes($value));
		}
		else
		{
   
		$value=is_array($value) ? array_map('addslashes_deep', $value) : mystrip_tags($value);
		}
		return $value;
    }
}

相关函数:

  • get_magic_quotes_gpc() ---- 获取当前magic_qoutes_gpc的配置选项设置。本函数自 PHP 7.4.0 起废弃。强烈建议不要使用本函数。返回0表示magic_quotes_gpc关闭,返回1代表开启。
  • array_map() ---- 为数组的每个元素应用回调函数

该函数首先会判断magic_qoutes_gpc是否开启,没有开启的话会使用addslashes注意:在挖掘sql注入漏洞时除非有宽字节注入或者二次注入等特殊情况,只要参数在拼接到sql语句之前调用了addslashes进行了过滤,就不能进行注入了】进行一次过滤。如果传进的值是数组的话会将数组中的每一个元素作用于addslashes_deep函数,实际会调用mystrip_tags函数。


mystrip_tags函数的内容如下。

function mystrip_tags($string)
{
   
	$string = new_html_special_chars($string);
	$string = remove_xss($string);
	return $string;
}

将传入的值分别作用于new_html_special_chars函数remove_xss函数,这两个函数都是用来过滤XSS的。


首先看看new_html_special_chars函数中的内容

function new_html_special_chars($string) {
   
	$string = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), array('&', '"', '<', '>'), $string);
	$string = strip_tags($string);
	return $string;

相关函数:

  • strip_tags() ---- 从字符串中去除 HTML 和 PHP 标记

该函数的作用是对输入字符串中的& " > <进行html实体编码,然后还使用了strip_tags函数进行了二次过滤。


remove_xss函数中的内容如下

function remove_xss($string) {
    
    $string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $string);

    $parm1 = Array('javascript', 'union','vbscript', 'expression', 'applet', 'xml', 'blink', 
  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值