"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

Normale salted MD5 Hashes für Auth ins htpasswd Format portieren (ServU=>Apache)

GrandAdmiralThrawn 21.04.2008 - 11:17 7203 15
Posts

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
Grüße!

Bevor ich zum eigentlichen Problem komme zuerst die Ausgangslage in Sachen Software:
  • OS: Microsoft Windows 2000
  • FTP Server: Serv-U 6 FTP Server
  • Webserver: Apache 2.2.4 Win32
  • Credentials für die Tests: User=testuser, PWD=testuser.
  • PWD Verschlüsselungen: Angeblich bei FTP- und Webserver MD5.
Das sollte auch schon alles wichtige sein. Nun zum Problem...

WAS soll eigentlich getan werden? Nun, am Webserver soll eine Seite geschützt werden, die FTP Statistiken zeigt. Nicht weiter schwer, ließe sich per htpasswd/.htaccess machen. Nur sollen die User vom FTP auch zum Webserver portiert werden, ohne die Klartextpasswörter zu kennen, damit sich FTP User mit bestehenden Credentials am Webserver einloggen können. Das geht nur mittels gleicher Hashalgorithmen. Die scheinen sich aber sowohl in ihrer Verschlüsselung, als auch Repräsentation (Encoding) zu unterscheiden. Zuerst zum FTP:

Der Serv-U 6 FTP Server hat bei mir ca. 30 User, und bis auf die Passwörter ist alles im Configfile als Klartext abgelegt. Die Passwörter, also das eigentlich interessante ist MD5 hashed.

Die Hashes sind mit 2-Byte Salts versehen. Im Configfile des FTP Servers sieht die entsprechende Zeile z.B. so aus:

Password=qi481F86E841C9D742BA6CC4261CF8EACF

"qi" ist also der Salt, der Rest der MD5 Hash, der aus Salt+PWD generiert wurde, also in unserem Falle aus "qitestuser". Daß der Hash wirklich Standard MD5 ist, läßt sich mittels des Tools mdcrack verifizieren. Wenn man selbiges mit stark limitiertem Alphabet auf den Hash losläßt, ist er innerhalb weniger Sekunden zu cracken. Der Salt muß natürlich als Prefix für den Challenge mit übergeben werden. Die Verifikation erfolgte so:

mdcrack-12.exe -s testuser -v -b qi -M MD5 481F86E841C9D742BA6CC4261CF8EACF
"-s" spezifiziert das Alphabet, "-b" den Salt als Prefix für die Challenge. Cracked nach nur 11 Sekunden auf C2D 3.16GHz mit reduziertem Alphabet.

Gut, nun wußte ich, Serv-U 6 setzt ganz normale salted MD5 Hashes ein. Soviel also zum FTP Server, hier liegt der Fall klar. Nun aber zum Apachen...

Wenn man am Apachen ebenfalls einen User "testuser" mit PWD "testuser" anlegt (mit default PWD encryption, bei Win32 laut htpasswd.exe "MD5"), sieht die entsprechende Zeile im htpasswd File (oder wie man sein Userfile halt nennen möchte) so aus:

testuser:$apr1$oo1.....$7Qr1pbvQE4uKH8gpveF.h/


Nach kurzer Google-Befragung wurde die Syntax einigermaßen klar, sieht so aus:

<username>:$apr1$<salt>$<md5 password hash>

Nun ist das ein MD5 Hash, wie ich ihn noch nie zuvor gesehen habe. Ein Kollege informierte mich dann, daß es verschiedene, gängige Codierungen/Repräsentationen für MD5 Hashes gibt. Eine davon ist hexadezimal, wie z.B. vom Serv-U FTP Server verwendet. Es gibt aber noch weitere, wie z.B. 8-Bit ASCII, binär, 6-Bit base64, 5-Bit base32 usw.

Base64 wäre noch ok gewesen, aber scheinbar verwendet Apache nicht das [standard base64 Alphabet] um den Hash darzustellen, sondern ein 6-Bit custom Alphabet, auch wenn ich nicht begreife, wieso?!

Auszug aus htpasswd.c (Apache 2.2.4 Win32 Sourcecode):
Code:
static void to64(char *s, unsigned long v, int n)
{
    static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    while (--n >= 0) {
        *s++ = itoa64[v&0x3f];
        v >>= 6;
    }
}

Das base64 Alphabet würde "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ =" lauten, dies ist mit dem 6-Bit Alphabet des Apache htpasswd Tools wie man sieht nicht identisch. Warum ein custom Encoding gewählt wurde, verschließt sich mir völlig. Wieso nicht das bestehende Standard base64, für das es fertige Converter zu ASCII oder HEX gibt?! Ich weiß es nicht. Aber das war nicht das einzige Problem...

