How SAP consulters bypass your security restrictions. Part2: CALL TRANSACTION
I continue my posts regarding secret knowledge of SAP Consulters to bypass your security. And today I will tell you about calling SAP transactions without authorizations for them. It is known that to invoke transaction codes users need the S_TCODE authorization objects. There are some techniques in SAP to bypass these checks. For instance, you may call a transaction as a report via SA38 or SE38. But SAP Consulters can act differently. The most universal way for bypassing security checks is to create a custom program with dynamic CALL TRANSACTION statement. It can be a separate tiny program or you can insert the command into other custom ABAP programs or transactions developed for other purposes.
CALL TRANSACTION ta WITH|WITHOUT AUTHORITY-CHECK
The statement CALL TRANSACTION calls the transaction whose transaction code is contained in the data object ta
As you may see there is an option to call a transaction without authority check. You can use the statement with static value (CALL TRANSACTION ‘SU01’) and with a variable (CALL TRANSACTION l_tcode). Of course we will be interested in the second option. Such ABAP code can potentially grant everybody (who can execute the code) the rights to call every transaction (in case the l_tcode value comes from user input) in SAP system, similar to the S_TCODE authorization object with * assigned to user. Note that most transactions, when called, check not only the S_TCODE authorization object, but also other authorization objects. But sometimes the other authorization objects could be already assigned to user. And one more remark Segregation of duties conflicts will not be highlighted because the S_TCODE objects aren’t in SAP roles. But in fact SAP users can execute the critical transactions from the SOD matrix (using malicious code).
So why are backdoors appeared in our SAP systems? Because SAP Consulters always need more and more privileges. They certainly don’t want to stick to company’s rules and procedures. Following legitimate process takes a lot of time and doesn’t match their timeline. Besides new transactions may conflict to one of three security principles Need to Know, Least privileges and Segregation of Duties. Thus the requests can be rejected by the access control team.
Note: Even in the standard SAP code there is a program code to invoke any transaction without authorization checks. For example, in the BUBAS module (SAP ERP) there is a functional module with such function. You can find it yourself. Thus employees who have access to transaction SE37 can most likely start any transaction using the functional module. I recommend restricting access to transaction SE37 in production at all or not granting anybody authorization to run function modules (S_DEVELOP object type FUGR (function group) with activity 16).
So let’s move on to the second part of the article where I will share my ideas on how to find malicious inserts with the CALL TRANSACTION statement in ABAP code.
STATIC ABAP CODE ANALYSIS:
We can find the CALL TRANSACTION statement in custom ABAP code using one of the following reports: AFX_CODE_SCANNER, RS_ABAP_SOURCE_SCAN, RSABAPSC. And we will look for only dynamic usage without authorization checks. Dynamic value is specified without quotation marks. Further it will be necessary to analyze the results obtained and find ABAP code sections where the called transaction is set dynamically from user input. Be prepared for a large number of findings to analyze.
For instance, you can use following parameters in the AFX_CODE_SCANNER report to find dynamic CALL TRANSACTION statements:
DYNAMIC ABAP CODE ANALYSIS:
Look at call transaction events in SM20 (Transaction Start – AU3 – Transaction &A Started). In addition to an invoked transaction, these events contain information from what a report the call was made. My first idea is to collect statistic (over a long period of time) what a report used to start transactions. Unique cases will not be of interest to us. We are looking for custom reports (Z*) that were used to launch various transaction codes.
The second idea is to analyze the chain of events AU4 (Transaction Start – AU4 – Start of transaction &A failed (Reason=&B) where the Reason is 6 – User is not authorized for this transaction) and then AU3 with the same transaction code. Too suspicious when at first the user didn’t have privileges to start the transaction and then the user successfully started it. Do you agree with me? The answer to the question “How?” will be found between the AU4 and the AU3 events. If we ‘ll find here SE37, SA38, SE38, Z* calls, they need to be properly analyzed.
There is also a third option – compare authorization objects (S_TCODE) assigned to users to the list of successfully executed transactions from Security Audit Log. My approach is as follows: I download the USRBF2 table rows (only the S_TCODE objects assigned to users) and the UST12 table (only authorizations from previously downloaded the USRBF2 table), then using the Python script I analyze all Security Audit files (only AU3 events – Transaction successfully started) Has the user the S_TCODE authorization object to start specific transaction from the audit event or hasn’t? There are two difficulties with this technique: user’s authorization may change over time (for example new roles can be assigned or revoked) and the UST12 table may contain no specific transactions but also ranges of transactions or even masks.
So, usually the best results are achieved using a combination of approaches. Good luck!
Previous post: How SAP consulters bypass your security restrictions. Part1: Arbitrary code execution in production
Next post: How SAP consulters bypass your security restrictions. Part3: Hidden SAP_ALL
I'm just making an educated guess that your next post will be about the SUBMIT statement 😄
I know two function modules for the mentioned purpose are typically available within the SAP standard. both containing 'CALL' and 'TRANSACTION' in their name just in different orders.
Thank you for your comment. No, My next post is about SAP_ALL.
SUBMIT is waiting for its turn.