Greetings to everybody!
In this post, we'll examine a way to doctor transport requests, which can be used with malicious intent, but potentially also as a "quick fix" by admins. The goal is to identify the involved tools and related authorizations to secure your SAP systems against such manipulations... as far as possible!
Let's start with the offender itself:
Report RDDIT076 allows you to select an existing transport request (or transport task) and edit many of its attributes.
As an example, we assume an unreleased workbench request (type "K"). That request contains a single task, which in turn consists of a repair... e.g. a changed report.
To make it interesting, we assume that the modified report copies the profile SAP_ALL to our user's authorization buffer once we start it (that gives us all authorizations without any traces). As the assumed code checks for SY-UNAME, it only works for one user (in the example that's me: DBERLIN). There's only a very shallow code-check during transport... so the chance of being caught is slim! 🥳
But wait... 😳 we absolutely don't want to be caught. Really not! So just in case our malicious code change is detected, let's blame someone else!
Let's see what RDDIT076 can do for us:
Okay – the title of the transport request is a bit too honest and we could easily have chosen a better one. The problem is: my user DBERLIN is the owner of both the request and the task and will be blamed for its contents. Fortunately, we can simply edit both entries:
We adjust the description and set a new owner: our estimated colleague Frank Grimes (FGRIMES).
Save and repeat for the task!
In our example we assumed a malicious, internal developer... but that's not the only situation, in which the report might be (mis-)used. We have to differentiate between three scenarios:
- justified usage (e.g. by a developer, who needs to cope with a particular situation)
- sloppy usage (e.g. an admin, who favors "shortcuts" instead of the longer standard process)
- malicious usage (e.g. to hide the origin of manipulative code in a transport request)
The first case is generally acceptable, but it must be ensured that the possibility to use RDDIT076 is not misused. That will turn out to be challenging and I doubt that such cases exist.
The second "sloppy" case is not easy to prove for an auditor, because there's always a "good" reason, why a change had to be fast and the usual process would've been too slow... so people might try to sell the second case for the first one.
Lastly, the third case is what our example is based on – an intentional attempt to maliciously exploit the SAP system. That's the most obvious case, but when cleaning up your system, always keep in mind that the other two cases exist as well (and are probably more likely 🤔).
How to prevent it
RDDIT076 is a report without an assigned authorization group and there is no associated transaction code – so to block access, you should take care of program execution rights, for example:
- SA38: only S_PROGRAM is checked with P_ACTION = SUBMIT
- SE38: first, S_DEVELOP with ACTVT = 03 and 16, OBJNAME = RDDIT076 and OBJTYPE = PROG is checked, then additionally S_PROGRAM (see above)
- START_REPORT: only S_TCODE with START_REPORT is checked... nothing else 🙄
Program execution rights should generally only be granted to few, carefully chosen users – especially because there is no way to do it in a granular way (i.e. without a program authorization group).
There are some, but not many authorizations necessary to run RDDIT076:
- S_TRANSPRT with ACTVT = 03 to select the transport request and read its contents
- S_CTS_ADMI with CTS_ADMFCT = TABL as a "general" protection
- and S_DATASET with ACTVT = 34 (write), PROGRAM = SAPLSTRF and FILENAME = <DIR_TRANS>/actlog/<LOGFILE>
The first two authorizations are administrative rights that can be used to limit the usage of the report and which should only be granted to few users! The third authorization is checked, when a log file is written – so in case this right is not granted, no log would be written... which is counterproductive!
The hard truth
In the end, you'll probably end up with a few users that have the necessary rights to use the report and can thus manipulate transport requests. The reason is that only a few generic authorizations are checked in RDDIT076 and all those rights are needed in other places as well... at least by SAP basis (on DEV and maybe also PROD) and developers (on DEV).
From an audit perspective, a residual risk remains after the first cleanup. You could further reduce it by additional measures... for example, you could assign the report to an authorization group (so that the S_PROGRAM check is more specific) and make sure that other ways to execute it, e.g. START_REPORT, are removed from all roles. That's feasible, but difficult for a rather small gain in security... and most people will probably not want to change the attributes of an SAP standard report.
Another option would be an ex-post control – but then we'd need a good log of the actions performed in RDDIT076. In the next chapter "How to detect it" we'll see that logging exists, but is far from being detailed enough. Other ways to trace such administrative activities, such as SAP UI Logging, are usually complex and expensive.
So, the hard truth is that RDDIT076 is a candidate for risk acceptance...
How to detect it
As stated above, changes performed in RDDIT076 lead to log files being written to <DIR_TRANS>/actlog/<LOGFILE>, if the S_DATASET authorizations allow it. One log file is used per transport request/task number.
Such a file, unfortunately, contains only minimal information... the example from the beginning of this article leads to two log files. One for the transport request and one for the contained task. Both files contain one line similar to the following:
1 ETR018 "05.04.2020 16:15:30" request/task "NSPK900042" was changed by user "DBERLIN"
No information about what was changed...
That's not enough data for a sensible ex-post control!
The bottom line
I'd suggest removing the involved authorizations from all users that don't need it – the remaining users should be administrative ones only.
Admins should have separate users (and rights) for "employee tasks", e.g. time management, day-to-day administration and extended admin-tasks. At least the latter user should be logged extensively. Logs should be monitored for the usage of RDDIT076 and - in case of matches - the logfiles should be inspected.
That's not bulletproof, but the best approach possible without disproportionate effort... at least IMHO...
Bye and see you soon!
This article is intended for all the auditees out there, who struggle with SAP authorizations. I'll try to provide you with a best-practice approach to tackle audit findings related to extensive/critical rights in SAP.
There is probably not a single SAP-related audit report out there that does not include a finding about extensive SAP authorizations...
Let's be honest: SAP offers fantastic possibilities and tools to tailor user authorizations and restrict them to a proper minimum – but due to the range of possibilities it is extremely hard and time consuming to get close to roles that follow the need-to-know principle.
In an audit, it is thus likely that there will be at least one or two findings dealing with extensive authorizations... that's probably the reason you read until here. 😉
Well... the problem is often that it is unclear how critical rights can be effectively reduced (without long deadlines or additional staff).
Audit findings that deal with SAP authorizations consist of a finding text that describes the "problem" (comprising a risk) and are usually accompanied by an evaluation of the critical rights and segregation of duties conflicts that led to the finding(s). Taking care of such findings can lead to time-consuming activities, as you need to take care of the listed rights (or users assigned to these rights) and additionally make sure that you don't just slightly tidy up the system, but also solve the core problem of the finding.
A best-practice procedure can help you tackle the cleanup and distribute the individual tasks to the responsible people.
Some basics upfront
A critical right is a single authorization, which can be used to perform extensive actions in the system, such as broad read access or uncontrolled data modifications.
- Debug with replace.
- Modification of program code in production.
- Display (or change) authorization for all tables in production.
A segregation of duties ("SoD") conflict is a combination of at least two authorizations, which can be used by a single person to execute a whole process and which must usually be distributed among several persons.
- Maintenance of vendor master data & maintenance of purchase orders.
- Creation & approval of expense reports.
Risk management: there are several ways to deal with a risk: you can...
- Ignore it – the worst choice (if a real choice at all)! The risk might lead to unforeseen damages and the extent is unclear. This usually results in the worst possible audit assessment... quite rightly.
- Accept it – if the risk is either very unlikely and/or has a minor impact, you can choose to accept it. Maybe it's a strategic risk, which is directly linked to your business model; then you may not be able to manage it without a negative impact on your ability to make profit (which you might consider unacceptable). The most important point when accepting a risk is: think about it and do it intentionally! The person, who decides on this must be in charge of the affected process and in a position to take the decision.
- Avoid it – if a risk has a potentially large impact on your business (and is maybe even likely), an adequate way of risk management may be to completely avoid the risk.
- Transfer it – essentially, you transfer the impact and management of the risk to someone else. You'll have to pay for this in one way or another. Outsourcing is a common example.
- Mitigate it – means that you reduce the potential impact or likelihood (or both) so that if the event occurs, it is easier to overcome – this means that a residual risk remains. It's a common technique, as taking risks is inherent to running a business and mitigation provides a good balance between not managing a risk (at little cost) and avoiding or transferring it (at high cost).
A compensating control strives to control a residual risk, e.g. by a regular ex-post check. Personnel restrictions, for example, could prevent an effective segregation of duties between the creation and approval of expense reports. A daily review of the creations and approvals by a responsible manager would enable the detection of fraud cases and is, therefore, a compensatory control.
The proposed procedure
Before you start, you should ensure a common understanding and expectation concerning the remediation; thus:
- Review all critical rights with the auditor to understand their impact/criticality.
- Discuss with audit, which critical rights must be remediated and which may be accepted.
The flowchart below strives to provide you with a structured approach to tackle authorization-related findings.
The basic idea is that you loop through the procedure role by role (or right by right) and continue until every authorization in scope has been checked and either found to be good or cleaned up.
( click here for a PDF version )
Most steps in the flowchart are rather obvious and I will not explain them in detail... the green decisions boxes, on the other hand, are very important and need some explanation:
Assignment of roles to users justified by positions of the employee?
Each user ID should relate to exactly one natural person, which in turn holds a position. To fulfill the tasks associated with that position, specific authorizations are required. The roles assigned to a user should not include more authorizations than needed to fulfill their position.
In case users do not belong to one person but are rather (at least potentially) used by several people, please get in touch with the auditor. Depending on the authorization concept and possibly implemented controls this might or might not be valid.
Does the right fit to the purpose of the role(s)?
In case the user is properly assigned to the role(s), which are associated with his/her position and there are still critical rights listed, the role could contain too many authorizations.
You should check if the role purpose and the contained rights match. Can the critical rights be removed without impacting the user's work? Keep in mind that some tasks occur only occasionally, e.g. when the annual financial statement is prepared.
Are there users with critical rights left?
After performing the two checks above for all critical right/user assignments, most rights should be either remediated or found to be justified.
Anyway, some questionable critical rights might be left, for which no remediation could be found – either due to special (known) situations or because of small team sizes, which do not allow proper segregation of duties. These remaining cases should be considered very carefully because they represent a risk and thus need to be controlled. To do this, we need to differentiate further...
Is it a (single) critical right or an SoD conflict?
The difference between these two has been described in the chapter "Some basics upfront"...
Single critical right – Define control or accept the risk?
For each remaining critical right, either a control must be implemented or the risk must be accepted by a person, who is accountable for the affected process or function and in a position to do so.
If acceptance is not an option and no efficient compensating control can be defined, the critical right must be remediated. If unsure, discuss the situation with your auditor!
SoD conflict – Does a compensating control for the conflict exist?
The situation is roughly the same for SoD conflicts: they must either be mitigated by a compensating control or cleaned up. It is inadequate to have SoD conflicts without any control. In case the conflict cannot be solved, e.g. due to staff shortages or small team sizes, a compensating control could be applied to reduce the risk to an acceptable level.
Your risk management department can usually provide you with best-practice approaches for such controls.
Can the chosen control be implemented?
In case a compensating control exists for the SoD conflict in question, you should decide with the affected persons if it can be implemented. In case the control is considered too complicated or not favorable at all, the SoD conflict must be cleaned up.
As such controls must be executed accurately, resources are required – and in the end, the conflict might be cleaned up, just because the additional effort for the control is considered too high... It is therefore very important to ensure that compensating controls are not defined without clear communication about the involved effort!
Hopefully, the above procedure helps you iron out SAP authorization findings!
a long time passed since my last post and even more, things changed in my life.
My "blue team" perspective has changed to the viewpoint of an internal auditor - and upcoming posts will probably reflect this… life remains exciting. 😎
In the following, we'll take a look at customer name ranges in SAP and how to use them to move things like malicious code out of the sight of security people and… well… auditors.
First of all:
Customer-created objects in SAP do not always start with Y* and Z*.
There are many more possibilities.
Let's start with some obvious things: Workbench objects in SAP (custom reports, tables, transaction codes, function modules, and many more) may not be named arbitrarily. They are bound to name ranges, which SAP designated for customer developments.
SAP Note 16466 - "Customer name range for SAP objects" gives a list of allowed name ranges per object type (yes: different types have different allowed name ranges).
In this post, we'll focus on some of the types, which are interesting for an attacker and allow data manipulation or implementing backdoors, etc.: ABAP reports (obvious!), tables (just because), and transaction codes (e.g. to bypass S_PROGRAM checks).
Let's see what the above-mentioned SAP note 16466 says about the allowed customer name ranges for these objects:
SAP adds in a strict but benevolent tone:
"It is essential that you always adhere to the SAP naming conventions. Serious problems may otherwise result during the next upgrade (the upgrade overwrites customer objects)."
We'll come back to that later.
It's time to dive deeper: when you try to create - for example - a new report in the ABAP workbench, a function module is called in the background that checks the specified name for its compliance with the allowed name ranges.
The relevant FM is TRINT_GET_NAMESPACE and it differentiates between 3 types of object names:
- Partner, and
For objects in the partner and SAP-reserved name ranges, you need an object key to create them - we won't discuss them here.
The allowed names can be found in the FM's source code (which is
pasta code long and has grown for many years).
I'll quickly summarize it for our 3 examples (reports, tables, and transaction codes) here:
|Name starts with...||Name range||Remarks by SAP|
|Customer||Old customer namespace|
|Customer||Modifiable MC programs|
|Customer||Modifiable help view program|
|Partner||Old partner namespace|
|Partner||Old partner namespace|
|( all others )||SAP-reserved|
|Name starts with...||Name range||Remarks by SAP||My remarks|
|Customer||Old customer namespace|
|Table names in this range are checked against the exception|
table TDKZ. If no entry is found, the name belongs to the
customer name range.
Table TDKZ usually contains the entries listed in the second
last line of this table.
|Partner||Old partner namespace;|
TJ-tables only for 2.2-compatibility
|SAP-reserved||These table names are SAP-reserved as per the exception table TDKZ.|
|( all others )||SAP-reserved|
|Name starts with...||Name range||Remarks by SAP|
|Customer||Old customer namespace|
|J||Partner||Old partner namespace|
|( all others )||SAP-reserved|
So, we have a whopping 47 name ranges to choose from for our next malicious report! … and hardly any auditor will ever identify a program called MSTHRP9INT as a customer-developed one.
To be even more sure, you could also fake the report's "creator" easily (more on this in my next post).
Now back to SAP's stern statement on what happens, when you're not nice and use name ranges not listed in Note 16466:
First, I doubt it - but didn't check it myself. Since the FM TRINT_GET_NAMESPACE is used by every workbench-related functionality in the ABAP-stack, I would assume that all ABAP code, which is called during an update also uses the same logic. The command-line tools (tp, R3trans …) are usually synced with their ABAP pendants, so they'll probably perform very similar checks as well.
And secondly, it doesn't matter. Most attackers would probably do, what they intended to do, once they have compromised an SAP system in such a way. There's no need to wait a long time and then come back… and persistence inside a victim's network can be achieved in more reliable ways and with fewer traces to cover.
Happy hunting and see you! 😀
PS: Just to prevent confusion - this post is about "name ranges", not "namespaces" like /SNAKEOIL.
Hi SAP security enthusiasts,
the Security Audit Log [SAL] contains -obviously- information about important system events and should, therefore, better not get lost unintentionally!
Let's see, how the Audit Log can be erased and what we can do to prevent this and maximize its protection.
The Audit Log is stored in log-files that are located in the file system (see parameter DIR_AUDIT) and is either rotated daily or when the current file is full (see parameter rsau/max_diskspace/per_file).
Access to these files is possible via kernel functionality (from within the SAP system) or on operating system level (e.g. via an external OS command). We’ll focus on access via the SAP application server and won’t take a deeper look at manipulations directly from OS level (i.e. from the command line).
Ways to delete the Security Audit Log
From inside the SAP system, three variants of deleting the SAL files exist.
Below we'll check them and see, which measures exist to protect the logs.
Variant 1: SM18 (or function module RSAU_CLEAR_AUDIT_LOG or system function C_REMOVE)
SM18 is the SAP standard way of removing old SAL files.
The transaction is protected by an authorization check for S_ADMI_FCD with value AUDA (= AUDit log Administration). The minimum age of files to be erased is 3 days − a nice feature because an attacker cannot remove fresh logs and hide what he/she did moments ago.
SM18 is not really problematic… S_ADMI_FCD with value AUDA is a critical authorization, which nobody should be assigned to on production.
Diving a bit deeper…
A clever developer might try to copy the code that is responsible for the deletion to a customer report − fortunately, this does not work... see below:
REPORT. WRITE 'SM18 (C_REMOVE):'. DATA: errno TYPE rsautypes-errno , errmsg TYPE rsautypes-errmsg. CALL 'C_REMOVE' ID 'DIR' FIELD '/usr/sap/<SID>/DVEBMGS00/log' ID 'FILE' FIELD 'audit_20160425' ID 'GROUP' FIELD 'AUDIT' ID 'ERRNO' FIELD errno ID 'ERRMSG' FIELD errmsg. IF sy-subrc = 0. WRITE: 'successful'. ELSE. WRITE: 'failed;', errmsg. " caller not registered ENDIF.
⇒ This report always runs into an error, because the SAP kernel checks the program name that calls the C_REMOVE function against an internal whitelist; we'll always get a "failed; caller not registered" message…
Variant 2: DELETE DATASET
A more sophisticated way of getting rid of audit log files is to simply delete them via the DELETE DATASET statement from within an ABAP report.
A simple example:
REPORT. WRITE 'DELETE DATASET:'. TRY. DELETE DATASET '/usr/sap/<SID>/DVEBMGS00/log/audit_20160425'. IF sy-subrc = 0. WRITE 'successful'. ELSE. WRITE 'failed / not found'. ENDIF. CATCH cx_sy_file_authority. WRITE 'missing authorization'. ENDTRY.
The kernel checks for S_DATASET authorizations each time a DELETE DATASET statement is executed (this cannot be prevented since the check takes place in the kernel).
The field ACTVT is checked for value 06 (delete) and the FILENAME field for the path of the file to be deleted.
A check for authorization object S_PATH can be activated to implement additional protection for file system accesses. It is then evaluated after a successful S_DATASET check.
Alternatively, we can also prevent unauthorized log file deletion completely… even if a user has S_DATASET with all field values set to "*"!
For the additional check, the logic is as follows (see SAP Note 177702):
- first, the system checks whether the SPTH table contains a PATH, which matches the start of the pathname of the log file that we want to delete
- if an authorization group is set in the FS_BRGRU field, the system then performs an authorization check on S_PATH with ACTVT = 02 (write or delete)
Additionally, the table SPTH has two flags, which can further limit file access and overwrite the authorization checks on S_PATH and S_DATASET:
- if FS_NOREAD has the value "X", neither read nor write access is possible
- and FS_NOWRITE = "X" prevents write access
To effectively prevent Security Audit Log deletion, you can add the following entry to SPTH:
PATH = /usr/sap/<SID>/DVEBMGS00/log/audit_
FS_NOREAD = X
FS_NOWRITE = X
Afterward, no user will be able to read or modify the SAL log files – disregarding their authorizations!
Anyway, SM20 will continue to work, as the access takes place in the kernel.
Variant 3: External operating system command
The third variant does not use the SAP kernel to delete the file, but rather an OS command (in the following example we’ll use the Unix/Linux rm command).
The following report creates a new external command, executes it to delete the same audit log file as above and finally deletes the command.
The creation and deletion of the command is logged via table logging for table SXPGCOSTAB… but at least at a first glance, we can hide what we did by deleting the command after execution…
REPORT. WRITE 'External command (SM69):'. DATA command TYPE sxpgcolist. command-NAME = 'Z_DEL_AUDITLOG'. command-opsystem = sy-opsys. command-opcommand = 'rm'. command-addpar = 'X'. CALL FUNCTION 'SXPG_COMMAND_INSERT' " --- Create command EXPORTING command = command EXCEPTIONS OTHERS = 1. IF sy-subrc = 0. WRITE 'creation successful;'. ELSE. WRITE 'creation failed.'. LEAVE PROGRAM. ENDIF. DATA exitcode TYPE extcmdexex-exitcode. CALL FUNCTION 'SXPG_COMMAND_EXECUTE' " --- Execute command EXPORTING commandname = command-NAME additional_parameters = '/usr/sap/<SID>/DVEBMGS00/log/audit_20160425' IMPORTING exitcode = exitcode EXCEPTIONS OTHERS = 1. IF sy-subrc = 0 AND exitcode = 0. WRITE 'execution successful;'. ELSE. WRITE 'execution failed;'. ENDIF. DATA: BEGIN OF command_del. INCLUDE STRUCTURE sxpgcostab. DATA: sapcommand TYPE sxpgcolist-sapcommand , TYPE(8) TYPE c , END OF command_del , rc TYPE i. command_del-NAME = command-NAME. command_del-opsystem = command-opsystem. PERFORM command_delete(saplsxpt) " --- Delete command USING SPACE CHANGING command_del rc. IF sy-subrc = 0 AND rc = 0. WRITE 'deletion successful.'. ELSE. WRITE 'deletion failed.'. ENDIF.
Of course, you could also create, execute and delete the command via transaction SM69.
The above method works fine if you have S_RZL_ADM (ACTVT = 01) for the creation of the command and S_LOG_COM authorizations for execution.
Unfortunately, the SPTH-protection from variant 2 does not work here.
If table logging is enabled (profile parameter rec/client), changes are recorded in table DBTABLOG and can be evaluated via transaction SCU3 (for table SXPGCOSTAB).
All three variants can be protected quite well via authorizations, so log deletion can be prevented by strictly controlling these authorizations.
Anyway high-privileged users – e.g. emergency users – still have access, so I suggest also implementing the SPTH-protection described in variant 2. 💡 It provides a good additional line of defense around the log files.
Please keep in mind that you should also take care of protecting table SPTH itself… 💡
Apart from the "access"-perspective, organizational measures should be implemented to make sure that malicious code - like to one above is - checked (and rejected) before a transport to production takes place!
Currently, a lack of time prevents me from finishing a post, which is in the pipeline for weeks now. Nevertheless, I'd like to point out a behavior of Security Policies, which might lead to an unexpected situation, if you're not aware of it (fortunately you will be).
Let us assume that you have hardened your system and set the password-related profile parameters login/min_password_lowercase = 1 and login/min_password_uppercase = 1. This forces users to include at least one lower- and one uppercase character in new passwords. The kernel default for both parameters is 0.
Additionally, you set the parameter login/min_password_lng = 10 to enforce a minimum password length of 10 characters.
Unfortunately, there is an RFC user on your system, which must – for whatever technical reason – not have a password longer than 8 characters. As you don't want to lower the system setting, you choose to create a new SECPOL with just the attribute MIN_PASSWORD_LENGTH = 8 and leave the profile parameter as it is (= 10). The desired result is obviously to override the minimum password length with a lower value for just the one RFC user and stay with the more secure value for all other users.
The SAP Help Portal says:
… you create security policies with attributes, for which you explicitly do not want to use the default value.
My initial expectation was, that a SECPOL attribute overrides the corresponding profile parameter (in our example MIN_PASSWORD_LENGTH overrides login/min_password_lng) … and all other profile parameters, for which SECPOL attributes exist, stay as they are set in the profile.
So, login/min_password_lowercase could potentially be overridden by MIN_PASSWORD_LOWERCASE – but since we did not add it to our SECPOL, one could assume that the profile value stays intact.
Security Policies do not override profile parameters - rather they replace them! All of them.
All profile parameters, for which a SECPOL attribute exists, are replaced – so if an attribute is not explicitly set in a SECPOL, the kernel default value is used! Not the profile parameter value.
The bottom line
If you've set any of the profile parameter values, which can be influenced by a Security Policy, you have to make sure that all those profile parameters are explicitly set again in all of your SECPOLs!
So, once you choose to make use of SECPOLs, you have to maintain all values at least twice: in RZ10 and in your Security Policy/ies… otherwise, you end up using default values by mistake.
Yep... unspectacular... but still interesting 🙂