Parseltounge
Forensics – 379pts
Description
Hisssss, can you ssssee ssssome sssssecretssss?
Solution
Attached file is a compiled python script, after decompiling with decompyle3 parseltounge.pyc > p.py
we get the following python code.
import Crypto.Util.number as l2b
import random
sszz = [
'aposlogahs', 'apsle', 'Sine', 'aʃe', 'bei∫ed', 'tuif', 'Kura', 'Vera', 'pard', 'pardshesl', 'bo∫', 'Gara', 'vinth', 'Pelʃis', 'keilsing', 'khair', 'tikni', 'Bana', 'Slehara', 'koukh', 'kups', 'dai', 'Andi', 'dorʃe', 'doʃe', 'sloʃe', 'kaʃe', 'Sarna', 'Suu', 'giʃe', 'Gorna', 'ass-girou', 'dros', 'feslure', 'hasli', 'riʃan', 'fraeslis', 'vris', 'gatsi', 'runʃe', 'Tira', 'hishe', 'einʃe', 'hesleuf', 'Firna', 'Baʃ', 'ʃem', 'ai', 'ine', 'dinʃe', 'Negei', 'slanp', 'ʃena', 'sliʃe', 'dati', 'slifai', 'Kuine', 'Ha', 'nisl', 'ʃe', 'Sobne', 'bna', 'Sora', 'ovith', 'houk', 'parknent', 'fasar', 'nesha', 'praughs', 'Pura', 'ʃine', 'ʃane', 'gisan', 'rai∫e', 'kata', 'Ara', 'Nigi', 'akaʃe', 'rashe', 'slan', 'Derne', 'Tina', 'snart', 'gariʃe', 'kerashe', 'stabsle', 'Fasi', 'Peina', 'Tasi', 'Sekusi', 'Harne', 'kapi', 'Athne', 'vaʃe', 'asl', 'ʃik', 'agiro', 'vei', 'Asuna', 'Teʃ', 'Fiʃ', 'Doʃ', 'ʃira', 'Haʃ', 'Vuʃ', 'vindovth', 'Bira', 'Sa', 'Slu', 'ou', 'iangsteur']
zzss = b'\x07\x1c\x0e\x14\x17\n\x06\x03\x0cJ\x00@G\x0e\x017X\x0b\x04W\xf8\xb5\x03P\x06\x0f\x80\xea\x9b\x00\x05A\x16\\\x00.\x17\x0f'
s = False
z = True
ss = s & z
z = abs(ss) - abs(z)
zz = ss | z
z = zz - z - z
zz = z | z
z = zz << zz
s = ss >> ss
sz = s << z
zs = z << s
z = zs - sz
ss = str(z).replace(str(zs), str(ss).replace(str(ss), str(z).replace(str(z), '')))
sss = bytes(ss.join(sszz), 'utf-8')
zzz = bytes([_a ^ _b for _a, _b in zip(sss, zzss)])
ssszzz = bytes([_a ^ _b for _a, _b in zip(zzz, zzss)])
sss += b'S'
ssss = []
ss = sss[:len(sss) // 2]
zz = sss[len(sss) // 2:]
for s in range(len(ss)):
ssss.append(ss[s] ^ zz[s])
else:
if 5 == 1:
print(' '.join([random.choice(sszz).upper() for _ in range(random.randrange(5, 10))]))
else:
print(' '.join([random.choice(sszz).upper() for _ in range(random.randrange(5, 10))]))
Executing this script outputs some random strings from the sszz
array like ASUNA KURA SLANP SLIFAI NEGEI HASLI APSLE. In order to understand what the code does we can print out the values of the variables after assignment. When we add print(zzz)
after zzz = bytes([_a ^ _b for _a, _b in zip(sss, zzss)])
we get the flag.
flag{eabd9a04bdd1ea626f2cfbb0ea5c5feb}
Henpeck
Forensics – 124pts
Description
So I’ll be honest, I never actually went through the Mavis Beacon program…
Solution
Here we got a pcap file containing USB packets. Using this script to decode the input we get the following output.
aaso the answer is flag{f7733e0093b7d281dd0a30fcf34a9634} hahahah lolEnterc
Typewriter
Forensics – 448pts
Description
A CONSTELLATIONS employee had his machine crash and he lost all his work. Thankfully IT managed to get a memory dump. Can you recover his work?
Solution
Using Volatility3 to examine the running processes with python3 vol.py -f image.bin windows.pslist.PsList
we can see that Word was running at the time.
2760 2212 WINWORD.EXE 0x85fa2d20 8 316 1 False 2021-02-21 16:24:39.000000 N/A Disabled
Identifying files with python3 vol.py -f image.bin windows.filescan.FileScan
reveals an interesting document.
0x7e615f80 \Users\IEUser\Desktop\~$NFIDENTIAL DOCUMENT.docx 128 0x7e841f80 \Users\IEUser\Desktop\CONFIDENTIAL DOCUMENT.docx 128 0x7eb665b8 \Users\IEUser\Desktop\CONFIDENTIAL DOCUMENT.docx 128
Lets dump those files. Running python3 vol.py -f image.bin windows.dumpfiles.DumpFiles
extracts all files found in the memory dump, and when it’s done we can find two interesting files.
file.0x85d665b8.0x85e41580.DataSectionObject.CONFIDENTIAL DOCUMENT.docx.dat file.0x85d665b8.0x85e41b30.SharedCacheMap.CONFIDENTIAL DOCUMENT.docx.vacb
Checking the file type of the files reveals that it’s Microsoft Word 2007+ files, but they are corrupted and cant be opened with LibreOffice. We can extract the data from the files using 7z x file.0x85d665b8.0x85e41580.DataSectionObject.CONFIDENTIAL DOCUMENT.docx.dat
. This extracts the document.xml file which contains the word document data.
To view the word document we can create a new docx file and replace the word/document.xml with the extracted document.xml and open it.

flag{c442f9ee67c7ab471bb5643a9346cf5e}
Resourceful
Mobile – 50pts
Description
I built my first ever android app with authentication!
Solution
When we have decompiled the app with JADX we can take a look at the resoruces.

Lets take a look at the strings.

The md5 string looks interesting, as it turns out it is the flag.
flag{7eecc051f5cb3a40cd6bda40de6eeb32}
Andra
Mobile – 50pts
Description
You know what to do. 🙂
Solution
When starting the app we get a login screen.

Lets decompile the app and find the login check.
@Override // androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
View findViewById = findViewById(R.id.name);
Intrinsics.checkNotNullExpressionValue(findViewById, "findViewById(R.id.name)");
this.name = (EditText) findViewById;
View findViewById2 = findViewById(R.id.pass);
Intrinsics.checkNotNullExpressionValue(findViewById2, "findViewById(R.id.pass)");
this.pass = (EditText) findViewById2;
View findViewById3 = findViewById(R.id.login_btn);
Intrinsics.checkNotNullExpressionValue(findViewById3, "findViewById(R.id.login_btn)");
Button button = (Button) findViewById3;
this.login_btn = button;
if (button == null) {
Intrinsics.throwUninitializedPropertyAccessException("login_btn");
}
button.setOnClickListener(new MainActivity$onCreate$1(this, "Nahamcom", "pink_panther@786"));
}
Here we find the onClickListener for the button with some parameters that looks like a username and password. When entering those in the app we are able to log in and get the flag.

flag{d9f72316dbe7ceab0db10bed1a738482}
Microscopium
Mobile – 476pts
Description
This cool app will keep your secrets!
Solution
When decompiling the app we find out that it’s an React Native application, to get the javascript bundle we can use apktool to extract the data. Opening the bundle and pretty print it we can find a function with the string Insert the pin to get the flag.
function b() {
var t;
(0, o.default)(this, b);
for (var n = arguments.length, l = new Array(n), u = 0; u < n; u++) l[u] = arguments[u];
return (t = v.call.apply(v, [this].concat(l))).state = {
output: 'Insert the pin to get the flag',
text: ''
}, t.partKey = "pgJ2K9PMJFHqzMnqEgL", t.cipher64 = "AA9VAhkGBwNWDQcCBwMJB1ZWVlZRVAENW1RSAwAEAVsDVlIAV00=", t.onChangeText = function(n) {
t.setState({
text: n
})
}, t.onPress = function() {
var n = p.Base64.toUint8Array(t.cipher64),
o = y.sha256.create();
o.update(t.partKey), o.update(t.state.text);
for (var l = o.hex(), u = "", c = 0; c < n.length; c++) u += String.fromCharCode(n[c] ^ l.charCodeAt(c));
t.setState({
output: u
})
}, t
}
So the function basically takes the base64 decoded value of t.cipher64
and XOR each value with a SHA256 hash based on t.partKey
and the entered PIN. Starting the app we can find out that the max length of the PIN is four chars, so lets write a script to find the flag.
#!/usr/bin/env python3
import hashlib
import base64
part_key = b'pgJ2K9PMJFHqzMnqEgL'
cipher64 = 'AA9VAhkGBwNWDQcCBwMJB1ZWVlZRVAENW1RSAwAEAVsDVlIAV00='
data = base64.b64decode(cipher64)
pin = 0
while True:
padded = f'{pin:04}'
sha = hashlib.sha256()
sha.update(part_key)
sha.update(bytes(padded,'utf-8'))
hexdigest = sha.hexdigest()
result = ''
for idx in range(0, len(data)):
result += chr(data[idx] ^ ord(hexdigest[idx]))
pin += 1
if 'flag{' in result:
print('Flag found', result)
break
Running the script we get the flag.
Flag found flag{06754e57e02b0c505149cd1055ba5e0b}
Abyss
Misc – 50pts
Description
A Vortex? No… an Abyss.
Solution
Connecting to the service we get screen after screen of random characters.
yrn3aC$>1WvTcy]BdVg^_iDq^_!RswL<q8P=q8cEx-F<8Yp}fZ?~->K7'pL6b!p!S~n4gg2"6T=...
If we keep the connection open for a bit we start to receive the flag repeatedly.
flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}flag{db758a0cc25523993416c305ef15f9ad}
Alphabet Soup
Misc – 461pts
Description
A, B, C, and V, G, L, Y… wait a second, that’s not how the song goes!
Solution
Opening the attached C# source code we find some obfuscated code. Cleaning it up a bit we end up with the following.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using System.Linq;
namespace NahamConCTF
{
class Program
{
private static string decode(string data, string alphabetMap)
{
string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
string returnValue = "";
Dictionary<char, char> alphabetDict = new Dictionary<char, char>();
for (int i = 0; i < alphabet.Length; ++i)
{
alphabetDict.Add(alphabetMap[i], alphabet[i]);
}
for (int i = 0; i < data.Length; ++i)
{
if ((data[i] >= 'A' && data[i] <= 'Z') || (data[i] >= 'a' && data[i] <= 'z'))
{
returnValue += alphabetDict[data[i]];
}
else
{
returnValue += data[i];
}
}
return returnValue;
}
static void Main()
{
string data = "<READACTED>";
string alphabetMap = "lQwSYRxgfBHqNucMsVonkpaTiteDhbXzLPyEWImKAdjZFCOvJGrU";
Assembly assembly = Assembly.Load(Convert.FromBase64String(decode(data, alphabetMap)));
MethodInfo methodInfo = assembly.EntryPoint;
methodInfo.Invoke(assembly.CreateInstance(methodInfo.Name), null);
}
}
}
So the data
variable contains a encoded .NET assembly that is resolved at runtime. Lets dump the assembly and take a look at it by changing the Main
method to the following and then executing it.
public static void Main()
{
string data = "<REDACTED>";
string alphabetMap = "lQwSYRxgfBHqNucMsVonkpaTiteDhbXzLPyEWImKAdjZFCOvJGrU";
var decoded = Convert.FromBase64String(decode(data, alphabetMap));
using (BinaryWriter binWriter = new BinaryWriter(File.Open("output.dll", FileMode.Create)))
{
binWriter.Write(decoded);
}
}
Now we got the assembly in output.dll. Opening this in ILSpy or another .NET decompiler we can find a large byte array in the Main
method in the Program
class.
// ConsoleApp1.Program
using System;
internal class Program
{
private static void Main()
{
byte[] array = new byte[40040]
{
159,
188,
...
79,
224
};
Console.WriteLine("Not so fast!");
}
}
Lets dump the data to a file by adding the following to the Main
method and executing it.
using (BinaryWriter binWriter = new BinaryWriter(File.Open("output2", FileMode.Create)))
{
binWriter.Write(array);
}
Now we got the array data in the file output2. Running strings -n8 output2
reveals the flag.
zYmb@"Un }R0wk!7s U7O0wjIL tBRwV?|)( flag{b6cfb6656ea0ac92849a06ead582456c} lk!!@N2 \(* ,8+' z)=g)@NA9 7@SiL.s(K
Gone Batty
Misc – 489pts
Description
Happy 100th, Trickbot!
Solution
Attached is an almost 10000 lines long obfuscated bat file.
@echo off
set zfvgawagi=set
%zfvgawagi% ufykqylob=
%zfvgawagi%%ufykqylob%gazhkl==
%zfvgawagi%%ufykqylob%lsdppuf%gazhkl%/
%zfvgawagi%%ufykqylob%kamnrmirz%gazhkl%a
%zfvgawagi%%ufykqylob%kcjmprb%gazhkl%c
%zfvgawagi%%ufykqylob%nsxzbbjvw%gazhkl%m
%zfvgawagi%%ufykqylob%btohszm%gazhkl%d
%zfvgawagi%%ufykqylob%swpkkttax%gazhkl%e
%zfvgawagi%%ufykqylob%smivqg%gazhkl%x
%zfvgawagi%%ufykqylob%nbyxysg%gazhkl%i
%zfvgawagi%%ufykqylob%fhqrcmmp%gazhkl%t
%zfvgawagi%%ufykqylob%lmkzcgr%gazhkl%
...
Starting the clean up we find a second block of around 200 lines of set commands.
set /a axpewk=7789391 %% 7789294
cmd /c exit %axpewk%
set qeluatb=%=exitcodeAscii%
set /a scboabb=5338648 %% 5338550
cmd /c exit %scboabb%
set wemnehsl=%=exitcodeAscii%
set /a pukizmym=5454801 %% 5454702
cmd /c exit %pukizmym%
set dlbiwvbel=%=exitcodeAscii%
set /a dxoyty=7625800 %% 7625700
cmd /c exit %dxoyty%
set ouiyvyqu=%=exitcodeAscii%
...
Extracting all the new set commands to a new bat file and running it produces a lot of variables which we can dump by using SET > env.txt
and use the values to continue to clean up the rest of the file.
When we have replaced all the variables from env.txt we get a lot of commented out variables, around 9700 lines.
rem set fhofmklptejwaibqyktyvgxevwimiupegqqimnsyivbngqgyut=eytpoohwmdottnrivekjagnoklhdhjtkplhhbudzdoilgyjqtggiwybidrqkoqn
rem set jwvcofueaqrvzdvaopbhgmbjxnexydojatfffyxg=saygkfmsevqywftyvrizkfpqgrblucfjnfqbeuljkknzdwn
rem set iomoccvfeyfpfrlzhfjztexliatoxmwniivelmjrencvtoufvglitn=vlmjawdjypqglkjxdtcrrcmtsrwyyawojlxuqzpnlqem
rem set lpnwqgoahbrknkkfavuqdsehoegctywwueietywxmmdpfweqgei=vcjhrjfstnobdubzqwbftmrcn
rem set hpyzpjowiikauceheogxtcnnmnwuui=kabazcpzchbvycojbygzxaakxjioxskupataixbtfglnzl
rem set iidsgxdrnetndugyjlkldmqemtqxtwfhiepuzzopzcwwrnhujtkuaidpfvgo=amutqmniivqjphduxlqqfsoyhpo
rem set fjkgzhetqtydkvfhtcigdnbbmdqpfuefveaaoulhzinjeovpike=cwboqyexpve
:: set khdvpxnedglxrlsq=ulzeejjlcvpqznskaymnyuxevcszqisjuwg
...
In the file we can find some variables named flag_characterXX
, extracting all those we get the flag.
:: set flag_character1=f :: set flag_character2=l :: set flag_character3=a :: set flag_character4=g :: set flag_character5={ :: set flag_character6=b :: set flag_character7=3 :: set flag_character8=9 :: set flag_character9=5 :: set flag_character10=c :: set flag_character11=c :: set flag_character12=3 :: set flag_character13=e :: set flag_character14=3 :: set flag_character15=3 :: set flag_character16=c :: set flag_character17=d :: set flag_character18=e :: set flag_character19=b :: set flag_character20=b :: set flag_character21=e :: set flag_character22=c :: set flag_character23=9 :: set flag_character24=d :: set flag_character25=1 :: set flag_character26=1 :: set flag_character27=7 :: set flag_character28=2 :: set flag_character29=9 :: set flag_character30=2 :: set flag_character31=b :: set flag_character32=d :: set flag_character33=2 :: set flag_character34=e :: set flag_character35=8 :: set flag_character36=1 :: set flag_character37=c :: set flag_character38=} flag{b395cc3e33cdebbec9d117292bd2e81c}
ngrocket
Scripting – 499pts
Description
Didn’t know this party was BYOB, bring-your-own-box? No worries! Blast off as many rockets as you would like to a location of your choosing! Hope the right one lands…
Solution
When connecting to the service we are prompted to enter a host and port to send a rocket to.

