HACKvent 2017 write-up

Like every year before Christmas the HACKvent is on! It is a Jeopardy CTF competition in the style of an advent calendar. Every day at 00:00 a new challenge is released. It starts with easy ones and then becomes harder and harder. If you solve a challenge before the next one is released, you’ll get full points. Oh boy, the last couple of days were stressful…

Unfortunately I lost 1 point because I wasn’t able to submit the tamagotchi challenge on time. It was even more frustrating when I’ve found out, that it didn’t work because of a copy/paste error.

Nevertheless, I am very happy with the result as I still managed to finish on the 8th place! 🙂

Day 01: 5th anniversary (Author: M.)

time to have a look back


This one was pretty straight forward. I just had to find the flags of the first days from the past 3 years. Simple Google-search was enough. Thanks “shiltemann” for the wirteups!



Day 02: Wishlist (Author: avarx)

The fifth power of two

Something happened to my wishlist, please help me.


The fifth power of two is 32. After I Base64 decoded the string for 32 times the flag was revealed:


Day 03: Strange Logcat Entry (Author: pyth0n33)

Lost in messages

I found those strange entries in my Android logcat, but I don’t know what it’s all about… I just want to read my messages!


While browsing through the logcat, the PDU log entries were very suspicious to me. PDU stands for Protocol Data Unit and is used to communicate with base-bands on mobile phones.

I used a PDU decoder to read the message:

To: +13371337133
Message: Good Job! Now take the Flag: HV17-th1s-isol-dsch-00lm-agic

Day 04: HoHoHo (Author: inik)

NOTE: New easyfied attachment available


Santa has hidden something for you here.

I got to know many new PDF tools with this challenge. 🙂 In the end I could solve it with pdfwalker. While scrolling through the content I’ve found a font called “DroidSans-HACKvent.sfd”.Object 21 was referenced from there. I opened this object and dumped the decoded stream. The dumped sfd file could be converted to a ttf file with fontforge:

When opening the created ttf with fontforge the flag is presented.


Day 05: Only one hint (Author: HaRdLoCk)

OK, 2nd hint: Its XOR not MOD

Here is your flag:


and the one and only hint:

0xFE8F9017 XOR 0x13371337

At first the challenge was released with a wrong description, the calculation was MOD instead of XOR. Unfortunately, this made me waste some time…

If you calculate the hint you’ll get 0xedb88320 which is the polynomial representation in the CRC-32 calculation. As I learned at last years HACKvent, the CRC-32 is reversible if it’s not longer than 4 bytes. I wrote a python script which calls this script and does the reverse calculation:


Day 06: Santa’s journey (Author: avarx)

Make sure Santa visits every country


Follow Santa Claus as he makes his journey around the world.


When opening the link a QR code is shown. If you decode the QR code you’ll get the name of a country. The countries are presented in random order. The goal of this challenge is to visit all countries and then probably the flag will show up. I wrote a script which reloads the URL and reads the QR codes until the result is something starting with “HV17”.


Day 07: i know … (Author: HaRdLoCk)

… what you did last xmas


We were able to steal a file from santas computer. We are sure, he prepared a gift and there are traces for it in this file.

Please help us to recover it:


When I have a challenge with an unknown file the first thing I try is always Binwalk. With Binwalk I could extract the file SANTA.IMA. And when running “strings” over it, the flag was presented.

I think there was an error in the challenge. Because the flag was there in cleartext with the chars ‘Y*’ in front. 2 lines below was the same flag but encrypted with rot13. Looks like someone wanted to remove the cleartext flag (maybe Ctrl+X?) but failed.. 🙂


Day 08: True 1337s (Author: pyth0n33)

… can read this instantly


I found this obfuscated code on a public FTP-Server. But I don’t understand what it’s doing…


To solve this I had to do a bit of python magic 🙂
– I took the first part of the file with the multiple “True”s, exchanged “exec” with print. This results in:

– Now I have the instructions for the second part
– I executed “A=chr” and the function definition
– Again, replaced “__1337=exec” with “print” and I got the next instructions:

– C=SANTA(“?”) is C=input(“?”) according to the first instructions
– “FUN” is “print”, so I got:

– Then I had a problem with non printable characters. Therefore I went one step back and didn’t print the instructions, but looked at the definition. I just removed the “print” in the beginning of the huge text.

