Adapting hashcat for SAP ‘half hashes’

In this article we will show how to adapt hashcat to work with SAP’s “half hashes”.

Context

One crucial aspect during SAP penetration testing is abusing users’ privileges after we got access to their passwords.

We often encounter a scenario when the server is an SAP NetWeaver ABAP and the interface available is via RFC protocol (be it either over tcp/33NN, or over webrfc SOAP gateway). In this scenario, we cannot login via SAP GUI (we got a system or communication user) but want to obtain an access of some existing SAP GUI users or just assess the robustness of the users’ passwords. So, it is necessary to get a hand on clear-text passwords.

We already know that SAP users’ passwords are hashed and stored for ABAP application server in the USR02table. The column BCODE stores the SAP CODVN B hash of the password, the column PASSCODE the SAP CODVN F/G version., and if the server is not too old we can find the column PWDSALTEDHASH with the SAP CODVN H hashed password.

The only way of gaining access to the database table via RFC is to invoke the (remote-enabled) function module RFC_READ_TABLE. This function has initially not been made to extract RAW fields and will return a truncated value with half the size of the original field.

For dictionary brute forcing hashes, it is a blocking issue. We need a full hash to check it against tools like hashcat/JohnTheRipper.

To solve this issue, it is required to find another RFC function module that is remote-enabled. In systems where Data Services are installed, variants exist that do not have this limitation/bug on raw data and can be directly handled with usual cracking tools:

  • /BODS/RFC_READ_TABLE
  • /SAPDS/RFC_READ_TABLE

There are still a number of systems without those function modules available. In this case, we get around the issue by adapting hashcat’s hash verification for BCODE and PASSCODE hashes. NB: PWDSALTEDHASH does not have this problem as it is stored as CHAR, but it is much slower to brute-force.

Methodology of adapting SAP mangled hashes to hashcat

Extract the hashes via RFC / SOAP RFC by calling function module RFC_READ_TABLE. And pad with NULL bytes the second part of the hash that is missing. So, it may look like this in our test system:

SAP hashes extraction

Extracting SAP hashes via pure RFC connection

pyRFC method using the NWRFCSDK

This will go through the Gateway service listening on tcp/33NN and will be dispatched for execution to one of the ABAP worker process.

Extracting SAP hashes via SOAP RFC

If the RFC port is not available, we can achieve the same result through the SOAP RFC interface on the ICM HTTP service (tcp/80NN).

Padding SAP half hashes

RFC dump of some users with non NULL BCODE hash is as follows:

MANDT BNAME UFLAG BCODE
001 BATIPPS 0 45E6C3EF
001 BLUMOEHR 0 7D3C4D5B
001 BOEHMA 0 D23047EF

Then we need to fix the hashes so that hashcat will ingest them with the default SAP CODVN parser: (we adopted this strategy in order to minimize the changes in the code)

BCODE half-hash BCODE fixed
45E6C3EF 45E6C3EF00000000
7D3C4D5B 7D3C4D5B00000000
D23047EF D23047EF00000000

and build a file with the following usernames/hashes:

Hashcat patch for SAP’s half hashes

We explain how we patch hashcat’s existing hashes (7700, 7800) into new ones (7701, 7801). We will focus on the attack mode 0 (i.e. wordlist and wordlist+rules) as it is mainly what we use during security assessments. The modifications are similar for the brute-force (-a3) and combinator modes (-a1).

SAP CODEVN B (7701)

The adaptation for CODEVN B (BCODE) hash is trivial and only requires clearing the b value inside the OpenCL kernel of the 7700 version so that we check only the first 32 bits of the clear-text hashed value against our computation.

SAP CODEVN F/G (7801)

In the PASSCODE case, we need to be a bit more careful as our limit where bits are all zeroed is in the middle of a 32-bit value. So we need to clear half of the digest2 32 bit value and the last part of the digest (digest[3] and digest[4]).

If we show a hexified representation of the digest when hash is full and mangled we have something like this:

  • PASSCODE full hash extracted from USR02 table: BC150094 0E40B280 A3AA0519 33D4939C 9DAFCD27

  • PASSCODE half hash extracted from USR02 table: BC150094 0E40B280 A3AA0000 00000000 00000000

So the adaptation of the 7800 OpenCL kernel to 7801 becomes:

As of collisions, we don’t think that it is a practical issue when considering that the probability for collision candidates to be in a valid password character set space is likely to be very low.

We added those as new hashes in our modified version of hashcat, namely:

  • 7701 SAP CODVN B (BCODE) via RFC_READ_TABLE
  • 7801 SAP CODVN F/G (PASSCODE) via RFC_READ_TABLE

Benchmark

With this method, there should not be any differences with the benchmark results of the 7700 and 7800 hashes.

Result

Here is a short video showing how this work-flow can be automated from the remote RFC hashes extraction to the dumping of the brute-forced passwords against a dictionary of common passwords:

hashcat demo

Download

You can download our patched version based on the hashcat release v4.1.0-3-g63defd1+. The sources of our modified version is available in our github

Do you want more?

Subscribe me to your mailing list