Entering a host and port using the ngrok service we get a key and an IV for the sent data.

And the data received by the listening service looks something like this.
8670671ab9ff69018d6d1507157fee0f853a28dcc0d78bd04baab6adf479bd34fd841bd7e730aebe1866867a9efa01022cba2dc3685c862a4d93fce70e5578af
Using the key and IV to decrypt the received data returns garbage for most of the rockets, some rockets say something like ‘oops empty’. But once in a while we get a rocket containing a string telling us that a character of the flag is in index n. So we need to listen to a lot of rockets, decrypt them and check if we got a character of the flag, then we need to be able to fire off a lot of rockets to our service.
Python scripts for the client and server can be found here. Starting the scripts and waiting for a while, hoping to receive the correct rockets, we get the flag.
Flag found flag{5d86a82e5ba044c0df2613ca708e1b8c}
$Echo
Web – 50pts
Description
So I just made a hardcoded bot that basically tells you what you wanna hear. Now usually it’s a $ for each thing you want it to say but I’ll waive the fee for you if you beta test it for me.
Solution
All we have on the challenge page is an input field where we can enter some text that will be echoed back on the page.

After trying out some characters we find out that there seems to be a filter on the input.

To be able to get command injection we can add %0A as the first character of the parameter echo, when using this to send /?echo=%0Acat%20index.php
we are able to get the source for the page.
<?php
$to_echo = $_REQUEST['echo'];
$cmd = "bash -c 'echo " . $to_echo . "'";
if(isset($to_echo))
{
if($to_echo=="") {
print "Please don't be lame, I can't just say nothing.";
} elseif (preg_match('/[#!@%^&*()$_+=\-\[\]\';,{}|":>?~\\\\]/', $to_echo)) {
print "Hey mate, you seem to be using some characters that makes me wanna throw it back in your face >:(";
} elseif ($to_echo=="cat") {
print "Meowwww... Well you asked for a cat didn't you? That's the best impression you're gonna get :/";
} elseif (strlen($to_echo) > 15) {
print "Man that's a mouthful to echo, what even?";
} else {
system($cmd);
}
} else {
print "Alright, what would you have me say?";
}
?>
Here we can see the filter and also a length constraint on the input. Checking out the files on the server we can find a flag.txt file in ../flag.txt. But we cant use the previous way to cat the flag.txt since we exceed the length limit. Focusing on the filter we can see that neither < nor ` is filtered meaning we should be able to pipe the file to echo without using the previous trick.
Entering `<../flag.txt`
in the input field and submitting returns the flag contents.

flag{1beadaf44586ea4aba2ea9a00c5b6d91}
eaxy
Cryptography – 50pts
Description
Crypto is eaxy, it’s all about math and keys 🙂
Solution
The attached file contains a bunch of seemingly random data. Trying to XOR with different values reveals some text in different parts of the file.
The XOR key you used to find string this is the 3 character index of the flag 🙂
So we could write a script to try all combinations and search for parts of the string.
#!/usr/bin/env python3
input = open('eaxy', 'rb')
data = input.read()
input.close()
for val in range(0, 256):
decoded_array = []
for idx in range(0, len(data)):
decoded_array.append(data[idx] ^ val)
output = open('output/' + hex(val), 'wb')
output.write(bytes(decoded_array))
output.close()
After executing this script we get a file for each tried value, when we run grep XOR *
we get a list of all files that was correctly decoded.
Binary file 0x30 matches Binary file 0x31 matches Binary file 0x32 matches Binary file 0x33 matches Binary file 0x34 matches Binary file 0x35 matches Binary file 0x36 matches Binary file 0x37 matches Binary file 0x38 matches Binary file 0x39 matches Binary file 0x61 matches Binary file 0x62 matches Binary file 0x63 matches Binary file 0x64 matches Binary file 0x65 matches Binary file 0x66 matches Binary file 0x67 matches Binary file 0x6c matches Binary file 0x7b matches Binary file 0x7d matches
Checking the index value of the decoded strings we can rebuild the flag.
flag{16edfce5c12443b61828af6cab90dc79}
Bionic
The Mission – 50pts
Description
CONSTELLATIONS has “tried” to reduce their attack surface by offering just a static website. But you might find some low-hanging fruit to get you started.
With the flag of this challenge, you should also find a new URL that will assist in the next challenge.
Solution
Checking out the robots.txt file we get the flag and the URL for the next challenge.
User-agent: * Disallow: /meet-the-team.html flag{33b5240485dda77430d3de22996297a1}
Meet the team
The Mission – 50pts
Description
Recover the list of employees working at CONSTELLATIONS.
With the flag of this challenge, you should find new information that will help with future challenges.
Solution
On the meet-the-team.html page we can see that the list of employees is redacted.

After some checking around we find out that a .git folder is published to the web server.

To retrieve the repository we can use GitTools to first dump the repo with gitdumper.sh, when we have the files we can extract the contents with extractor.sh. Now we have a couple of different directories for different versions of the page. In one of the earlier versions we can find the previous meet-the-team.html page containing the list of employees.

Checking the source for the page we find the flag in a comment at the end of the list.
<!-- <li><h4><b>flag{4063962f3a52f923ddb4411c139dd24c}</b></h4></li> -->
Lyra
The Mission – 50pts
Description
Use open-source intelligence to track down information on Lyra.
With the flag of this challenge, you should also find details you can use in later challenges.
Solution
We can find Lyra Patte on twitter.

Checking her tweets we can find a tweet with a link to a page on constellations.page.

Clicking on the link gets us to https://constellations.page/constellations-documents/1/ which contains some hiring guidelines.

Changing the Id we can find some other pages, when we get to Id 5 we get the flag.

Hydraulic
The Mission – 190pts
Description
Gain access with the information you have gathered thus far and retrieve the flag.
Solution
Now we have a server with an open ssh port, but no user and password. So if we use the information from the previous challenges we can generate a list of usernames from the first names of the employees and take the default account passwords to try to brute force the ssh service with hydra.
hydra -L usernames.txt -P passwords.txt ssh://challenge.nahamcon.com:32697Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway). Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2021-03-13 13:17:37 [DATA] max 16 tasks per 1 server, overall 16 tasks, 520 login tries (l:8/p:65), ~33 tries per task [DATA] attacking ssh://challenge.nahamcon.com:32697/ [32697][ssh] host: challenge.nahamcon.com login: pavo password: starsinthesky [STATUS] 229.00 tries/min, 229 tries in 00:01h, 291 to do in 00:02h, 16 active [STATUS] 235.50 tries/min, 471 tries in 00:02h, 49 to do in 00:01h, 16 active 1 of 1 target successfully completed, 1 valid password found Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2021-03-13 13:19:51
So we found a valid password for the user pavo. Logging in using these credentials we can access the flag in the home directory.
flag{cadbbfd75d2547700221f8c2588e026e}
Centaurus
The Mission – 495pts
Description
Constellation employees use this app to secure their passwords. Is it really secure?
Solution
Now we got an android app. When decompiling the app with JADX we can start to check out how it works. We can quickly see that it’s obfuscated due to the different packages and classes are named a, b, c and so on. After some analysis of the source we find an interesting interface.
public interface c {
@e("users/{uuid}")
d<c.b.a.c.d> a(@p("uuid") String str);
@l("passwords/{uuid}")
d<b> b(@p("uuid") String str, @a b bVar);
@e("notes/{uuid}")
d<c.b.a.c.a[]> c(@p("uuid") String str);
@e("passwords/{uuid}")
d<b[]> d(@p("uuid") String str);
@l("auth")
d<c.b.a.c.d> e(@a c.b.a.c.c cVar);
@l("users")
d<c.b.a.c.d> f(@a c.b.a.c.c cVar);
@l("notes/{uuid}")
d<c.b.a.c.a> g(@p("uuid") String str, @a c.b.a.c.a aVar);
}
After some more analysis we can find what looks like a HTTP client containing the base URL and an authorization header for the API.
d.e("http://challenge.nahamcon.com:31234/api/", "$this$toHttpUrl");
c2.a("Authorization", "ZUBoMXQybXw0RlhFU05TNVpBMiZndkRLSmRfZDVYZDM=");
Using this information we can call the users endpoint to see if we can access it. And sure enough, we get a response with the users and the uuids for each user.
[ { "username": "gemini.coley", "uuid": "2164421e-3cdc-465f-b1fc-2da0bed89a6c" }, { "username": "pavo.welly", "uuid": "b4bc4415-bb08-49aa-9b87-c3f232253c4d" }, { "username": "congon4tor", "uuid": "f5e80b35-8e12-43a5-88a5-7bc8585ab234" }, { "username": "testaccount", "uuid": "09ad1f68-11a2-4855-98ed-93c2bc3f7193" }, { "username": "admin", "uuid": "812b3885-6203-4101-997a-a7ca5afcc969" }, { "username": "adminf", "uuid": "91aab5b1-c75e-45fb-9db6-7a1579c157a6" } ]
Calling the passwords endpoint with each uuid returns a bunch of passwords, but no flag. Time to try the notes endpoint.
Calling the notes endpoint with gemini.coley’s uuid we get the flag.
[ { "content": "flag{4a8f943a965086945794066f7ce97f23}", "name": "flag" } ]
NASCAR
The Mission – 499pts
Description
CONSTELLATIONS employees rejoice, NASCAR has developed a cloud solution to control cars remotely! You are headed to a race and need to get up and running. Here are some logs that might help you get started.
Solution
Connecting to the service we can find out that we need to provide the CAN codes for locking the car and setting the odometer to 40mph.
_ _____ _____ _________ ____ / | / / | / ___// ____/ | / __ \ / |/ / /| | \__ \/ / / /| | / /_/ / / /| / ___ |___/ / /___/ ___ |/ _, _/ /_/ |_/_/ |_/____/\____/_/ |_/_/Please send the CAN codes to: 1. Lock the car 2. Set the odometer to 40 mph
Checking the provided log file we quickly find out two potential codes for the lock code, 19B#000000000000 and 19B#00000F000000. As it turns out, the lock code is 19B#00000F000000. Now we have to calculate the odometer value, checking the logs the code is most likely to begin with 244# and then the correct value.
Checking out the code for ICSim we can find the formula for calculating the correct values, now we got 244#00000018FF. Entering those codes returns the flag.
flag{e056ee2f338a63d03a2e47aefebf178f}
Gus
The Mission – 50pts
Description
Use open-source intelligence to track down information on Gus.
With the flag of this challenge, you should also find details you can use in later challenges.
Solution
Following the GitHub link on the CONSTELLATIONS web site we can see one person in the CONSTELLATIONS organization.

The one person in the organization is Gus.

Checking out the development repository we a commit that says update flag.txt.

Opening the file reveals the flag.
flag{84d5cc7e162895fa0a5834f1efdd0b32}
Hercules
The Mission – 50pts
Description
Use open-source intelligence to track down information on Hercules.
With the flag of this challenge, you should also find details you can use in later challenges.
Solution
If we check Gus’s followers on GitHub we can find a follower named HerculesScox.

Going to his GitHub account we can find a repository named maintenance.

Taking a look at the latest commit we can see that he has updated the file connect.sh. Opening this file reveals the flag.

flag{5bf9da15002d7ea53cb487f31781ce47}
Orion
The Mission – 156pts
Description
Use open-source intelligence to track down information on Orion.
With the flag of this challenge, you should also find a password you can use in later challenges.
Solution
Orion Morra can be found on twitter.

Taking a look at the tweets, the flag can be found in one of his posts.

flag{0bcffb17cbcbf4359a42ec45d0ccaf2}