查看原文
其他

原创 | 某cms比较有意思的sql注入

escape SecIN技术平台 2022-06-18

点击上方蓝字 关注我吧


前段时间工作需要刷几十个cnvd通用,草草看了几十套源码,发现其中有一套系统中出现了比较有意思的sql注入漏洞。

拿到这套cms,安装好之后随便找个控制器测测路由,在代码审计的时候如果能搭建好系统,那么通过黑盒到处点点功能看url的格式是能最快确定路由规则的方式。

大概了解路由之后开始看控制器,找个功能少的再确认一下路由,比如这个Down控制器。

它的token参数看起来似乎是没有注入的,因为在mvc框架下,除了框架本身缺陷,一般来说看到是数组传参那么其在内部做了sql注入的处理是一种共识。

但是我随手加了一个单引号,居然报了sql错误。

难道居然真的没过滤?我立刻跟到where函数,发现当参数是array时其调用了parseValue。

继续跟进,调用了escapeString,这个escapeString对传入参数是做了sql注入过滤的。

一时半会比较无解,只好通过下断点来判断问题到底出在哪里,php这种脚本型语言为了调试方便可以不用动态调试而是直接用echo、var_dump等函数来静态调试。

通过打点调试,最终发现是在经过如下红框标注的代码后,发生了反斜杆被吃掉导致单引号逃逸的情况。

可以看到前后的打印结果发生了变化,经过preg_replace后被吃掉了一个反斜杆。

这里说一下为什么经过一次escapeString之后的参数值不是1\'而是1\\\',是因为这套cms在系统入口就有一个全局的对GET POST REQUEST数组的过滤,等于说是转义了两次。

那为什么这里有一个转义符会被吃掉呢?我突然想到在p师傅曾经发过的一篇文章:经典写配置漏洞与几种变形(https://www.leavesongs.com/PENETRATION/thinking-about-config-file-arbitrary-write.html)。

里面提到过这种情况,那么证明这里确实是因为preg_replace函数导致了单引号的逃逸。

但这里其实并不是存在转义符就会被吃掉,而是两个转义符才会被合并为一个。

注释掉全局的过滤函数只剩where中的过滤函数后再传参就会发现参数被正常转义,并没有报sql错误。


而假如传入多个反斜杆,就会看到确实是每存在两个转义符就会被吃掉一个,这里原本7个反斜杆经过preg_replace后变为4个。

因此如果不是这套系统恰好存在一个全局的过滤函数(一般cms都不会这么写)导致两个反斜杆变为一个反斜杆使得单引号逃逸出来并在我随手测试时报出sql错误,这个洞应该很难被挖到。

接下来只要全局搜索where(array(,只要参数是用户输入那么都存在sql注入。

这套系统没办法回显,也不能像tp一样修改app_debug改成调试模式,所以只能盲注,用个脚本跑一跑数据库名字,如下:


然后再改改url,几个cnvd通用就水到了。


后面又看了一下,除了这个漏洞之外,熟悉thinkphp的人应该都知道tp3本身框架上存在不少缺陷,对parseItem这个方法一定有印象,这个缺陷使得所有Thinkphp3开发的系统一不小心就可能被一发数组打穿,这套系统虽然没有使用thinkphp框架,但是基本可以说是有参考,它在前面的where方法中也调用了parseItem方法。

比如这里当传入的数组key(value[0])为not exists时,value[1]就忘记了过滤而被直接拼接到了sql语句中,然而这个点不能用,因为这里开发者居然把not exists的语句的语法写错了。

下面的not like同样也直接拼接了value,不过这套系统后续的补丁是通过正则表达式限制了参数的取值,估计开发者也没弄明白到底哪里产生了注入,有兴趣的师傅可以试试构造一下利用。

相关推荐




原创 | java安全-java类加载器
原创 | java安全-java反射
原创 | java安全-java RMI你要的分享、在看与点赞都在这儿~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存