1. MMACTF 2016 - Judgement

    Challenge description:

    Pwn Warmup
    Host :
    Port : 31729

    This was a binary pwn challenge, so I loaded it up in radare2 to take a look:

    Looks like a textbook format string vulnerability. printf has a positional arguments feature so normally you can specify which argument you want to use if you are the programmer. The following is an example use case of this:

    printf("3rd argument: %3$08x, 1st argument: %1$c\n", 'a', "unused", 0x41414141);

    This will print "3rd argument: 0x41414141, 1st argument: a"

    Format string vulnerabilities occur when a user controlled buffer is passed to printf. When printf is called it reads things off of the stack (function arguments) to print. Because the input buffer is passed straight in it allows reads off of the stack.

    Since the address of the flag was loaded on the stack before the main function it was somewhere reachable by printfs positional arguments.

    I just wrote a loop to brute force the exact offset number and spit out the flag:

    → for i in {10..50}; do echo "%$i\$s" | nc 31729; done | grep CTF
    Input flag >> TWCTF{R3:l1f3_1n_4_pwn_w0rld_fr0m_z3r0}
    Input flag >> TWCTF{R3:l1f3_1n_4_pwn_w0rld_fr0m_z3r0}
    Input flag >> TWCTF{R3:l1f3_1n_4_pwn_w0rld_fr0m_z3r0}

    I got it more than once... but I got it.


  2. CTFX 2016 - dat-boinary

    Reversing the Binary

    This challenge provided two binaries: dat-boinary and Usually this combination requires you to leak memory, calculate offsets, and call system or an exec function from libc. With that in mind I jumped right in to reversing with radare2. The functions are rather large so I will leave this as an exercise to the reader. The binary can be found here.

    The first block of main allocates a dynamic buffer of size 0x80 with malloc and gets a "meme id" of up to 9 bytes that is stored in ebp-0x20. The next block provides five menu options: update the meme id, update the meme dankness, update meme content, print meme contents, and the super secret meme option. The first 4 are pretty straight forward, while the last is not so much.

    Stack locations of interest are:

    • ebp-0xc - location of menu choice (4 bytes)
    • ebp-0x10 - Temporary storage for the dankness of the meme (4 bytes)
    • ebp-0x14 - malloced buffer for meme content - (4 byte pointer)
    • ebp-0x18 - Meme dankness if the temporary dankness is greater than 0x7f (4 bytes)
    • ebp-0x20 - meme id location (8 bytes)

    After some trial and error in gdb I noticed that the initial fgets for the id of the meme takes 9 characters instead of the provided 8. This would prove useful later.

    Setting the meme id using the menu option used the length of the preexisting id to know how much to read from the user. This will also be useful, because as long as null bytes in the meme dankness can be avoided then the pointer to the malloced buffer can be overwritten and arbitrary write can be achieved. The only issue here is that this bug can only be triggered once without somehow making strlen return more than the actual strlen of the buffer. Again, that's a task for after investigation.

    Setting the dankness involved reading in a number into ebp-0x10 (temporary dankness storage), checking if it was over 0x7f, and then moving it into the meme dankness memory location (ebp-0x18) if that check was false. This is a problem because the meme dankness is directly before the pointer that I wanted to overwrite.

    The update content option does exactly what one would expect, but with one additional check: it uses fgets to read into the buffer allocated by malloc. The number of bytes it reads is the dankness number. Before anything is read it checks if the dankness is over 0x80, because that would cause a buffer overflow.

    Print contents is also straight forward; it prints the content of the meme with a proper call to printf.

    Finally, the secret meme function is passed the meme id buffer and then calls secret_meme. The secret_meme function sets meme id + 8 to 0x69696969 and prints something...


    Check out the full post for more details!
  3. IceCTF 2016 - So Close

    Challenge description

    Yet so far :( /home/so_close on the shell.

    Jumping right in I checked the binary's security with checksec and loaded it up in radare2: No NX and a call to read over stack data... sounds like a simple stack based buffer overflow. ...

    Check out the full post for more details!
  4. IceCTF 2016 - ROPi

    Challenge description:

    Ritorno orientata programmazione nc 6500

    The binary provided with the challenge was an x86 ELF. I started by reversing it with radare2: Feel free to stop the video above to look at the functions! The main function just calls ezy, which reads 0x40 bytes on top of a buffer that is 0x28 bytes in size. This means that we are running 0x18 bytes over the buffer. The first 4 bytes after those 0x28 overwrite the saved EBP and then the next 4 overwrite EIP. To test this theory we load up the binary in gdb and put in 0x28 bytes, plus BBBB to overwrite EBP, then iiii to overwrite EIP:


    Check out the full post for more details!
  5. IceCTF 2016 - A Strong Feeling

    Challenge description:

    Do you think you could defeat this password checker for us? It's making me real pissed off! /home/a_strong_feeling/ on the shell or download it here

    I started by loading the bin into radare2 and once I realized how big the main function was I just tried running it with input.

    It looks like the sentence returned is different the more characters we get right and the same if we get the same number wrong. I had the idea to write a python script with pwntools that ran the binary over and over until a different sentence was produced:

    from pwn import *
    import string
    charset = string.ascii_letters + string.digits + "{}_#"
    context.log_level = 'error'
    flag = "I"
    b = ELF("./strong_feeling")
    p = process(b.path)
    out = p.recvall()
    while flag[-1] != '}':
        for c in charset:
            p = process(b.path)
            newout = p.recvall()
            if newout != out:
                out = newout
                flag += c
                print flag

    The results were quite satisfying:

    Flag acquired


    And yes I realize now that this could have just been solved with angr, but this was a cool way to do it too!

  6. IceCTF 2016 - Blue Monday

    Challenge Description:

    Those who came before me lived through their vocations From the past until completion, they'll turn away no more And still I find it so hard to say what I need to say But I'm quite sure that you'll tell me just how I should feel today. A file download was given for this challenge. Running file yielded the following result:

    → file blue_monday.mid
    blue_monday.mid: Standard MIDI data (format 1) using 1 track at 1/220

    Assuming it actually was MIDI, I opened it up in audacity with no luck. It was just a bunch of constant tones. This was at about 2:30AM so as a last effort before bed I just catted the file:

    → cat blue_monday.mid

    The point of interest here for me was that it looked like the beginning was spelling IceCTF{ but with extra characters in between. I loaded it up into ipython and ended up with this snippet to solve it:

    with open("blue_monday") as f:
        print(''.join([i for i in if ord(i)<127 and ord(i)>0x10 and i!='\\' and i !='d'])[7:][:-2][::2])

    Basically this just removes any character that is non-ascii, a backslash, or d, and then cuts off the first 7 characters (the header) and the last 2, and then takes every other character. They had just embedded the flag into a working MIDI file it seems. Anyway, when you run this it prints the flag: IceCTF{HAck1n9_mU5Ic_W17h_mID15_L3t5_H4vE_a_r4v3}

  7. IceCTF 2016 - Corrupt Transmission

    Challenge description:

    We intercepted this image, but it must have gotten corrupted during the transmission. Can you try and fix it?

    For this challenge a file with the extension .png was provided. A common CTF challenge is to corrupt some part of an image, so the solution is to fix it! I started with the header. According to Wikipedia the file header is supposed to start with 89 50 4E 47 0D 0A 1A 0A. Looking at the file using xxd we can see that this png does not start with those bytes:

    → xxd corrupt_orig.png | head -1
    00000000: 9050 4e47 0e1a 0a1b 0000 000d 4948 4452  .PNG........IHDR

    The first byte and bytes 5-8 are wrong. To fix, I opened the image up in hexedit and changed the bytes to their correct values. Opening the file provided a valid image:


    And of course, the flag: IceCTF{t1s_but_4_5cr4tch}

  8. IceCTF 2016 - Demo

    Challenge description:

    I found this awesome premium shell, but my demo version just ran out... can you help me crack it? /home/demo/ on the shell. The source for this challenge was provided:

    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <libgen.h>
    #include <string.h>
    void give_shell() {
        gid_t gid = getegid();
        setresgid(gid, gid, gid);
    int main(int argc, char *argv[]) {
        if(strncmp(basename(getenv("_")), "icesh", 6) == 0){
        else {
            printf("I'm sorry, your free trial has ended.\n");
        return 0;

    So to get the flag we need to make the _ shell variable equal icesh. The _ shell variable in bash is always set to the program name of the command being run. So I decided to use a different shell to see what would happen.

    ls icesh; /home/demo/demo
    cat flag.txt

    And there we have our flag: IceCTF{wH0_WoU1d_3vr_7Ru5t_4rgV}

  9. IceCTF 2016 - Thor is a hacker now

    Challenge description:

    Thor has been staring at this for hours and he can't make any sense out of it, can you help him figure out what it is?

    The text file provided is just a hexdump produced with xxd. xxd actually has a feature to reverse a hexdump back into the original file, from there I identified the resulting file's format with the file command. It was an lzip. Extracting the lzip resulted in the following image:




    Commands that were run in order:

    → xxd -r thor.txt > thor.bin
    → file thor.bin
    thor.bin: lzip compressed data, version: 1
    lzip -d thor.bin
    → file thor.bin.out
    thor.bin.out: JPEG image data, JFIF standard 1.01
    → mv thor.bin.out thor.jpg
  10. IceCTF 2016 - Vape Nation

    Challenge description:

    Go Green!

    They provide a png called vape_nation.png:

    vape nation

    With the hint I figured it must be a green filter of some sort so I loaded up Stegsolve and checked out the green plane filters. Green plane 0 resulted in the following:

    solved nation

    Looks like a flag :)