PHP De-Obfuscation

Server Security

In den letzten Tagen hatte ich viel mit obfusciertem PHP-Quellcode (Frameworks & Schadcode) zu tun, der zumeist über einen langen String definiert war und dann mittels einfacher eval()-Funktion erst zur Laufzeit das ein oder andere dunkle Geheimnis preisgab.

Das erste Hindernis besteht darin diesen String in lesbaren Quellcode zu formatieren. Nach kurzer Recherche im Web und ein paar Experimenten hatte ich folgendes kleine PHP-Script:

ob_start();
eval(""?"" . "">"" . base64_decode( $code) . ""<"" . ""?php"");
$output = ob_get_contents();
ob_end_clean();
echo $output;

1. Die Funktion ob_start() aktiviert die Pufferung von Ausgaben ein. Während die Ausgabe-Pufferung aktiv ist, erfolgt keine Ausgabe an den Client. Stattdessen werden alle Ausgaben in einem internen Puffer gespeichert.

2. Die Funktion eval() wertet einen String als PHP-Code aus. Sie ist nützlich, wenn man bspw. PHP-Code aus einer Datenbank lädt.  Für dieses Experiment jedoch wäre sie ungeeignet, da der PHP-Quellcode direkt ausgeführt würde.  Wenn der String mit „?>“ (PHP endet) beginnt, wird der Code nicht ausgeführt und man hat eine saubere Ausgabe. Die Funktion base64_decode() war nötig, da der Code base64-kodiert war.

3. Mit der Funktion ob_get_contents() wird der Inhalt des internen Puffers in eine String-Variable kopiert. Die String-Variable enthält sämtliche Ausgaben seit dem Befehl ob_start().

4. Die Funktion ob_end_clean() löscht daraufhin den internen Ausgabepuffer und beendet das Outputbuffering.

5. Der Quellcode steht u.U immer noch in einer Zeile ist jedoch lesbar. Er kann nun angesehen und mit einer leistungsstarken IDE formatiert werden.

Im Quellcode der gegebenen PHP-Datei sind die Texte ASCII-codiert und die Strings deshalb nicht lesbar. Alle Zeichen wurden mit dem entsprechenden ASCII-Code abgebildet (z.B.: „\x73“). Das berechnen des Quellcodes mit eval() hilft hier nur soweit man während der Laufzeit noch auf diese Strings lesbar zugreifen kann. Möchte man jedoch schon den Quellcode lesen können, hilft die Funktion str_replace() weiter:

$output = str_replace(""\\x73"", ""s"", $input);

Der doppelte Backslash „“\\““ ist nötig um den Backslash selber zu escapen.

Um das an dieser Stelle zu beschleunigen:

$ascii_hex = array(
""\\x20"", ""\\x21"", ""\\x22"", ""\\x23"", ""\\x24"", ""\\x25"", ""\\x26"", ""\\x27"", ""\\x28"", 
""\\x29"", ""\\x2a"", ""\\x2b"", ""\\x2c"", ""\\x2d"", ""\\x2e"", ""\\x2f"",  ""\\x30"", ""\\x31"", 
""\\x32"", ""\\x33"", ""\\x34"", ""\\x35"", ""\\x36"", ""\\x37"", ""\\x38"", ""\\x39"", ""\\x3a"", 
""\\x3b"", ""\\x3c"", ""\\x3d"", ""\\x3e"", ""\\x3f"",  ""\\x40"", ""\\x41"", ""\\x42"", ""\\x43"", 
""\\x44"", ""\\x45"", ""\\x46"", ""\\x47"", ""\\x48"", ""\\x49"", ""\\x4a"", ""\\x4b"", ""\\x4c"", 
""\\x4d"", ""\\x4e"", ""\\x4f"",  ""\\x50"", ""\\x51"", ""\\x52"", ""\\x53"", ""\\x54"", ""\\x55"", 
""\\x56"", ""\\x57"", ""\\x58"", ""\\x59"", ""\\x5a"", ""\\x5b"", ""\\x5c"", ""\\x5d"", ""\\x5e"", 
""\\x5f"",  ""\\x60"", ""\\x61"", ""\\x62"", ""\\x63"", ""\\x64"", ""\\x65"", ""\\x66"", ""\\x67"",
 ""\\x68"", ""\\x69"", ""\\x6a"", ""\\x6b"", ""\\x6c"", ""\\x6d"", ""\\x6e"", ""\\x6f"",  ""\\x70"", 
""\\x71"", ""\\x72"", ""\\x73"", ""\\x74"", ""\\x75"", ""\\x76"", ""\\x77"", ""\\x78"", ""\\x79"", 
""\\x7a"", ""\\x7b"", ""\\x7c"", ""\\x7d"", ""\\x7e"", ""\\x7f""
);

