HacktivityCon CTF 2020 – Web Writeups

This year’s [email protected] was the first Capture the Flags I’ve participated in (if we don’t consider the first couple of levels on Hacker101.com) and I found it amazing. It’s been entertaining and informative, I’ve learned new information and also I’ve learned more about my current level of skills and what I need to improve.

I’ve then decided to post my experience and writeups of the CTFs. Even if I didn’t do a lot of them I thought that writing all of them on one page would have been too much and difficult to read, so I’m splitting the writeups in multiple posts.

This article is about the WEB CTFs of the HacktivityCon 2020, and at the bottom, you will find the links to the other type of challenges.

The ‘web’ challenges were about finding vulnerabilities on different types of websites and finding the flag, that was always in the format flag{example_flag}. You could find common vulnerabilities like LFI (local file inclusion) vulnerability, SQL Injection, LDAP Injection (Lightweight Directory Access Protocol), or SSTI (Server Side Template Injection).

I’ve resolved 2 of the Web challenges, ‘LadyBug’ and ‘Bite’, and made good progress with another couple of challenges but without finding the flag.

I’ll be using the URLs with the domain ‘example.com’ to give a generic explanation of the steps I did, but that wasn’t of course the domain that was being used during the HacktivityCon.

Table of Contents


The website had several pages about movies on this fictitious Ladybug character, and each page had URLs like example.com/film/park

ladybug hacktivitycon

In the beginning, I was poking around the ‘Contact us’ page because the hint on the HacktivityCon CTF page mentioned something about ‘contacting them’, so I thought that they were pointing to the bug being inside the ‘Contact LadyBug’ page. So I’ve spent a bit of time on this page, investigating the form fields, requests sent, etc.

Having quickly realized that the form page wasn’t showing anything obvious I did something that I usually do when starting to investigate a website, I’ve tried to open pages with random URLs to see if any error shows up, and in fact, a page with a glorious debugging page with an AssertionError showed up.

So something like example.com/film/2sd3ws would show the error page.

ladybug hacktivitycon solution

Luckily the debugging page gave plenty of information, and even if I never saw anything like this or worked with this technology (Flask).
But I know a bit of Python, so I’ve started to look around via the Python command line (accessible by clicking on any of the rows on this page), playing with the command dump() first, as suggested at the bottom of the debugging page. Being for the first time I saw something like this I’ve spent some time seeing what type of information I could gather from this debugger, looking at the variables and the other info that the dump() command would provide me.

I don’t remember the exact sequence of commands I’ve launched at the time as I was messing around this site, but the gist of it was that after doing ‘import os’ to import the module to interact with the OS via Python, I’ve looked around the files on the system, and there was a flag.txt file (which contained the flag).

This was pretty much the sequence I’ve followed:

import os
dir = os.listdir()
flag = open("flag.txt", "r")

ladybug hacktivitycon debugger



Bite was a simple website with pages about bit, bytes, and other types of data. There was a Search function that didn’t work. ‘Bit’ was the default page.

hacktivitycon bite page

When clicking on the pages on the sidebar (e.g. ‘Bit’) I’ve noticed that the URL was  in the format example.com/?page=bit

I’ve also figured out that the main page was index.php (which was hidden in the URL by default) and that each page was a .php file with just a paragraph inside.
When clicking on the link the index.php would setup the main layout, and at the center of the page would just load the paragraph of the .php file.

So example.com/?pages=byte would show the standard home page index.php but with the byte.php content.

hacktivitycon bite

This was proved correct from the fact that the URL example.com/?pages=index would create a recursive loop that would freeze the browser while displaying on the page a series of index pages one nested inside each other.

hacktivitycon writeup ctf bite

The other thing I’ve found out is that ?pages=xxxx worked by simply searching for a file inside the folder with the name xxxx.php and displaying it on the page.

By doing some tests it was clear that ?pages= would add the extension .php to whatever value you would give to it, and if a corresponding file was present it would display it on the page, or it would give an error.

At this point, I’ve tried loading example.com/?pages=flag which was successful, and reporting the message that the flag was inside the /flag.txt file.

hacktivitycon bite flag

From there it was just a matter of using the /file.txt followed with the Null character %00
You can pass the Null character in a URL using the encoded format %00, often referred to as a Null Byte Injection, which forces the application to stop reading the string, ignoring what comes after that point. In this case, it was forcing the web application to ignore the .php part, otherwise, it would have tried to open example.com/flag.txt.php which would have just given an error.

So via the URL example.com/?pages=/flag.txt%00 I’ve forced the website to show on screen the content of the file.txt (containing the flag), subverting its original purpose.

hacktivitycon flag solution bite

It took me some time to figure this out, especially since I didn’t try to open flag.php straight away. I was poking around the application to understand what other .php files could be inside the folder or if that nested index.php bug could be useful to resolve this challenge.

In the end, as always, the solution was simple in hindsight. A clue would have been the site itself too, being about ‘bytes’, and the solution to this challenge found via a null ‘byte’ injection (many, if not all, the challenges’ names were related to the solution).

This was an example of Local File Inclusion vulnerability (LFI), a type of vulnerability that can be used to trick a web application to run files on the webserver, and may happen when an application accepts a path as input and usually is caused by the fact that a proper sanitization of the user input has not been done.  It may lead to RFI (Remote File Inclusion) if the attacker can use this vulnerability to load a remote file.

In this CTF, the objective was to find the flag inside the flag.txt file, but this vulnerability could have been exploited to, for example, also access other important files on the webserver like the passwd file, by navigating to example.com/?page=/etc/passwd%00

hacktivitycon passwd ctf writeup



The following are the challenges I’ve started but for which I didn’t get the flag for various reasons (e.g. I didn’t find them or I run out of time). I won’t be providing screenshots as it’s just a summary of my findings during the exploration of these CTFs and not a proper writeup / walkthrough.

Waffle Land

This was a website with a list of waffles to purchase, a Sign In page, and a Search function.

The very first thing I do every time I see a search function is to use ‘ and see if there is the possibility of an SQLi (SQL Injection), which in this case was successful: I had an error message that showed the lack of sanitization of the input and the fact that the search function was using SQL.

I’ve used the command classic’ or 1=1 # and it simply gave the overall list of waffles, showing that it was possible to inject SQL successfully. From there I’ve played a bit with the command UNION and tried to pull the name of the database or the tables but couldn’t find the solution I was looking for.

The first obstacle was caused by the fact that there was a WAF (Web Application Firewall) filtering keywords like UNION or DATABASE. I could bypass the filtering of UNION using /**/ (the symbols for opening and closing a comment, which sometimes helps in bypassing WAFs:  ‘/**/union/**/select 1,2,3 — but I’ve pretty much stopped there as I’ve run out of time.
By looking at some other writeups I saw that instead of searching for tables or database names I could have gone directly for trying some common tables like ‘user’ and ‘users’ and I would have found the users table name, and from there use the above UNION query and looking for username, password to pull the admin credentials.
Then once logged in with those credentials, the flag would appear.

Lesson learned for next time!



You can find the other 2 parts of the writeups at the following links:
Part 2: HacktivityCon CTF 2020 – Steganography / Scripting Writeups
Part 3: HacktivityCon CTF 2020 – Mixed categories Writeups

Default image
Solution-focused devil's advocate with a knack for revolution. Cybersecurity is my passion, and curiosity is my superpower. Check the About Me page to know more.

Leave a Reply