Hier ein Auszug aus der Apache Dokumentation, der mich erst recht aus allen Wolken fallen ließ:
Zitat
MD5
"$apr1$" + the result of an Apache-specific algorithm using an iterated (1,000 times) MD5 digest of various combinations of a random 32-bit salt and the password. See the APR source file apr_md5.c for the details of the algorithm.

Der Salt in jedem der 1000 Hashschritte ist Random 32-Bit steht hier. Meiner Meinung nach ist der Salt aber 8-32 Bit, also auch in Länge variabel (man siehe ein htpasswd Ergebnis mit unterschiedlichen PWDs)!

Ich habe mir den Qellcode der apr_md5.c natürlich angesehen, aber das ist mir einfach zu hoch, da ich kein C beherrsche, und das nur sehr begrenzt verstehen kann, habe auch von Kryptographie null Ahnung. Aber der Zeichensatz (das bestätigt sich durch 6-Bit Rightshifts in apr_md5.c würde ich meinen) ist wohl definitiv besagter custom base64, da eben auch die Funktion "to64(char *s, unsigned long v, int n)" eingesetzt wird.

Nun die Primefrage an alle, die den Quellcode verstehen (ist als ZIP angehängt, htpasswd.c und apr_md5.c): Wie kann ich Standard MD5 Hashes so portieren, daß daraus von Apache lesbare MD5 Hashes werden (sprich: Reproduktion des Apache Hashalgos, ohne alle PWDs vorher zu Plaintext cracken zu müssen)?

Ist es überhaupt möglich, den Standardhash von Serv-U zu so einem Customhash zu machen? Das Encoding im custom base64 Alphabet ist wohl noch das geringere Problem, aber ich verstehe diese 1000 MD5-Runs mit Random Salts leider nicht ausreichend.

Ein cracken oder erfragen aller FTP Userpasswörter wäre zu mühsam oder im Crackfall schlichtweg gröber bedenklich.

Vielen Dank für eure Hilfe!

Anhänge (Apache Sourcecode):
htpasswd.c als ZIP
apr_md5.c als ZIP

Dieser Fall wurde auch bei [DevShed] gepostet.
Bearbeitet von GrandAdmiralThrawn am 21.04.2008, 11:33 (Kleinere Korrekturen)

COLOSSUS

Administrator
Frickler
Avatar
Registered: Dec 2000
Location: ~
Posts: 11903
Ich hab den Thread nur ueberflogen und grade im Moment aufgrund anderer Obligationen keine Zeit, den Quellcode des Apache-md5-Hashers anzusehen, aber wenn da wirklich 1000mal iteriert und gehasht wird, ist das ganze schon alleine deswegen ein bisschen ein Krampf, weil du den Serv-U-Hash so transformieren muesstest, dass nach 999maligem Anwenden des Apache-Algorithmus auf den "konvertierten" Hash der selbe Apache-kodierte Hash wie in der htpasswd-File rauskommt (du muesstest also den Wert des "Apache-Hashes" nach der ersten Hashing-Iteration kennen). Gut, das erhoeht die Komplexitaet des Problems dann eigentlich auch nicht mehr schlimm, aber ich wuerde dennoch die Wahl eines anderen Auth-Backends als Investition in die Zukunft in Betracht ziehen ;)

Oder Serv-U rigoros kuebeln, und mod_ftp fuer Apache holen...

Edith kann's doch nicht lassen und meint: Ich glaub, es waer fast einfacher, das Serv-U-Hasformat in der apr-Library zu unterstuetzen. Hast du da zuverlaessige Informationen/"Forschunsergebnisse", wie die Hases generiert werden? Vielleicht hab ich ja demnaechst mal an einem Abend etwas Zeit dafuer.

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
Sowas hab ich mir auch schon gedacht (Serv-U Hash durch Apache unterstützen). Problem dabei ist nur, daß ich dazu nicht die nötigen Fähigkeiten besitze.

Der Serv-U Hash ist wie gesagt ein einfacher MD5 mit 16-Bit Salt.

Salt ist ein Prefix, also wird der MD5 immer von <salt><pwd> generiert. Wenn der Salt also wie oben "qi" ist, und das PWD "testuser", wird der MD5 über "qitestuser" generiert. Der Salt ist Random, kann aber als Klartext ausgelesen werden.