– Assembling this together resulted in this:

– I don’t care about the input or anything, I just want the flag – therefore I just execute the print line:


Day 09: JSONion (Author: inik)



… is not really an onion. Peel it and find the flag.


The hardest part of this challenge was to figure out what to do at first. After some thinking I got that the JSON file tells you what to do in the “op” field. There are different operations: remap, gzip, b64, xor, rev and null. I had to read the JSON, interpret the operation and apply it on the data.

Very special was, that the author added a branch somewhere. If you assumed that there is always only one element in the JSON, you will end up with a fake flag! Very nice twist, inik! 🙂 This would have been the perfect place to hide a hidden flag btw!


Day 10: Just play the game (Author: pyth0n33)

Haven’t you ever been bored at school?


Santa is in trouble. He’s elves are busy playing TicTacToe. Beat them and help Sata to save christmas!

nc challenges.hackvent.hacking-lab.com 1037

My python script plays “tic tac toe” against the computer. I’ve found out that 1-9-7-4 wins almost all the time. But as we have to win all the time, I also need to identify dangerous situations where I could lose and react accordingly:


Day 11: Crypt-o-Math 2.0 (Author: HaRdLoCk)


So you bruteforced last years math lessions? This time you cant escape!

find “a” to get your flag.

Uh, I had to read up some math theory to solve this!! This Stackoverflow link was a good help: https://stackoverflow.com/questions/16044553/solving-a-modular-equation-python
I did calculate the modulo inverse and then I had to solve the equation. I documented every step in the comments of the python script:


Day 12: giftlogistics (Author: inik)

countercomplete inmeasure

Most passwords of Santa GiftLogistics were stolen. You find an example of the traffic for Santa’s account with password and everything. The Elves CSIRT Team detected this and made sure that everyone changed their password.

Unfortunately this was an incomplete countermeasure. It’s still possible to retrieve the protected user profile data where you will find the flag.

Link traffic

Another nice challenge by inik.

– First I went through the unencrypted traffic in Wireshark
– I’ve found an OpenID configuration file, which looked suspicious. But I didn’t go more into detail there.

– Going further through the traffic I’ve found a username and password, but the credentials didn’t work. As stated in the description, the CSIRT ensured everyone changed their password.
– I stayed on this path and found the OpenID login request and the access token which was returned.

– I tried to use this token to access the website. It is a bearer token type, so I generated this GET Request:

– But the page still showed the login button and I didn’t get any more information.. I tried to submit the bearer token in different ways, but none worked. The Lifetime of the token is long enough though, it should still work..
– Then the OpenID configuration I’ve found in the beginning came back to my mind. And there were some API calls, like userinfo:

– Calling this API endpoint revealed the flag


Day 13: muffin_asm (Author: muffinX)

As M. said, kind of a different architecture!


ohai \o/

How about some custom asm to obsfucate the codez?


After fiddling a bit and adding debug messages to the script I’ve found out how it works. The “_cmp” function compares the user input “chr(r[r1])” against the flag I am looking for. The only thing to do was to add a print function there and to always return true, then it printed the whole flag. To make it a bit easier to read I saved every character to a global var and printed it at once when I had the full flag.


Day 14: Happy Cryptmas (Author: HaRdLoCk)



Todays gift was encrypted with the attached program. try to unbox your xmas present.



To reverse engineer this binary is pretty easy. There is not much going on in the program and you can see that there is a call to the function “powmod” in the library “libgmp” .


This calculates “input * b % a”. I’ve spent way to much time on this and wanted to solve the equation myself (was in the math-mood after HaRdLoCks last challenges! 🙂 )… Until I’ve figured out this is the RSA implementation!!

I started to fresh up my knowledge about the theory of RSA:
Everything is pretty straight forward, only that I don’t have the private key?! And RSA is based on the principle, that you cannot factorize large numbers. Then I found this pretty little website: http://factordb.com/. Somebody already did the factorization for us:

Now I was able to calculate all the missing variables

The function to decrypt is:

The only problem here is, that python is very slow in solving this. Using the pow() function solved the problem.


Day 15: Unsafe Gallery (Author: inik)

See pictures you shouldn’t see


