PYRE 0-1¶
Python source
def save_cookie_expiration(cookiejar):
cookie_path = "./cookies.db"
try:
for cookie in cookiejar:
print cookie.path
cookie_file = open(cookie.path, "a+")
cookie_file.write("%s:%s\n%s\n%s\n" % (cookie.domain, cookie.expires, cookie.name, cookie.value))
cookie_file.close()
except Exception, e:
logger.debug("cError: %s" % str(e))
return
The vulnerability is that an arbitrary path can
be set by the cookie to overwrite an arbitrary file.
A first target would be some of the modules pyrefox imports.
Unfortunately this turned out to be a little difficult because
it is hard to get valid python code for the cookie domain.
Other options include ~/.bash_profile, ~/.bash_history, ~/.bashrc,
and .ssh/authorized_keys.
During the game we tried authorized_keys to no avail. In
hindsight cron would have been a good target.
The home directory was leaked via
user_agent = "pyrefox-0.1 [%s]" % os.environ['HOME']
But .ssh/authorized_keys also seeemd to work.
Exploit follows
header("Set-cookie: asdf=123; path=./asdf");
Note: it is a good idea to use header to avoid html encoding
done by php's set-cookie ()
#!/usr/bin/env python2.5
import sys
import os
import getopt
import logging
import random
import string
import urllib2
import urllib
import urlparse
import BeautifulSoup
import socket
import cookielib
logger = None
def save_cookie_expiration(cookiejar):
cookie_path = "./cookies.db"
try:
for cookie in cookiejar:
print cookie.path
cookie_file = open(cookie.path, "a+")
cookie_file.write("%s:%s\n%s\n%s\n" % (cookie.domain, cookie.expires, cookie.name, cookie.value))
cookie_file.close()
except Exception, e:
logger.debug("cError: %s" % str(e))
return
def usage(fname):
print "%s [-d (debug)] [-x <proxy>] [-p prompt]" % fname
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
def main(argv=None):
global logger
proxy = None
prompt = "COMMAND> "
user_agent = "pyrefox-0.1 [%s]" % os.environ['HOME']
url = None
page = None
soup = None
debug = False
loglevel = logging.INFO
if argv is None:
argv = sys.argv
try:
try:
opts, args = getopt.getopt(argv[1:], "dhx:p:")
except getopt.error, msg:
raise Usage(msg)
for o, a in opts:
if o == "-d":
debug = True
if o == "-h":
usage(os.path.basename(argv[0]))
return 1
if o == "-x":
proxy = a
if o == "-p":
prompt = a
except Usage, err:
usage(os.path.basename(argv[0]))
return 2
if debug:
loglevel = logging.DEBUG
logging.basicConfig(level=loglevel)
logger = logging.getLogger('pyrefox')
cookie_processor = urllib2.HTTPCookieProcessor()
if proxy != None:
opener = urllib2.build_opener(urllib2.ProxyHandler({'http': "http://%s/" % proxy}), cookie_processor)
else:
opener = urllib2.build_opener(cookie_processor)
# Infinite loop
url = None
page = None
soup = None
links = None
while True:
sys.stdout.write(prompt)
line = sys.stdin.readline().strip().split(' ')
if len(line) == 0:
continue
if len(line[0]) == 0:
continue
if line[0] == '#':
continue
elif line[0] == 'q':
break
elif line[0] == 'u':
try:
if len(line) == 1:
logger.error("Missing URL")
continue
url = line[1]
logger.debug("Getting URL: %s" % url)
req = urllib2.Request(url)
req.add_header("User-Agent", user_agent)
resp = opener.open(req)
page = resp.read()
soup = BeautifulSoup.BeautifulSoup(page)
links = soup.findAll('a')
save_cookie_expiration(cookie_processor.cookiejar)
print page
except Exception, err:
logger.error("aError: %s" % str(err))
url = None
page = None
soup = None
links = None
continue
elif line[0] == 'p':
try:
if len(line) != 3:
logger.error("Malformed POST request (p <url> <data>)")
continue
url = line[1]
data = line[2]
logger.debug("Posting to URL: %s with data: %s" % (url, data))
req = urllib2.Request(url)
req.add_header("User-Agent", user_agent)
resp = opener.open(req, data)
page = resp.read()
save_cookie_expiration(cookie_processor.cookiejar)
soup = BeautifulSoup.BeautifulSoup(page)
links = soup.findAll('a')
print page
except Exception, err:
logger.error("bError: %s" % str(err))
url = None
page = None
soup = None
links = None
continue
elif line[0] == 'l':
if page == None:
continue
for link in links:
href = link['href']
absurl = urlparse.urljoin(url, href)
print absurl
else:
logger.error("Unknown command: %s" % str(line[0]))
logger.debug("Terminated!")
return 0
if __name__ == "__main__":
res = 0
try:
res = main()
except KeyboardInterrupt:
logger.info('Browser is shutting down...')
res = 1
sys.exit(res)