Wie der MD5 Algorithmus genauer arbeitet, weiß ich nicht, da habe ich zu wenig Ahnung aus Kryptografie, und Serv-U ist closed Source. Es scheint aber ein ziemlicher "standard" MD5 zu sein, da "mdcrack" den Serv-U Hash ja auch knacken kann.

Beim Apache kann ich mich eigentlich auch nur wiederholen, alles was ich weiß, habe ich gepostet.. 6-Bit Codierung mittels oben im Code-Teil gezeigten Alphabets, und der Algo soll eben in apr_md5.c stehen, nur ist mir der Source bei weitem zu hoch...

Aufgabe des Serv-U ist leider nicht möglich, Aufgabe des Apachen auch nicht. In beiden Servern steckt schon zuviel Arbeit drin, und sie sind ansonsten auch perfekt geeignet für das, was sie tun sollen mit den Features, die sie besitzen...

Danke für jede Hilfestellung!

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4259
du könntest auch ein für das betroffene dir ein php-file prependen, das die auth übernimmt. mit php kannst du (bei richtiger konfig) auf das pw-file vom ftp zugriefen und das eingegebene pw nach dem algorithmus vom ftp hashen und vergleichen.

imho die einfachste variante.

COLOSSUS

Administrator
Frickler
Avatar
Registered: Dec 2000
Location: ~
Posts: 11903
Wo kriegt man denn dieses mdcrack (nachdem das den Serv-U hash cracken kann sollte man darin ja auch sehen koennen, wie der Hash generiert wird) im Source? Ich kann die Komplexitaet der apr-Modifikation noch nicht genau abschaetzen, aber wuerde es dir was bringen, wenn ich fuer genau diese Apache-Version, die du verwendest, Support fuer den Hash aus Serv-U implementiere? (Wenn das ganze I/O-Zeug entsprechend gut wegabstrahiert ist, sollte das kein unbewaeltigbares Problem sein.) Garantie, dass das mit kommenden Releases von Apache dann auch noch kompatibel ist, gaeb's halt keine... und man muesste sich einen verbindlichen Prefix ausmachen, der einen Serv-U Hash kennzeichnet (ums von Plaintext unterscheidbar zu machen).

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
@COLOSSUS: [mdcrack 1.2 C Source Tarball]

Sicher, daß du dir so eine Arbeit antun willst? Ich kanns zwar noch weniger abschätzen, aber es klingt schon nach einigem Aufwand. Wenn das nur bei meiner jetzigen Version (2.2.4 Win32) funktioniert, wäre das schon großartig, ich update sowieso nicht grade häufig.

Als Präfix würde ich (da der Hash ja nicht rein Serv-U spezifisch ist) sowas wie "simplemd5" oder als htpasswd-Anlehnung mit den $-Delimitern "$simplemd5$" vorschlagen, aber im Prinzip bleibt das ganz dir überlassen, wenn du das wirklich angehen willst. :)

Das mit PHP ist auch keine so blöde Idee, auch wenn's mir lieber wär, das Auth direkt im Apachen zu haben. Das wäre aber eine Alternative, wenn die Implementation in den Webserver selbst zu schwierig sein sollte.

Danke!

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4259
oder du nutzt die ODBC anbindung vom ftp. fürn indianer gibts ja auch ein auth_db. ich hoffe doch, daß da auch odbc unterstützt wird.

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
Wobei sich da wieder die Frage stellt, ob sich die User mit ihren PWDs so einfach vom Serv-U INI-File in eine Datenbank schupfen lassen... Hab mir das noch nicht angesehen.

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4259
wenn du die pw mit mdcrack knacken kannst, dann wäre das eine einmalige sache.

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
Ich knacke grad ein relativ langes mit 16 Stellen und mit Einverständnis des Benutzers. Also 18 Stellen mit Salt... Scheint ewig zu dauern bei der Länge. Challenge-Alphabet ist A-Z, a-z und 0-9.

Ich will nur nicht PWDs von Usern knacken, die nichts davon wissen.. Und hausieren will ich halt auch ned. ;)

Snoop

Here to stay
Registered: Jun 2002
Location: Gablitz
Posts: 1075
also jetzt mal ganz ehrlich, warum so ein aufwand für "mickrige" 30 user ?
Aber oke...

Naja ich würd das problem vielleicht von einer anderen Seite her angehen:

Du weißt, dass sich die md5hashes unterscheiden, aber bei beiden system werden kalrerweise immer die selben herauskommen. Die frage die sich mir jetzt stellt ist: wer erstellt die user am FTP ? ein Script oder ein program ? oder du/admin ?