The List of all Users of the Unsafe Gallery was leaked (See account list).
With this list the URL to each gallery can be constructed. E.g. you find Danny’s gallery here.

Now find the flag in Thumper’s gallery.

I didn’t like this challenge, because it was depending too much on guessing. With the given example it was possible to focus on two Dannys in the CSV file. After a lot of trial & error I managed to find the right combination.

The email address field was hashed with SHA-256 and then Base64 encoded. All non alphanumeric characters were removed from the Base64 string, and the result of this was the URL.

Here is the python script to solve the challenge:


Day 16: Try to escape … (Author: pyth0n33)

… from the snake cage


Santa programmed a secure jail to give his elves access from remote. Sadly the jail is not as secure as expected.

nc challenges.hackvent.hacking-lab.com 1034

Very entertaining challenge. I assume there were many different ways to solve this challenge. I don’t think it is possible for the author to just allow one possible path in such an environment.

When connecting to the server some nice ASCII art is shown, a message and a python command prompt:

After playing around a bit with the python jail I made some discoveries:

– Everything entered gets transformed to lowercase
– There are some denied characters and functions

– There are allowed functions as well

– ‘Denied’ is a list with blacklisted functions and I could print it!

– I was able to use these functions: a=denied[0]
– I had the eval() function, which can execute code. And I had the upper() function.

Now I was able to create SANTA().

With eval() it is possible to execute SANTA().

🙁 And I thought I already solved the challenge before this point… So, I started to play with arguments for the SANTA() function.

This returned some non-printable characters. I tried to input more characters:

OK, I definitely got something, lets try out numbers instead of ‘A’s.

This already looks like our flag, but still encoded/encrypted somehow. I started to change my input, character by character and was able to construct ‘HV17’ with

Later on I’ve found an alternative method to solve this challenge. It is also possible to use the title function to construct “SANTA()”.


Day 17: Portable NotExecutable (Author: HaRdLoCk)


here is your flag.

but wait – its not running, because it uses the new Portable NotExecutable Format. this runs only on Santas PC. can you fix that?

get the flag here

This executable is not running correctly, apparently the header is broken and the challenge is to fix it. First I had to read about the PE file format. These links helped a lot:


The PEView tool is very helpful as it parses the file and shows the header information. https://www.aldeid.com/wiki/PEView

In the end it was to read up the specifications and find the errors in the header. Finally, I had to make 4 modifications to make the executable run.

– Change the e_magic number to 4D5A (Address: 0x00)
– Change the e_lfanew number from 0x20 to 0x40 (Address: 0x3C)
– Change PNE to PE00 –> 504e4500 to 50450000 (Address: 0x40)
– There are only 4 sections, so change 6 sections to 4 (Address: 0x46)

This still didn’t reveal the right flag. And for every tiny modification I did, the printed flag was a new one. Therefore, I tried to modify only what was really needed.

When running strings over the file, there was this hint:

I assumed that I have to get rid of the DOS window which opens when the executable is running. Fortunately I did exactly this for another purpose some weeks back. To do so I had to set the “image_optional_header_subsystem” at the address 09c from windows_cui to windows_gui. This means to change the value from 3 to 2.

All the modifications:

Executing the modified EXE file the right flag is printed:


Day 18: I want to play a Game (Reloaded) (Author: HaRdLoCk)



last year we played some funny games together – do you remember? ready for another round?

download the game here and play until you find the flag.

get the game

I always struggle a bit with Reverse Engineering challenges. But it’s HACKvent, here we go.

The rpcs3 Playstation 3 emulator was a real help for this challenge. The game didn’t start at first, but after looking around I noticed that if I load the hackvent.self binary the game starts and it reveals the hidden flag number 2!


I analyzed the files and found some useful information:

  1. hackvent.self is encrypted and signed. Therefore it can be run. It also can be decrypted with TrueAncestor.
  2. EBOOT.BIN is almost the same like the unencrypted hackvent.self file. There are some differences and it contains debug information. The instructions and addresses are the same!
  3. We cannot make EBOOT.BIN run, I tried to sign it with TrueAncestor, but the file is somehow broken.
  4. The hint says we should follow the flag in the unsigned binary (EBOOT.BIN), so there must be some differences between the unsigned and signed binaries.
  5. I assumed, the unsigned binary does exactly the same like the signed one, but reveals the real flag in the end.

