Daniel Berlin on Security IT Audit, SAP security, development… and all the rest

13Mar 19

Customer name ranges for SAP objects

Dear readers,
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:

[except from the SAP note]

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:

  • Customer,
  • Partner, and
  • SAP-reserved

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 actually 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:

→ Reports

Name starts with...Name rangeRemarks by SAP
Y
Z
CustomerOld customer namespace
MP9CustomerInfotype-dialog module
SAPDY
SAPDZ
DY
DZ
CustomerDialog-module-pools
SAPFY
SAPFZ
FY
FZ
CustomerSubroutine-pools
SAPMY
SAPMZ
MY
MZ
CustomerModule-pools
SAPUY
SAPUZ
UY
UZ
CustomerUpdate-tasks
MENUY
MENUZ
MENU+
CustomerMenus
MSTY
MSTZ
MSTP9
MSTT9
MSTHRI9
MSTHRP9
MSTHRT9
MSTPA9
MSTPB9
MSTPS9
MSTPT9
CustomerTables



3.0E
3.0E
3.0E



3.0E

MC_Y
MC_Z
MC_....0
MC_....1
MC_....2
MC_....3
MC_....4
MC_....5
MC_....6
MC_....7
MC_....8
MC_....9
CustomerModifiable MC programs
Customer MCOBs
Customer MCOBs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
Customer MCIDs
%H_Y
%H_Z
CustomerModifiable help view program
J_
MJ
DJ
FJ
UJ
PartnerOld partner namespace
SAPMJ
SAPDJ
SAPFJ
SAPUJ
MSTJ_
MSTTJ
MENUJ
PartnerOld partner namespace
( all others )SAP-reserved
→ Tables
Name starts with...Name rangeRemarks by SAPMy remarks
YY
ZZ
CI_
H_Y
H_Z
HRI9
HRP9
HRT9
PA9
PB9
PS9
PT9
P9
CustomerOld customer namespace




3.0E
3.0E
3.0E



3.0E
Y
Z
T9
Customer
(with exceptions)
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.
J_
TJ
PartnerOld partner namespace;
TJ-tables only for 2.2-compatibility
T9COM
T9DEV
T9PRO
ZCXCB
ZCXCM
ZHLB1
ZHLG1
ZHLG2
ZIS_FORM
SAP-reservedThese table names are SAP-reserved as per the exception table TDKZ.
( all others )SAP-reserved
→ Transaction codes
Name starts with...Name rangeRemarks by SAP
Y
Z
+
CustomerOld customer namespace
JPartnerOld 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 really 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 less traces to cover.

Happy hunting and see you! 😀

PS: Just to prevent confusion - this post is about "name ranges", not "namespaces" like /SNAKEOIL.

11Jan 15

New GitHub repository for REPOSRC decompressor

Hi all.
Some time ago, I posted a small C++ program that decompresses the source code stored in table REPOSRC
(⇒ check this article).
New GitHub repository
It was never intended to be more than a proof of concept, but since many people showed interest in it (and found bugs), I decided to create a GitHub repository:

https://github.com/daberlin/sap-reposrc-decompressor/

It contains the history of my ancient CVS repository (converted thanks to this great how-to).

So… if you find any bugs or want to help improve it — please go there and either create an issue or simply fork it and unleash the developer in you).

See you!

» Update: The repository has been moved to https://gitlab.com/daberlin/sap-reposrc-decompressor

24Dec 12

Find obsolete SAP roles (not assigned for X days)

Hi authorization admins,
from time to time I get in the mood to clean up one or two SAP systems – and lately I was looking for obsolete roles, which weren't assigned to anybody for ages (e.g. used at least 365 days ago).

While looking around in SUIM and change documents, the developer inside me became more and more delighted – because there is no SAP standard solution for this → time for some R&D. 😛

Report

Here we go:

  • Create a new report in SE38 and paste this source code (don't forget to set a program authorization group *cough*).
  • There's no need to edit any of the selection texts, as they're defined inside the report…
  • Activate & execute the program.

Usage

The report allows you to select:

  • the role names (all SAP standard roles excluded per default),
  • the user who created the role (default exclusion: "SAP") and
  • the days since the role's last assignment to any user (default: 180).

Result

The result consists of the following columns:

  • Role: … well… the role name
  • Creation date: the role's creation date
  • Change date: the date of the role's last change
  • Removal date: the date of the last removal from a user
  • Removed by: the user, who performed the removal
  • Role name: the role description
  • 3 status indicator fields:

Role type:

The role type shows, whether it is a single or composite role (using the standard SAP icons).

Status:

This icon equals to the traffic light icons on PFCG's "Authorizations" tab (→ green: generated, yellow: action required, red: not generated).
For composite roles this field stays empty (since they have no profile).

SR used in CR:

For single roles, this icon indicates if the role is assigned to a composite role (glowing bulb) or not (dark bulb).
Of course this makes no sense for composite roles – so the field is empty then.

Final words

Obsolete / superfluous / unused roles on productive systems should be removed before they get moldy!

😀 Happy Xmas 😀

3Oct 12

Determine transaction type & status from table TSTC (field CINFO)

Hello programmers,
if you ever wanted to determine the transaction type (dialog, parameter tcode …) and status (locked …), you probably came across table TSTC (where tcodes are defined) and found that this information is encoded in the CINFO field — which contains an old-school hexadecimal value.

Meaning

So… wtf do those CINFO values mean? Here we go:

CINFO (hex)BinaryTypeLocked ?Auth. object check ?
0x000000 0000Dialog transactionnono
0x040000 0100Dialog transactionnoyes
0x200010 0000Dialog transactionyesno
0x240010 0100Dialog transactionyesyes
0x010000 0001Area menu (obsolete)no-
0x210010 0001Area menu (obsolete)yes-
0x020000 0010Parameter / variant transactionno-
0x220010 0010Parameter / variant transactionyes-
0x080000 1000Object transactionnono
0x0C0000 1100Object transactionnoyes
0x280010 1000Object transactionyesno
0x2C0010 1100Object transactionyesyes
0x801000 0000Report transactionnono
0x841000 0100Report transactionnoyes
0xA01010 0000Report transactionyesno
0xA41010 0100Report transactionyesyes
0x901001 0000Report transaction with variantnono
0x941001 0100Report transaction with variantnoyes
0xB01011 0000Report transaction with variantyesno
0xB41011 0100Report transaction with variantyesyes
0x05 (invalid)0000 0101Area menu (obsolete)no-
0x06 (invalid)0000 0110Object transaction -or-
Parameter transaction
no
no
yes
n/a
0x44 (invalid)0100 0100Dialog transactionnoyes

(The CINFO values marked with "invalid" exist, but make no sense… probably because they're relicts created by SAP a long time ago. 😯 )

Bitmasks

According to the above, these are the bitmasks for your own program:

Bitmask (hex)BinaryMeaning
0x000000 0000Dialog transaction
0x010000 0001Area menu
0x020000 0010Parameter / variant transaction
0x080000 1000Object transaction
0x801000 0000Report transaction
0x901001 0000Report transaction with variant
0x040000 0100Flag: Authorization object check ?
0x200010 0000Flag: Locked ?

Example

To get started, either have a look at the report "RSAUDITC_BCE" or try this:

REPORT.
 
TABLES: tstc.
 
* -- Bitmasks
DATA: c_auth TYPE x VALUE '04',
      c_lock TYPE x VALUE '20'.
 
* -- Find all locked transactions
SELECT * FROM tstc.
  CHECK tstc-cinfo O c_lock.
  WRITE: / tstc-tcode, 'is locked'.
ENDSELECT.
 
* -- Find customer transactions w/o authorization check
SELECT * FROM tstc WHERE tcode LIKE 'Y%' OR tcode LIKE 'Z%'.
  CHECK NOT tstc-cinfo O c_auth.
  WRITE: / tstc-tcode, 'has no authorization check'.
ENDSELECT.
3Oct 12

Import user favorites into a role menu

Hi consultants,
did you ever wonder, what's behind the button "Import from file" in PFCG's Menu tab?

Well, it obviously allows you to upload a menu from a file, but expects a special file format: SAP Note 389675 has the details. You won't find this format anywhere in PFCG or elsewhere in your system, so it has to be created by you…

This usually makes the "Import from file" button hard to use and thus unpreferable!

The plan

Let's say, you're trying to revise (and minimize) the authorization in a SAP client ex post, i.e. when the system has been in use for some while and nobody took care of proper roles. Moreover some (key-) users might already have created their own favorites, which – hopefully – reflect their tasks in the system.

Wouldn't it be nice to be able to import those user favorites to a role and build adequate authorizations this way? Still there will be much to analyze and adjust — but it might be a good starting point!

Technical background

A user's favorites are stored in the table SMEN_BUFFC and SMEN_BUFFI (for the various kinds of link targets). So this is the place we'll get the menu data from.

The file format from the above mentioned SAP Note 389675 only supports a subset of all possible favorite types: folders, transaction codes, URLs, Knowledge Warehouse links and custom types (we won't deal with the last-mentioned one).
So in addition to reading and converting the favorites, we'll have to filter out all unsupported types of favorites.

Conversion report

Here's how to create the program that does the work:

  • Create a new report in SE38 and paste this source code (don't forget to set a program authorization group).
  • In the selection texts, tick "dictionary reference" for all parameters.
  • Activate & execute the program.

The selection screen allows you to select:

  • the user from whom to read the favorites and
  • an optional file to save the data to.

Once started, the report prints the converted favorites on screen and optionally saves it to the specified file.

Next steps

You might want to customize the report to download the favorites of several users at once — but be aware that you'll have to either save each user's favorites to its own file or deal with duplicate object IDs (and parent IDs and the sort order …)!

If you're interested in role menus, you might want to check the AGR_HIER* tables.

😀 Have fun!