Möglichkeit:
du machst den auth nicht über .htpassword sondern über php mit $_SERVER["HTTP_AUTH_USER"] und $_SERVER["HTTP_AUTH_PW"] wenn sich jetzt ein user einloggen will hast du in einem file sowohl den hash vom apache als auch den hash vom servu in einem file oder ner db stehen und nimmst dann das was du gerade brauchst ?

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
Ähm, ehrlich gesagt, ich verstehe nicht, was du mir da vorschlägst? Ich bin mir zwar nicht sicher, aber irgendwie scheint mir, daß du voraussetzt, daß sowohl die Serv-U MD5 Hashes, als auch die htpasswd Hashes bereits vorliegen, was nicht der Fall ist!

Der oben von kleinerChemiker vorgeschlagene Fall, mit PHP einfach gegen das Passwortfile von Serv-U zu authentifizieren leuchtet mir noch ein, aber ich verstehe deinen Vorschlag leider nicht ganz..

Zitat
wenn sich jetzt ein user einloggen will hast du in einem file sowohl den hash vom apache als auch den hash vom servu in einem file oder ner db stehen und nimmst dann das was du gerade brauchst?

Ich habe wie gesagt die Apache/htpasswd Hashes ja noch gar nicht!!

Also mir erscheinen momentan drei Wege möglich:
  1. Der Serv-U MD5 Hash läßt sich zu einem htpasswd Hash (1000-fach iteriertes MD5 mit 32-Bit Random Salt, codiert in custom 6-Bit Zeichensatz) transformieren. Scheint nur schwer möglich.
  2. Apache wird der "einfache" MD5 Hash Algorithmus mit 16-Bit Salt beigebracht. Die Serv-U Hashes inklusive Salts werden für Apache wiederverwendet (die Lösung, die COLOSSUS vorgeschlagen hat).
  3. Apache authentifiziert seine User nicht mittels seinem eigenen Auth-System, sondern mittels PHP. Dabei wird der einfache MD5 Hash-Algorithmus mit 16-Bit Salt in PHP implementiert. Authentifiziert wird direkt gegen das INI-File von Serv-U, welches die "einfachen" Hashes beinhaltet (die Lösung, die kleinerChemiker anfangs vorgeschlagen hat).
Die letzten beiden Lösungen setzen voraus, daß der komplexere, mehrfach iterierte Hash von htpasswd außen vor gelassen wird.

So habe ich die bisherigen Vorschläge verstanden. Wenn ich da was in den falschen Hals bekommen habe, bitte ich, mich zu korrigieren. ;)

Snoops Vorschlag verstehe ich leider nicht so recht. :confused:

thxle
Bearbeitet von GrandAdmiralThrawn am 22.04.2008, 23:32

Snoop

Here to stay
Registered: Jun 2002
Location: Gablitz
Posts: 1075
naja ganz ehrlich verstehe ich auch nicht so 100% was du willst, daher hab ich mal eine annahme getroffen dass du folgende Herausforderung hast (es gibt keine Probleme!!! :) :D )

Du hast einen ServU FTp und einen Apache. ServU hat eine eigene Technik um user PWs abzuspeichern. Du willst aber dass man über das Web seine Statistiken zum User anzeigen kann, daher willst du dass wenn er sich einloggt, die Informationen zum Login von ServU genommen werden. Das problem is, dass egal wie du das PW via apache oder via PHP md5 hashst es kommt nicht das selbe raus wie bei ServU somit ist ein vergleich mit herkömmlichen methoden nicht möglich?

Ich hoffe ich hab die Problematik richtig verstanden ;).

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3682
Fast. Mit PHP läßt sich der Hash von Serv-U ganz sicher nachbilden (Da gibts doch eine md5() Funktion, die habe ich schon Mal benutzt, um das Passwort eines eAccelerator Interfaces besser zu sichern). Wenn man im Web MD5 Hashgeneratoren benutzt - da gibts ja ein paar - kann man den Hash von Serv-U auch nachbilden, wenn man nicht auf den Salt vergißt.

Ich habs aber jetzt mit PHP nicht versucht, weil ich damit schon ewig nichts mehr gemacht habe, und eben nicht wirklich ein Entwickler bin. Und halt, weil mir die Lösung über das Apache-eigene Auth System viel lieber wäre.

Snoop

Here to stay
Registered: Jun 2002
Location: Gablitz
Posts: 1075
naja dann probier halt mal

<?

echo md5("blablabaOHNEsalt");
?>

dann siehst eh mal obs ähnlich is oder nicht... :)
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz