前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代码审计| 从今天起,做一个精致的多米咖!

代码审计| 从今天起,做一个精致的多米咖!

作者头像
漏斗社区
发布2018-03-28 11:54:42
1.3K1
发布2018-03-28 11:54:42
举报
文章被收录于专栏:漏斗社区漏斗社区漏斗社区

0x00 背景

在看CNVD漏洞库的时候发现有师傅发了某cms前台SQL注入漏洞,通过查阅漏洞描述可知道存在问题的参数是cardpwd,便开始尝试对该版本的cms进行审计。 源码下载地址:https://pan.baidu.com/s/1jIMhDK6 漏洞来源地址:http://www.cnvd.org.cn/flaw/show/CNVD-2017-22079

0x01 审计过程

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

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

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

● 到这里我们知道需要访问这个功能需要满足两个条件: (1)注册并登录

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

4.注册会员后访问站点的/member/mypay.php文件,http://127.0.0.1/dm132/member/mypay.php 简单输入1,2 进行请求,确定可以提交cardpwd参数。

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

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

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

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

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

9.联合查询无法使用的情况下就想到的子查询的方法,经过测试无法绕过628行过滤的正则~\([^)]*?select~s进行子查询,无括号的子查询貌似是不存在的吧~ ?! 此时此刻已经是对这个过滤规则研究了一整天,后面也请教了几位师傅,也没有好的方法进行无括号的子查询,其实官方文档上也说了子查询必须有括号。

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

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

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

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

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

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

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

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

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

根据这个现象可以推测两种可能: ❂SQL语句在被过滤前就执行了(×)

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

0x02 确定问题位置

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

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

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

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

开发人员为了避免类似密码处的关键字符被过滤,而设计的方法反而让过滤规则绕过成为了可能。 数据跟踪: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

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

利用两个双引号:

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

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

0x04 小小总结

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 漏斗社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
代码审计
代码审计(Code Audit,CA)提供通过自动化分析工具和人工审查的组合审计方式,对程序源代码逐条进行检查、分析,发现其中的错误信息、安全隐患和规范性缺陷问题,以及由这些问题引发的安全漏洞,提供代码修订措施和建议。支持脚本类语言源码以及有内存控制类源码。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档