$ascii_char = array(
"" "", ""!"", '""', ""#"", ""$"", ""%"", ""&"", ""'"", ""("", "")"", ""*"", ""+"", "","", ""-"", ""."", ""/"",  
""0"", ""1"", ""2"", ""3"", ""4"", ""5"", ""6"", ""7"", ""8"", ""9"", "":"", "";"", ""<"", ""="", "">"", ""?"",  
""@"", ""A"", ""B"", ""C"", ""D"", ""E"", ""F"", ""G"", ""H"", ""I"", ""J"", ""K"", ""L"", ""M"", ""N"", ""O"",  ""P"", 
""Q"", ""R"", ""S"", ""T"", ""U"", ""V"", ""W"", ""X"", ""Y"", ""Z"", ""["", ""\\"", ""]"", ""^"", ""_"",  ""`"", ""a"", 
""b"", ""c"", ""d"", ""e"", ""f"", ""g"", ""h"", ""i"", ""j"", ""k"", ""l"", ""m"", ""n"", ""o"",  ""p"", ""q"", ""r"", 
""s"", ""t"", ""u"", ""v"", ""w"", ""x"", ""y"", ""z"", ""{"", ""|"", ""}"", ""~""
);
$output = str_replace($ascii_hex, $ascii_char, $input);

So hat man schnell den lesbaren Text /PHP-Quellcode.

Sicherlich ist das nicht die eleganteste Lösung und ich lasse mich gerne von schöneren überzeugen!

Ein weiterer Teil der Strings ist wieder base64-kodiert, wie bspw.:

$output = base64_decode(""aHR0cDovL3d3dy5kaXJlY3Qtd2Vic29sdXRpb25zLmRlL2Jsb2cvd2ViZGVzaWduL3BocC1kZS1vYmZ1c2NhdGlvbi10ZWlsLTMuaHRtbA=="");

Um dieses Problem zu lösen, hilft die PHP-Funktion preg_replace_callback():

function decode($erg) {
    return '""' . base64_decode($erg[1]) . '""';
}
$output = preg_replace_callback(""/base64_decode\('([a-z0-9+=]*)'\)/i"", 'decode', $input);

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Weitere spannende Posts zu digitalen Themen

PHP max_input_vars in Plesk einstellen

Solltest Du dich fragen: „Wie setze ich die PHP-Variable max_input_vars unter Linux in Plesk?“, dann habe ich hier die Antwort für Dich. Wofür ist die

Wordpress Kommentare
Wordpress

WordPress Kommentare deaktivieren

Willst Du die Kommentarfunktion in WordPress deaktivieren geht das vielfach sehr einfach und ist in wenigen Schritten erledigt: Klicken Sie auf „Speichern„, um die Änderungen

Willst du dein Unternehmen digital nach vorne bringen?

Kontaktiere uns jetzt

small_c_popup.png

Bestelle für Deine Webseite das

Soforthilfe-Paket

Wir schauen uns das Problem direkt unverbindlich an und melden uns bei Dir. Wir teilen dir mit was wir benötigen und gehen an die Arbeit. Je 15 Minuten berechnen wir 30,- Euro netto, egal wie viel Uhr es ist.