freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

代码审计| DuomiCms全局过滤规则绕过
2017-12-04 15:25:37

0x00 背景

在看CNVD漏洞库的时候发现有师傅发了某cms前台SQL注入漏洞,通过查阅漏洞描述可知道存在问题的参数是cardpwd,便开始尝试对该版本的cms进行审计。 

源码下载地址:https://pan.baidu.com/s/1jIMhDK6 

漏洞来源地址:http://www.cnvd.org.cn/flaw/show/CNVD-2017-22079

背景.png

 

0x01 审计过程

1.下载好源码后在本地部署,然后使用seay 源代码审计系统加载源码文件,查找关键字cardpwd得到如下信息,cardpwd参数是在member/mypay.php文件中以POST的方式接收使用的。

审计 1.png


2.进入到member/mypay.php文件(26行和38行)在接收cardpwd参数的值之前还需要进行登录,并且满足$dm=='mypay'

 审计 2.png


3.继续跟进$dm并未发现变量被创建的位置,最后在/duomiphp/common.php(52行-55行)中发现接收了GET,POST以及COOKIE中的参数和值,并且创建相应的变量赋予接收到的值,此处可能还存在变量覆盖的问题,本文咱不讨论。

审计3.png

 

•到这里我们知道需要访问这个功能需要满足两个条件: 

(1)注册并登录

(2)在GET,POST或COOKIE中提交dm=mypay


4.注册会员后访问站点的/member/mypay.php文件,http://127.0.0.1/dm132/member/mypay.php 

简单输入1,2 进行请求,确定可以提交cardpwd参数。

审计4.png

 

5. 继续阅读/member/mypay.php在43-63行之间是对cardkey,cardpwd的处理,并使用了正则[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,} 对数据进行检测,分析并对这个正则进行测试,发现使用/*!50000 xxxx*/便可以绕过。

审计5  1.png

审计5  2.png

 

6. 本以为过滤规则是如此简单,经过测试发现还有其他过滤规则,继续往下分析发现/member/mypay.php在63行要执行SQL语句的时候还使用了GetOne的函数,定位到这个函数所在的位置/doumiphp/sql.class.php的277-300行,GetOne大致做了以下的事情,先清理掉字符串最后面的,和;然后拼接上limit 0,1;使查询的结果只返回一行。 

正如代码上面所注释的“//执行一个SQL语句,返回前一条记录或仅返回一条记录”

审计6.png

 

7. 拼接后在/doumiphp/sql.class.php在288行执行了SetQuery方法,290行执行了Execute方法,跟进Execute方法,在234行-269行发现了Execute方法的代码块,其中CheckSql是一个关键名称的方法,并且在上方有注释说用于SQL安全检查。

审计7.png

 

8. 跟进CheckSql在/doumiphp/sql.class.php的537行-642行发现CheckSql方法的代码块,上面有提示 //SQL语句过滤程序,由80sec提供,这里作了适当的修改,经过测试这个过滤规则在598行过滤了/*而且是用硬匹配的方法,所以无法绕过,因此第5步的 /*!50000 xxxx*/的payload无法使用。

审计8.png

 

9. 联合查询无法使用的情况下就想到的子查询的方法,经过测试无法绕过628行过滤的正则~\([^)]*?select~s进行子查询,无括号的子查询貌似是不存在的吧~ ?! 

此时此刻已经是对这个过滤规则研究了一整天,后面也请教了几位师傅,也没有好的方法进行无括号的子查询,其实官方文档上也说了子查询必须有括号。

审计 9.png


10. 当没有思路或测试进行不下去的时候,就一定要回头看看一路走来所获得的信息,往往有小惊喜遗留在路上 By Thinking!继续看CNVD中的描述,系统未对变量进行过滤 我突然觉得我下载的是假的源码!!

审计10  1.png

 

 这个CMS在/member/mypay.php页面提交任意充值卡号,在卡号密码处使用’or’ 1可以实现任意充值,使用报错注入可以获取user() 或version()的数据,但是无法进行子查询。

• 先在后台添加了充值卡。

审计10  2.png

 

• 在前台注册并登录后,将cardpwd的值设置为’or’ 1提交,便可以任意充值了,虽然这算一个漏洞,但是在我的观念中这种漏洞不太能说服我。