I reverse engineered the EBOOT.BIN file with Hopper. Eventually I’ve found out, that the magic is happening in the function .drawScene.

After several attempts to use the debugger of rpcs3 I was finally able to step through the drawScene function. Of course there was not the right data, but it helped a lot to understand the function.

The data which is used lays at the addresses 0x40040, 0x4005d and 0x4007a. I tried to completely understand the function, but I am really slow in reversing! At 23:40 I decided to patch the decrypted hackvent.elf file and resign it with TrueAncestor. So I could run it with the “real” data. I replaced the data at the three addresses mentioned above with hexedit.


Then I re-signed the file and ran it again. And there it is, the right flag.

I was able to submit the correct flag at 23:59:54!!! 6 seconds later and I would not have received the full points!


Day 19: Cryptolocker Ransomware (Author: Dykcik)

Pay the price, Thumper did it already!


This flag has been taken for ransom. Transfer 10’000 Szabo to 0x1337C8b69bcb49d677D758cF541116af1F2759Ca with your HACKvent username (case sensitive) in the transaction data to get your personal decryption key. To get points for this challenge, enter the key in the form below.

Disclaimer: No need to spend r34l m0n3y!

Enter your 32-byte decryption key here. Type it as 64 hexadecimal characters without 0x at the beginning.


I had the idea to make a blockchain CTF challenge myself. I was very excited to solve this one!

According to the description I knew that it was a smart contract hosted in the Ethereum blockchain. All blockchain transactions and contracts in Ethereum can be publicly viewed. The bytecode of the contract is here:

The transaction made from Thumper can be found here:

And Thumpers key can be found in the event logs:

Reverse engineering an Ethereum contract is pretty hard. A better solution is, to run the contract in a private blockchain and trigger it by sending a transaction to it. To do so I used ethereumjs-vm. I extended the example of the simple transactions:

And then I modified the index.js:

I ran the code locally and when I browsed to the URL I received my key to solve the challenge:

Day 20: linux malware (Author: muffinX)

oh boy, this will go wrong… =D


ohai my name is muffinx…
…um yeah btw. cyberwar just started and you should just pwn everyone?

Make sure you don’t leave traces and make the lifes of your opponents harder, but fairplay!

You are a hacker? Then think like a hacker!
Attack! Defend! And trick!

Ladies and gentlemen,
We understand that you
Have come tonight
To bear witness to the sound
Of drum And Bass

We regret to announce
That this is not the case,
As instead
We come tonight to bring you
The sonic recreation of the end of the world.

Ladies and gentlemen,
To hold

Fuck it,
I lied.
It’s drum and bass.
What you gonna do?



You should keep the container inside the same host your haxxing on (same ip) or some things will not work…


Hint #1: check https://hub.docker.com/r/muffinx/hackvent17_linux_malware/ for regular updates, keep the container running (on the same ip) when you are haxxing the bot panel
Hint #2: you can also use https://hookbin.com/ to create private endpoints

WOW – This challenge was super amazing!! Thanks muffinx for this experience!

I started the docker container and connected to the container as root, otherwise not all files are readable.

I started to explore what was happening. According to the description there is some kind of malware running on the system.

Interesting files:
– /root/party.py: Generates a lot of distraction. Writes temporary files in different folders with fake/random flags.
– /root/loopz.py: Makes sure that /home/bot/bot is running.
– /root/checker.py: XOR a nonce which is fetched from http://challenges.hackvent.hacking-lab.com:8081/?nonce with a 29 byte long value in the script. I first thought this could be the flag already. But I got rick-rolled when looking for it. 🙂
– /home/bot/bot: Creates different files in /tmp. But they are deleted right after execution. I copied the files to another directory with this command:

One of the copied files was very interesting. First it looked like a manual file. But when scrolling through it, there was python code hidden in the middle of the file! The script connects to http://challenges.hackvent.hacking-lab.com:8081/?twitter, reads twitter names listed there and then decrypts the tweets of the users in the list. The decrypted tweets can contain code which will be executed afterwards.

This is a bot-net controlled over encrypted twitter commands! My now goal was to somehow inject my twitter name into the website and take over control over the bot-net.

In the main website of this challenge there is a hidden form with a password in the source code, this was the entry point to the admin panel. I found a SQL-injection-vulnerability in this field. I used sqlmap to exploit this because I was very lazy! 🙂 While looking around, I’ve found a password table which contained the password. But it was encrypted. :/ I played a bit more with sqlmap and I received this error message:

Now I had the password to decrypt the password. This could be easily done in the MySQL shell I had:

After entering the password into the hidden form, another website with a video appeared. The new page contained a new hidden form, where I could add a twitter name. This script executes both commands.

After adding myself to the twitter list, I had control over the botnet. Basically everyone solving the challenge was a part in the botnet! The feeling to control all these little minions was amazing! 🙂 Next step was to understand the script which decrypts the commands from Twitter. I modified it a bit and added my own functions to encrypt/decrypt commands.

With this I was able to execute commands on all the bots and I could start looking for the flag. It was pretty hard to find the needle in the haystack, because there is this script on all hosts which generates fake flags.

So what to look for? I pinged the website of the challenge and got back the IP I checked if I can control this IP over the botnet as well – and yes I got answers from there. Now it was clear, I had to focus on this host.

I found the flag in the root directory. Fortunately there were no fake flags in the root directory and it was the only host which contained a flag in this directory. I could get the flag with this command:


Day 21: tamagotchi (Author: muffinX)

ohai fuud or gtfo



I’m a little tamagotchi who wants fuuuuud, pls don’t giveh me too much or I’ll crash…

nc challenges.hackvent.hacking-lab.com 31337

File #1: tamagotchi File #2: libc-2.26.so

Here I messed up, the only point I lost was at this challenge. I wasn’t able to successfully exploit the tamagotchi binary on the remote server in time. It was even more frustrating when I’ve found out the next morning, that it was because of a copy/paste error of the system offset! 🙁

These tutorials helped me a lot to solve this challenge:


The food function is exploitable. To find the offset that I could overwrite the RIP I used gdb-peda:

I copy/pasted the pattern into the food function:

And now I was able to calculate the offset:

Now I was able to create a PoC on my local system, which overwrites the RIP with 0x0000424242424242.

Following the tutorials I created a local exploit, which used a ROP chain and executed /bin/sh from system(). The ROP I have found with Ropper. The system and /bin/sh addresses can be found with gdb.

Don’t forget to disable ASLR when running the local PoC.

This was pretty easy so far, as I disabled ASLR on my machine. But on the remote server ASLR is enabled. This means I had to find a leak to calculate the libc_base address. I followed tutorial #3 to achieve this step. As the libc.so which is used on the server was provided, I could find all needed offsets from there. I passed a pointer to the puts() function and printed this address. Now I had the remote address of this function and because I knew the offset of the puts() function, I could calculate the libc_base address of the remote system. I used pwntools because it makes exploitation much easier.

I documented the script to make it understandable. The first part was to find the base_libc address, then the exploit calls the main() function of tamagotchi again, so I could get command execution with the obtained address. Here is a copy of the execution flow:


Day 22: frozen flag (Author: HaRdLoCk)



todays flag is frozen. its quite cold in santas house at the north pole.

can you help him to unfreeze it?

get the frozen flag here

Running the PEiD Krypto Analyzer showed that the ICE Cipher is used.

This link has a lot of useful information and different implementations on the ICE Cipher: http://www.darkside.com.au/ice/

I compared the C implementation with the disassembled code in Hopper and could find various similarities. sub_401811 looks like the encrypt function:

The encrypt function is called in sub_401ce9:

Solution 1 – Binary patching

I compared the disassembled file and the C implementation further and found that the decrypt function is also embedded in frozen.exe, although it is not used.

So, instead of calling the encrypt function at sub_401811 from the sub_401ce9, I just patches the binary to call the decrypt function sub_401937. This modification is done at the address 0x401e67.


Solution 2 – Modify Java implementation

Before the encrypt function is called, the string “ice-cold” is compiled. This looks like the key which is used to encrypt the file. I tried to use the given C & Java implementations with this key, but it didn’t work at first. But investigating further and implementing my own main-function in the Java IceKey.java file reconstructed the flag.

Run it:


Day 23: only perl can parse Perl (Author: M.)

… but there is always one more way to approach things!


(in doubt, use perl5.10+ on *nix)

get your flag here

First I deobfuscated the perl file:

Then I worked with the perl debugger and got this:

I made it a bit more readable manually and got this file:

I found the password manually, because I am very unfamiliar with perl! 🙂 I noticed that when I change a character, the output (which I am printing at the end) changes as well. I started to try with alphanumeric input. First success was when I entered ‘p’ as the password, then the first character from the output was “72” which is the char code for “H”. Going further like that I’ve found the password “p0lyglot”:

A polyglot is a program which can be run with different interpreters/programs. And the hint talks about the old Microsoft shell. This must be DOS. But to be able to run the program I had to rename the file extension to “com”.

Additionally to the perl password we need a dos code. The program didn’t return anything if the dos code was not 5 characters long. The code must be 5 characters then! I tried brute force the password with a script. But I failed to write the script, as dosbox only supports a limit set of commands and I could not run a loop. By pure luck I entered “AAAAA” as code, and the program returned something which looked very similar to a flag!

Again manually playing with the dos code password I ended up with the right one: “S4n7A”.


Day 24: Chatterbox (Author: pyth0n33)

… likes to talk

I love to chat secure and private.

For this I mostly use http://challenges.hackvent.hacking-lab.com:1087.

It’s easy to create a private chat and start chatting without a registration.

Hint #1: the admin is a lazy clicker boy and only likes <a href=”…”></a>
Hint #2: As a passionate designer, the admin loves different fonts.
Hint #3: For step 2: I’d better be my own CA.
Hint #4: For step 2: It’s all about the state
Hint #5: For step 3: python programmers don’t need {{ ninjas }}

This challenge was super hard. There were three stages until the flag was revealed and each stage could have been a final challenge. The first solver of this challenge came only after several hints and like 48 hours. I was very frustrated at the beginning as this was on Christmas Eve and I was looking forward to finally be released of the HACKvent stress. Because nobody solved this challenge in time they changed the rules for this challenge and the first 10 solvers would get full points. In the end I could jump to the 8th place in the global ranking, because I was solver number 7 of this challenge! 🙂

Stage 1:

The website to chat contained several things which were suspicious. There was a working chat, you could create your own secret chat with a CSS stylesheet, a form to contact the administrator, an API which returned PHP errors, etc, etc. With the description of the challenge and hint #1 I assumed that I had to create my own chat and invite the admin over the feedback form to get him into my chat. I copied the original CSS file and changed the background-url to hookbin, so I could verify if somebody would click on my link:

And very well, some seconds/minutes after I sent the clickable link(<a href=”url-to-secret-chat”>clickme</a>) to the admin I registered a call from the IP address of challenges.hackvent.hacking-lab.com on my hookb.in backend.

With hint #2 I found this vulnerability: http://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html This is basically a keylogger implemented in CSS! I added all alphanumeric characters and some special characters to the CSS and then tried to hook this PoC font to the chat input field. But the admin was not typing anything. Then I had the idea to hook it to the password input field from the the password form and it worked!

This gave me the password “Christmas2017” which led to the link “http://challenges.hackvent.hacking-lab.com:1088/?key=E7g24fPcZgL5dg78” of stage 2!

Stage 2:

Again, there were many distraction points. First I assumed it to be a command injection. As there were tools like “ping” used on the website. After hint #3 (Better be my own CA) was released I knew I had to focus on the CSR tool. There you could submit a CSR and a CA certificate was generated for you.

I fuzzed the input fields of the certificate and found out that the server will return an error 500 if the state field contained a quote (‘)! I tried to reproduce it on my own computer with openssl and it worked. So, the CA must parse the CSR and do something with it. Playing with the State field inputs revealed that it was an timebased blind SQL-injection. Only problem there was, that it had to be embedded in a valid CSR! I tried to write a tamper script for sqlmap which generates a CSR. But unfortunately this didn’t work, because sqlmap generates payloads which are too long for the State field! 🙁 Solution to this was to write my own time-based blind sql injection script. It was a lot of work, but implementing it was actually fun and I’ve learned a lot!

To work faster and find the right SQL query I wrote a small script. With this I could just pass the SQL query as parameter and it would automatically generate the CSR and do the post request.

My sql query to trigger the vulnerability was:

If the request took longer than 1 second then the query was successful! I wrote a script which first dumped the database name, then the tables, after that the columns and finally the content.