Archive for the ‘Hackvent 2015’ Category

HACKvent 2015: Day 15

15 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 15 December 2015



Straight away this looks like a logic solver problem. I intend to use Z3 theorem solver (link) as I am most familiar with it out of all the available solvers out there.

First step is to understand the problem. Each letter corresponds to a single digit 0-9. The q  digit cannot be 0. Each digit is represented by exactly 2 letters. In the grid of equations, a series of letters like bytwycju means 8 digits. Ie if b  was 2 and y  was 8, it would be a number starting with 28XXXXXX. The operations used in the equations are   & ^ | + - ==. C-like operator precedence is also used but this will match up nicely with python operator precedence.

Looking at the secret message, is it 38 pairs of letters. If each letter is a single digit then each pair must correspond to a ASCII  capital letters/numbers/spaces…etc. So I am going to assume the secret message is a 38 character length string.

Every letter from the alphabet is present in the challenge description and equations except for: aekmpr
This works out nicely as excluding those 6 letters leaves 20 letters total which leaves exactly 2 letters per digit, perfect!

So I start writing a new python script and add in all the rules I need. I use a BitVec of 32 bits because some operations become large. I could use a BitVec of 4 bits but then certain bitwise operations would overflow which is not what I want.

For each equation I need to generate a list of long constraints to add to the Z3 solver object. To do this I use a short python script written by OS-Freeze from Germany (thanks!) which was slightly modified by myself:

The above script would produce:

I simply change the equation for each equation in the challenge description until I have all of the constraints I need.

Now I can construct my actual solver script:

This is really a simple script. I use a dictionary called ZV to keep track of all my letters. I add in every letter as 32 bit BitVec’s. Next I add the constraint that ensures each letter is in [0,9]. I add the q != 0 contraint which eliminates the trivial all zero solution. Finally I add all the rules I generated above and run the script!

The following solution is found after 20 seconds or so:

I write a short script to decode the original message using the above solution (or key).
I end up with:

I run the script and the following message is printed:


I enter this into the ball-0-matic, get the daily QR code and the daily flag!


Day 15 Solution Ball

Flag:  HV15-U3bA-BKhc-gNqN-Hit6-C1fK

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 14

14 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 14 December 2015


The following Windows binary was also provided: Download EXE File



I download the binary and run it and am presented with the following program:

Hackvent Day 14 Program

It turns out that this program will tell you (via a messagebox) if you enter in the correct daily nugget or not!
So all we have to do is check the binary to see what causes the successful message box to appear.

Note: You can do this challenge using IDA or a .NET disassembler like ILSpy (link).

If using IDA, its useful to be familiar with CIL instructions.

ILSpy Approach
I decided to use ILSpy as it is apparently a very good .NET disassembler. I open the program and load the binary and it disassembles it into various classes as you would expect.
We are mainly interested in the hv15 class. By searching for strings like yes, that is the key! we realise the only important functions we need to look at are Button1_Click and  Encrypt .

This is the code for both:





It becomes super simple to solve this challenge at this stage. The input parameter is just the text we enter into the textbox and the pass parameter is  Form1.GlobalVariables.assembly which is defined to be the string  __ERROR_HANDLER. All we have to do is reverse the encryption starting with an input that equals  zV5/UFU8PUD3N2T49IBuCwvGzCLYz39tkMZts7rfBU4=. We first decode the base64 string into a byte array and then run the program again but with  rijndaelManaged.CreateEncryptor() changed to rijndaelManaged.CreateDecryptor().

I wrote a small C# program that accomplishes what we want to do:

We run the above program and get our flag!

Flag:  HV15-uQEJ-4HPX-Qcau-Xvt7-NAlP

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 13

13 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 13 December 2015


The following image was also provided:

Day 13 Ball


First I suspect the common least significant bit steganography technique has been used here where the least two or one significant bit(s) of the image have been changes so other images can be hidden without affecting the appearance of the first image by much.

I load up Matlab as it is fairly good for image processing and write a little script to gather the least significant bit of each RGB channel for every pixel (this is based off a script I wrote for HV14).

I end up with this code:

Now, I added the RGB channels least significant bits together and observe the image that is produced.

I get:
Secret image R+G+B

I can read the text on the image but its clear that each RGB channel contains something different. I run the script three more times and change  res(i,j) = R + G + B  to  res(i,j) = R then res(i,j) = G  and finally  res(i,j) = B

After this I get three clear images:

Red Channel

Red Channel Image

This is a message telling us that we should look elsewhere. Nothing special but a sweet Mario reference!


Blue Channel

Blue Channel Image

This one is interesting, its telling us to look at XKCD comic number #26 which is available here.


XKCD 26 Fourier

Seems interesting and important.


Green Channel

Green Channel Image

This image also seems important. I try to convert all the bits within to ASCII but no luck. I scan the image for QR codes and barcodes and do fine some UPC_E barcodes but they just happened to be created by coincidence.


Putting it all together

Finally, I think about the XKCD comic and discover (through research) that you can hide images within images using a Fourier transform. I try to do this within Photoshop but my plugin was not compatible or perhaps it was corrupt. Gimp should have a FFT filter but I did not have access to linux at the time. So I found an online tool that performs Fourier transformations to images (link).

