关于齐博cms代码审计的思考

之前看到了齐博cms报错注入漏洞,就想是否可以使用同样的路径发现sql注入,在思考尝试中有了这篇文章,最终发现了sql注入,但版本仅限于4.1<mysql≤5,也就是说2008年mysql出现5.1后,这个洞就用不了了,比较鸡肋,但思考的过程值得记一下。

路径

之前的齐博cms报错注入使用了以下两个函数:


query函数中有这么一行:

可以让$query=False,然后执行报错语句,$showerr代码自己定义=1,那就不需要我们管了。

我首先查看了还有文件的调用路径包含这两个函数,结果在:/do/search.php 这里找到,为了调用其中的内容,我们可以写为:type=keyword&keyword=sql语句

开始调试

这是一个搜索页面,之前学习PHP代码审计的时候,师傅给的例子就是ESPCMS的搜索框sql注入,所以觉得存在sql注入的可能性挺大的。

现在开始构造注入语句:

1
http://127.0.0.1/qibocms-v7/do/search.php?type=keyword&keyword=%27%20and%20(updatexml(1,concat(0x7e,(substring((select%20username%20from%20qb_memberdata%20where%20groupid=3),1,32))),1))%20--%20

发现我们传入的闭合单引号被注释了,发现是针对符号%的过滤:

1
$keyword=str_replace("%","\%",$keyword);

发现我们注释符号-- 后面的空格被吞掉了,那就在%20后面随意加个,改成:--%20p

上面调试过程中发现有这么一行:

那么我们就可以使用宽字节%df进行绕过(这里是个大坑,但此时还没意识到),进入到query函数发现我们成功让sql语句闭合:

1
SELECT B.aid FROM qb_keywordid B LEFT JOIN qb_keyword A ON A.id=B.id WHERE A.keywords='運' and (updatexml(1,concat(0x7e,(substring((select username from qb_memberdata where groupid=3),1,32))),1)) -- p'

把语句放到phpmyadmin中看看是否能返回我们想要的结果,这里构造的sql语句是使用updatexml报出后台管理员用户名,发现我们的sql语句是没有问题的。

那我们不是离胜利非常接近了?(并不,接着往下看)

定位:

奇怪的地方来了,这个resource id是什么?$query不应该返回False才对嘛?

查了一下mysql_query()得到以下两个结果:看来我们的情况是有红线的这边。

来源:https://www.php.net/manual/en/function.mysql-query.php

来源:https://blog.csdn.net/weixin_30896511/article/details/95709013

因为我们的$method是空,所以只能运行mysql_query(),看来报错注入的方法行不通了,接着往下看看:

发现有mysql_fetch_array()那我们正常注入是不是可以呢?立马试一下:

1
http://127.0.0.1/qibocms-v7/do/search.php?type=keyword&keyword=%df%27%20union%20select%20username%20from%20qb_memberdata%20where%20groupid=3%20--%20p

这是怎么回事,怎么$array是空呢?

检查发现我们构造的sql语句没问题

然后自己用mysql_connect() mysql_select_db() mysql_query() mysql_fetch_array()这些函数,尽量贴近齐博cms的原本代码,连一下齐博cms的数据库,看看是否可以正常返回:

发现没有问题。那么就排除了mysql_fetch_array()的问题,只把产生问题的地方定位在query()函数这里:

排查:

接下来我们把自己写的,没有问题的那些代码放到query()里面执行,结果发现居然也没有Array,然后我们开始改造sql语句,看看正常sql语句能否执行:

1
2
3
4
原本的:$sqll = "SELECT B.aid FROM qb_keywordid B LEFT JOIN qb_keyword A ON A.id=B.id WHERE A.keywords='運' union select username from qb_memberdata where groupid=3 -- p'";
改造一:$sqll = "select username from qb_memberdata where groupid=3";
改造二:$sqll = "select 1 and 1=2 union select username from qb_memberdata where groupid=3";
改造三:$sqll = "SELECT B.aid FROM qb_keywordid B LEFT JOIN qb_keyword A ON A.id=B.id WHERE A.keywords='' union select username from qb_memberdata where groupid=3 -- p'"

结果出来了,除了原本的其他改造sql语句全部能执行,这就说明是我们的宽字节闭合出问题了,再确认一下:

1
$sqll = "SELECT B.aid FROM qb_keywordid B LEFT JOIN qb_keyword A ON A.id=B.id WHERE A.keywords='好' union select username from qb_memberdata where groupid=3 -- p'";

发现执行正常,为什么我们看到dbcharset=gbk,使用宽字节闭合时会出错呢?在query()中有连接数据库的函数connect(),跟进看一下发生了什么(之前调试都会跳过它,以为只是进行数据库连接,并没有其他用处),结果发现了下面的代码。

赶紧看一下我们的数据库版本,发现是5.5,所以说,宽字节闭合sql语句发生了错误,再看看mysql5.1版本是什么时候发行的,发现是2008年,哎。

大疑问

那为什么我们模拟齐博cms源代码,也没有设定连接时必须是gbk,为什么执行时没有出错呢?

现在把重点放到这个代码上:

1
mysql_query("SET sql_mode=''")

这里是空的,也就是并没有定义MySQL应该支持的sql语法,对数据的校验等等,具体什么设置,可以参考;https://segmentfault.com/a/1190000005936172

小解答:

那么这是怎么回事呢?有一种可能就是我们模拟时默认编码是utf8,mysql字符集也是utf8,所以没有问题,如果不设置mysql接收gbk,那么连接时齐博cms发送的是gbk,但是mysql只接收utf8,所以出错了。

通过这句话,我们就可以设置mysql接收gbk了

1
mysql_query("SET NAMES '$dbcharset'");

怎么把这句话放到我们的sql语句中呢?如果可以执行多行sql语句,那不就是堆叠注入了嘛?但是没有mysqli_multi_query(),所以无法实现。

最后

这些是目前的一些想法,还有很多的不足,师傅们请多指教。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!