审计10  3.png

 

11. 使用灰盒方式先测试下/member/mypay.php的cardpwd参数

被/member/mypay.php在43-63行之间的正则过滤了。

审计 11 1.png

 

被/doumiphp/sql.class.php的537行-642行的CheckSql方法过滤了。

审计 12 2.png

 

未进行'的闭合导致SQL语句报错了。

审计11 3.png

 

12. 到这里发现了一个小细节,多了一个'的导致SQL语句报错了?!,在报错信息中发现了插入的cardpwd的值,而不是先提示被过滤了,所以此处肯定有问题,经过测试是第2种情况。 

根据这个现象可以推测两种可能: 

o SQL语句在被过滤前就执行了(×)

o 多了'导致注入语句被绕过(√)


0x02 确定问题位置

1. 确定位我使用的方法是在关键位置使用echo 将传入的cardpwd数据在处理过程中打印出来,首先是在使用/*! 50000union */的情况下提示:Safe Alert: Request Error step 2! 找到这个关键字所在的位置,/doumiphp/sql.class.php的635行,刚好在CheckSql方法内。

问题 1 1.png

 问题 1  2.png

 

2. 在561-586行有个 //完整的SQL检查 之前一直都在关注过滤规则,并没有在意这个代码块,因为这个CMS都是明文传输,密码处可能会有一些关键字符会触发SQL检测的规则,为了避免这种情况,开发人员便写了这个代码块,用于将SQL语句中两个单引号包裹的数据进行替换处理。

问题 2.png

 

3. 直接在589行处插入echo $clean;将经过这个代码块的数据打印出来,发现确实将单引号内的字符变成了$s$

问题 3 1.png

 问题 3  2.png


4. 在640行处插入echo $db_string;将通过检测的数据打印出来。

问题 4  1.png

问题 4  2.png


开发人员为了避免类似密码处的关键字符被过滤,而设计的方法反而让过滤规则绕过成为了可能。 

数据跟踪:cardpwd->$pwd->GetOne()->Execute()->CheckSql()->$clean->$db_string 

$clean->$db_string 的过程是先经过把数据进行处理(//完整的SQL检查)再赋给$clean,然后把$clean传到各种SQL注入检测规则中,全部通过后返回原始数$db_string,幸运的是在各种过滤规则中没有过滤 `,’,” 号。 

因此仅需要利用//完整的SQL检查中的被单引号包裹的字符会被替换为$s$这个功能。


0x03 构造PAYLOAD

要利用单引号将字符包裹且不影响SQL语义,单引号就必需要被转义! 

转义单引号的方法:

• SQL注释法: 

1. /*'*/

2. /*!60000'*/

• 反引号方法: 

1. ` ’ `

• 双引号方法: 

1. " ' "

因此可以构造如下PAYLOAD:

利用双引号和反引号: 

bypass’or”‘“or extractvalue(1,(select group_concat(0x3a,name,0x3a,password) from duomi_admin`’`))or ‘1

构造 01.png

 

方便阅读将处理后的结果打印出来:

构造02.png

 

利用两个双引号: 

bypass’or”‘“or extractvalue(1,(select group_concat(0x3a,name,0x3a,password) from duomi_admin))or “’”=

构造03.png


方便阅读将处理后的结果打印出来:

构造 04.png


0x04 小小总结

其实这个漏洞整个思路还是很清晰对的审计起来也不困难,但是因为一开始将重点放在了过滤规则的绕过上面,导致花费太多精力在分析正则上,所以当过滤规则有些时候强绕绕不过,或许可以看下代码的其他上下文相关信息,这次的较为灵活的利用//完整的SQL检查绕过了全局的SQL安全检测,本篇绕过了全局的检测,凡是使用到了CheckSql()方法的位置都存在这个问题,最后感谢师傅们的各种协助和讨论。

640.webp.jpg

本文作者:, 转载请注明来自FreeBuf.COM

# 代码审计 # 规则绕过
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
评论 按时间排序

登录/注册后在FreeBuf发布内容哦

相关推荐
  • 0 文章数
  • 0 评论数
  • 0 关注者
登录 / 注册后在FreeBuf发布内容哦
收入专辑