I use the online tool on the original Christmas ball image (because the excess amounts of green blobs in the center of the image make it the primary candidate) and get this result:

Fourier Secret Image

A secret message is found which says:  f0uRier-ru1ez

We put this in the ball-o-matic and get it gives us the ball which we scan to get our flag!

Day 13 Solution Ball

Flag:  HV15-1W0A-gTOY-bOpM-mexV-LoAz

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 12

12 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 12 December 2015


The following C code is also provided:



Clearly the issue here is that this program is very inefficient.
So what does the program do? First it sets the unsigned 64 bit integer variables  val and i  to 0. Then 0xC0DE42 iterations occur and the val is recomputed each calculation. The previous val  and i  values are used to recompute the new val  value.

After all this, it appears as if the nugget we need is printed out! The 4 missing blocks in the nugget are based on 4 groups of 16 bits which come from the final val value.
So we begin to optimize the code!


foo and bar

We start with the foo and bar  functions which are very similar to each other.
It turns out that they simplify to:

So we have just optimised these two functions slightly. The next step is go through the code and replace all calls to foo  and bar  with simply increments or decrements. I’m not going to show the changes I made to each call as that would make this post too long but you get the idea.

Optimized functions:



baz  should look like this at this stage:

It is clear from the code that baz  can be optimised. First the variable r  is set to zero and then a 1 is added to r , a times. Then 1 is added to rb times.
This is simply the same as adding a  to b  and storing the result in r .

Optimized function:



Spam should look like this at this stage:

This function is simply setting r  to a and then taking away 1 from rb times before returning the result in r .
This is the same as returning a - b .

Optimized function:



eggs  should look like this at this stage:

Well all that is happening here is r  is increasing by b, a times. That means we are adding a number of b’s to r .
This is the same as returning a * b .

Optimized function:



merry  should look like this at this stage:

So at this stage, we are taking away b  from a  while a  is still bigger than b . The value of  i is then returned which is the number of times we took away b  from a .
This is clearly a simple division operation: a / b

Optimized function:



xmas  should look like this at this stage:

This one is a little more tough. a  is divided by b  then multiplied by b  and this result is subtracted from a . You may be tempted to think that this returns 0 all the time but it does not.
This is because the division operation that occurs is integer division and multiplying that result by b  may not result in the original a  being restored.
A small example: 10/3 = 3.33 but is stored as 3 in an integer. However, 3*3 = 9 and not 10!

In this case, a modulo operation is happening: a % b

Optimized function:



hackvent should look like this at this stage:

This is a fun one. Notice how r is set to 1 initially, that is important. r is then multiplied by ba number of times.
This is the same as calculating b to the power of a.
However, we cannot just use the pow function defined in <math.h>.
We are dealing with uint64_t data types and must thus get a power function that can handle these larger numbers.
I decide to find one online and use it.

Optimized function ( ipow  and hackvent):


Putting it all together

At this stage you can do two things.
You can either run your program as is to find the answer or you can inline your function or convert the function calls in main so you save making all those function frames.
In this case it doesn’t really matter but this is what the calculation of val in main should look like with no function calls:

Then you run your program and within a few seconds you get the flag!

Flag:  HV15-mHPC-067e-751e-f50e-17e3

Note: You can download my final solution C file here:
Download hv15-d12-solution.c

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 11

11 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 11 December 2015


The following image is provided:

HV15 Day 11 Punch Card


I had to spend some time researching the above image but I soon discover that it is a punch card.
It turns out to be a IBM 96 Column Punchcard. Unfortunately there isn’t much information online on how to decode them.

A reverse image search comes up with the following image:
IBM 96 Punchcard

This is what the challenge organiser used to make the above challenge!
The first thing I do is open the image in Photoshop and apply a black background so I can see the data (black dots) more easily.

I get:
HV15 Punchcard Black Dots

Another important piece of information was this image I found online:
Zorch its a system 3

I used the above image to determine how I decoded the data. The above image encodes the data ZORCH IT’S A SYSTEM 3.

You have to look at each column in the punch card and generate a number.
For example, in the first column above we have _A__81 or in binary 011001.
This corresponds to the letter (more on this later).

Thus each block can have a total of 32 bit characters. The total card can therefore contain a total of 96 (32*3) characters.

Now, going back to our message, I first write out all the bits in one big block, I get:

At this stage all I need to figure out is the language, I don’t find much on this online but I eventually come up with a 64 length partially working language (it begins with a space):

So in the example I discussed, 011001 is Z because 011001 is 25 in decimal and Z is at index 25 in the string array above.

Note: This language was created using trial and error and so I didn’t determine many characters initially (which I have just left as a ? ). Later on I discovered an image (link) which allowed me to determine every character! (some special characters were still left as a ? )

At this stage I can write a nice short python script to read the data and convert it to the language.

I put the bit data into a file called input.txt and run my script.
The following message is printed out:

Great! The clue is quite simple, we simply need to alternate the case of each of the 6 blocks in the nugget (as separated with | ). We know the nugget begins with the uppercase  HV15 so we know the pattern straight away.

Flag:  HV15-m3hn-BG5H-lufe-8WPM-kzfk

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 10

10 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 10 December 2015


The following zip file was also provided: Download ZIP File


We notice that the zip file contains one zip file called, that contains one zip file called and so on. I also know that the file zile will keep getting lower and lower in file size the more we extract (due to ZIP headers and padding). Furthermore, opening the file in HxD (the hex editor) allows us to see the names of all embedded zip files. We see the number among many others so we know there are a lot of files here!

We write a quick python script to recursively extract each zip file.

Finally we reach the zip file: which is different from all of the other files.
This zip file contains one file called worst.500 and is password protected.

We use the glorious Accent Zip Password Recovery to crack the password in milliseconds.

The password for the zip file is: love

We extract the file, look inside and find the flag!

Flag:  HV15-iQYf-adNg-o4S9-JHc7-vfWu

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 1

09 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 09 December 2015



I decode the string above using a Vigenere Cipher solver with the key ‘geek‘ (deduced from frequency analysis).

The message I get is:

The message is pretty clear. First spot I check as a webmaster is /robots.txt (psss go check my websites robots.txt :p). I find 1 disallowed resource which is: /MeMyselfAndI-surfingInTheSky/hacker.jpg

I visit this webpage in my browser and find the picture Santa was hiding, here it is:
Santas Hidden Picture

Following Santa’s clues, I use Google reverse image search to find other images like this on the web.
I find one website with a similar image, namely at:

This is what the webpage looks like:
Hacking-Lab Club Webpage

Drat! We are too late, luckily cache is a thing.
You can either check WayBackMachine or Google cache to find a previous state for the webpage.
We inspect the source of the website in Google cache and discover a reference to: /work.jpg
Unfortunately that image is not on the live website but work.png was! (Finding this was just guesswork based on the format of the ‘too late’ Christmas ball).

This is what work.png looks like:

Day 1 Solution QR Code

We scan it to get our flag:  HV15-Tz9K-4JIJ-EowK-oXP1-NUYL

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 9

09 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 09 December 2015


The following sound file was also provided: Download MP3


This was a very simple challenge.
First we listen to the transmission and discover it spells out the nugget but some characters are turned into noise.

We get:

The ?  character represents a character in the set [A-Za-z0-9] (because those are the only characters that can appear in the nugget).
We notice that dashes are omitted. We also know the nugget starts with HV15 so the first unknown character is determined to be 1.

Now, we bruteforce the remaining 3 characters using our hint. We want to first find a full lowercase solution that has a sha1sum which equals B39ECFBC2C64ADBB7C7A9292EEE31794D28FE224 .
After a solution is found for that, we can then try to find the sha1sum of all permutations of the case of each character after HV15 (we know HV15 must be uppercase).

So we construct our template to be:

Then we write a python script to carry out the Bruteforce attack:

We run this and get our flag in 1 second:

Flag:  HV15-GnUj-1YQ7-vdYC-2wlr-E6xj

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 8

08 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 08 December 2015


Link to website (may be down):


I inspect the source of the website and take a look at the background image but that seems to be fine. There is nothing else of interest on the website so I figure this may require a brute-force attack.

I then however find a cookie that is generated once I fail to authenticate with the website. I try to login using the username admin and the password pass. The following cookie is generated for me:

I then replace %3D with =  and decode the above as base64.

Thus it is obvious that the cookie is simply calculated like so:

I then try to tinker with the cookie fields. I figure that the challenge would not be making any database calls and thus the password would be hardcoded. In this case, the PHP code in the authentication script would look like so:

The above uses strict comparison. However, the PHP script may use loose comparison which opens up a vulnerability. This turns out to be the case and the script does something like this:

In the above examples SOMETHING can be anything we want it to be. It does not have to just be a string. We could modify our JSON payload to pass a value like true  as the username and password. This is what we will do as a loose comparison with true is almost always true (unless the true username or password is “0” which is unlikely).

We construct our payload:

Then we encrypt this using base64 (converting all =  symbols back to %3D ):

Finally, we use a scripting language or a web browser extension (I used EditThisCookie for Chrome) to load the cookie for the webpage. Then we refresh the page and are greeted with the following message:

The goodie is our flag!

Flag:  HV15-0Ch0-91zo-m99Y-kxGI-8iQ5

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 6

08 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 08 December 2015


We are given the following string:


We can deduce by the amount of padding that this is Base32 encoded string. We use an online decoder and get:

Then we try various other things to decode the above string. I will admit I failed to find a proper solution until I received some help from SlEePlEs5 on the hacking-lab IRC. Then I was able to realise that I had to decode the above string using ASCII85. I get:

Great! This looks a lot like our nugget. I guess a simple Caesar cipher is required here and find the offset number to be 13 (as we want U->H for first character in our nugget). We apply the cipher (basically ROT13) and get our flag!

Flag:  HV15-t9P8-QaIV-J0Ar-83F3-M8Dc

No Comments

Posted in Hackvent 2015