本文由红日安全成员: l1nk3r 编写,如有不当,还望斧正。
前言
大家好,我们是红日安全-代码审计小组。最近我们小组正在做一个PHP代码审计的项目,供大家学习交流,我们给这个项目起了一个名字叫 PHP-Audit-Labs 。现在大家所看到的系列文章,属于项目 第一阶段 的内容,本阶段的内容题目均来自 PHP SECURITY CALENDAR 2017 。对于每一道题目,我们均给出对应的分析,并结合实际CMS进行解说。在文章的最后,我们还会留一道CTF题目,供大家练习,希望大家喜欢。下面是 第13篇 代码审计文章:
Day 13 - Turkey Baster
代码如下:
这是一道典型的用户登录程序,从代码来看,考察的应该是通过 SQL注入 绕过登陆验证。代码 第33行 ,通过 POST 方式传入 user 和 passwd 两个参数,通过 isValid() 来判断登陆是否合法。我们跟进一下 isValid() 这个函数,该函数主要功能代码在 第12行-第22行 ,我们看到 13行 和 14行 调用 sanitizeInput() 针对 user 和 password 进行相关处理。
跟进一下 sanitizeInput() ,主要功能代码在 第24行-第29行 ,这里针对输入的数据调用 addslashes 函数进行处理,然后再针对处理后的内容进行长度的判断,如果长度大于20,就只截取前20个字符。 addslashes 函数定义如下:addslashes — 使用反斜线引用字符串string addslashes ( string $str )
作用:在单引号(')、双引号(")、反斜线(\)与 NUL( NULL 字符)字符之前加上反斜线。
我们来看个例子:
那这题已经过滤了单引号,正常情况下是没有注入了,那为什么还能导致注入了,原因实际上出在了 substr 函数,我们先看这个函数的定义:substr — 返回字符串的子串string substr ( string $string , int $start [, int $length ] )
作用:返回字符串 string 由 start 和 length 参数指定的子字符串。
我们来看个例子:
那么再回到这里,我们知道反斜杠可以取消特殊字符的用法,而注入想要通过单引号闭合,在这道题里势必会引入反斜杠。所以我们能否在反斜杠与单引号之间截断掉,只留一个反斜杠呢?答案是可以,我们看个以下这个例子。
在这个例子中,我们直接使用题目代码中的过滤代码,并且成功在反斜杠和单引号之间截断了,那我们把这个payload带入到题目代码中,拼接一下 第17行-第19行 代码中的sql语句。select count(p) from user u where user = '1234567890123456789\' AND password = '$pass'
这里的sql语句由于反斜杠的原因, user = '1234567890123456789\' 最后这个单引号便失去了它的作用。这里我们让 pass=or 1=1# ,那么最后的sql语句如下:select count(p) from user where user = '1234567890123456789\' AND password = 'or 1=1#'
这时候在此SQL