Skip to main content
SAP Pentest Playbook
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage
Edit page

Critical RFC-Enabled Function Modules

Description

The RFC Gateway (33XX) exposes thousands of RFC-enabled function modules (FMs) and BAPIs to any caller holding a valid RFC logon. A handful of standard, SAP-shipped FMs are so broadly capable that authorization to call them is functionally equivalent to full system control - no vulnerability or exploit required, only a missing or over-broad S_RFC grant for the function group in question. This page catalogs the small set of FMs that repeatedly turn up as the payload of an RFC-based attack chain:

  • RFC_READ_TABLE - generic, parameter-driven read of any DB table via RFC, bypassing the transaction-level authority checks a SE16/SE16N browse would normally enforce. Returns rows as delimiter-packed strings (mangles binary RAW fields).
  • SXPG_STEP_XPG_START / SXPG_COMMAND_EXECUTE (function group SXPG) - runs an OS command defined in SM49/SM69 as the SAP work-process OS user. See OS command execution for the full primitive.
  • RFC_ABAP_INSTALL_AND_RUN (and its hardened-kernel rename /SAPDS/RFC_ABAP_INSTALL_RUN) - compiles and executes an ad-hoc ABAP report supplied entirely over RFC. Arbitrary ABAP is arbitrary code execution in the application-server context.
  • BAPI_USER_CREATE1 (+ BAPI_USER_PROFILES_ASSIGN, BAPI_TRANSACTION_COMMIT) - remote user provisioning; chaining these three creates a new user and grants it SAP_ALL in one RFC round trip.

These FMs are reachable over binary RFC to the Gateway/dispatcher (33XX, or 48XX when SNC is enforced) and, identically, over the SOAP-RFC HTTP bridge - see SOAP-RFC over HTTP.

Risk

Any credential with unrestricted S_RFC for these function groups converts a single authenticated RFC logon into: arbitrary table disclosure (RFC_READ_TABLE), OS command execution as the SAP work-process user (SXPG_*, which itself bridges to a SAP* super-user session - see virtual SAP*), arbitrary ABAP execution (RFC_ABAP_INSTALL_AND_RUN), and a persistent SAP_ALL account (BAPI_USER_CREATE1). Together they cover confidentiality, integrity, and availability of the whole system and, via RFC destination pivoting, the wider landscape.

Options

  • Table read - RFC_READ_TABLE(QUERY_TABLE=<table>, DELIMITER='|', ...); gated by S_TABU_DIS/S_TABU_NAM (and S_TABU_LIN for row-level restrictions) on top of S_RFC for the function group. Common target: RSECTAB, USR02 - see secure store decryption.
  • OS command execution - SXPG_STEP_XPG_START/SXPG_COMMAND_EXECUTE against a command pre-registered in SM49/SM69; gated by S_LOG_COM. Older kernels reject the MXROW parameter (RFC_INVALID_PARAMETER) - retry without it.
  • Arbitrary ABAP - RFC_ABAP_INSTALL_AND_RUN(PROGRAM=<source lines>); compiles then executes. S_DEVELOP is the gate on modern kernels. PROGRAM table rows are silently truncated past ~72 characters - long generated source must be chunked.
  • Privilege escalation via user creation - chain BAPI_USER_CREATE1 -> BAPI_USER_PROFILES_ASSIGN(BAPIPROFILE=[{BAPIPROF:"SAP_ALL"}]) -> BAPI_TRANSACTION_COMMIT(WAIT='X'). Tolerate an “already exists” return (message class 01/102) on create and still proceed to the profile assign - this still grants SAP_ALL to a pre-existing account. BAPI_USER_PROFILES_ASSIGN replaces the full profile list, dropping any pre-existing profiles. Gated by S_USER_GRP/S_USER_AUT/S_USER_PRO.
  • Tooling: SAPMAP modules/discovery/sapmap_rfc.py (binary RFC via pyrfc/NW RFC SDK), SAPMAP modules/protocols/sap_soap_basic.py (same FM set over HTTP - see SOAP-RFC over HTTP); manual equivalent: SE37 test-call with an authorized user, or an RFC destination configured with pyrfc/pysap.
Note
None of these FMs are defects - they are documented SAP interfaces. The entire attack surface is the S_RFC grant (which function groups a given RFC user may call) plus the FM’s own object-level authorizations. Auditing S_RFC scope per RFC user/service account is the single highest-leverage control here.

Mitigation

  • Restrict S_RFC per RFC user/service account to the minimal function-group set actually required; never grant S_RFC with ACTVT=16 and RFC_NAME=*.
  • Restrict SXPG_STEP_XPG_START/SXPG_COMMAND_EXECUTE via S_LOG_COM to trusted service accounts; keep the SM49/SM69 external-command allowlist minimal.
  • Restrict RFC_ABAP_INSTALL_AND_RUN//SAPDS/RFC_ABAP_INSTALL_RUN via S_DEVELOP to genuine developer/service accounts.
  • Restrict S_TABU_DIS/S_TABU_NAM so RFC_READ_TABLE cannot reach sensitive tables (RSECTAB, USR02, RFCDES, RFCTRUST, RFCSYSACL).
  • Restrict S_USER_GRP/S_USER_AUT/S_USER_PRO so BAPI_USER_CREATE1/BAPI_USER_PROFILES_ASSIGN cannot be used to self-grant SAP_ALL; monitor any assignment of SAP_ALL via these BAPIs.
  • Never assign S_RFCACL/S_RFC inside SAP_ALL; keep landscape-wide RFC trust (RFCTRUST/RFCSYSACL) scoped and reviewed - a compromised low-privilege credential otherwise maps the whole RFC-trust landscape via RSRFCCHK/RFCDES reads.

Detection and Monitoring

  • Security Audit Log (SM20/RSAU_READ_LOG): enable audit classes covering RFC/CPIC logon and dangerous function-module calls, not just dialog logon.
  • RFC_READ_TABLE reads of RSECTAB, USR02, RFCDES, RFCTRUST, RFCSYSACL - no legitimate business read use case.
  • SXPG_STEP_XPG_START/SXPG_COMMAND_EXECUTE calls from unexpected source IPs/users; correlate with SM49/SM69 external-command definitions.
  • RFC_ABAP_INSTALL_AND_RUN compiling/running short-lived, dynamically-installed report names from a non-developer source; correlate with ST22 short dumps.
  • BAPI_USER_PROFILES_ASSIGN calls that grant SAP_ALL - high-confidence indicator regardless of caller.
  • GET_TABLEBLOCK_COMPRESSED_RFC and raw RFCDES-table reads bypassing RFC_GET_FUNCTION_INTERFACE metadata lookups are rare in normal operations and a strong automated-tool signal in an RFC trace (STRFCTRACE/STAUTHTRACE).

References