Introduction

The Swedish CERT, CERT-SE, hosted another CTF this year with the following scenario.

CERT-SE has come across network traffic from the fictional hacker group "Medelålders Sura Blackhats".
Can you find all the flags?

Analysis

When opening the attached pcap file we can find a couple of IRC-sessions. Filtering out all the messages we end up with this conversation.

Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Well, it should be safe. This new free VPN-service is what all my buddies is using. 🙂
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Just look at your IP, it's a private non-routable one.
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :If you say so... It seems too good to be true, I mean, why is it free?!?
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :It's a developer that want to help with our cause. He's on our side! He's developed encryption software to others before.
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Ok ok ok, stop arguing!
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Just send the broadcast.
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Done!
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :Ok then, just make sure all your disks are encrypted...
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Of course! Do you think we're stupid?!?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Erm, wait... I need to reinstall...
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :Oh what a muppet!!!
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Sigh...
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :LOL!!!
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Hey guys, I'm back! 🙂
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :Encrypted now?!?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Yeah... Sorry, I was in a hurry.
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Ok, but no more slipups! Nyckelpiga 17173 is too important!!!
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Yeyeye... I know. :-/
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Is everything set?
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Yes, I'm ready!
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :Done, just waiting for the signal!
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Almost, I just have to finish the last pieces...
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :Sigh, seriously?!?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Ehehe... Just kidding, of course I'm ready! Soon...
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Come on!
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Just finish it already! We're about to go!
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Well, let's just go. It's ready enough...
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Ok!
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :What's the URL?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :192.168.122.129
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :It's not encrypted!?!?!
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :?!? :-O
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Well, it's the thing I didn't have time to finish. But it should be ok, we want prople to find it anyway.
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :You better be right, but if this fails it's because of you...
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Don't worry, I'm too 1337 for that to happen! 🙂
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Ok, but shut the server down as soon as you see that the message is received.
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Of course, that was the plan all along.
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :I'm a bit hesistant of the transmission... Will it work?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :If it worked for Apollo and ISS it should do fine for us. The receiver knows what to expect.
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :By the way, can I you have the star-file?
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Sure, sending it to you now...
Hejarn!user@192.168.122.251 PRIVMSG Kammen :\001DCC SEND Star!6.kmz 199 0 2363 106\001
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Done.
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Thanks!
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :I still would feel much safer if we'd use an encrypted transfer.
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :You're being paranoid! We're on a VPN! 🙂
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :I hope you're right...
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Me too!
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :We'll be in the lost island of Atlantis before they even start looking for us. X-D
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Yeah, Atlantis rulez! ❤
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Sure does! Great parties!
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :Anyway, too late to go back... Is the Debian-dump ready?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Erm, yes... I have it on my USB key... Here... Somewhere...
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :One sec...
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Sigh...
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Oh come on!!!
Hejarn!user@192.168.122.251 PRIVMSG #Priv-IRC :Oh damn, did you hear?!? This "free" VPN is a made by the feds!!! They've developed it just to be able to see our traffic! Disconnect and go back to our old method! NOW!
Frissan!user@192.168.122.156 PRIVMSG #Priv-IRC :k
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :What?!? :-O
Sippen!user@192.168.122.186 PRIVMSG #Priv-IRC :Ok.
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Ok, sending the dump now.
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Ok, transfer is completed from my side. Now we just wait for the response. 🙂
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :So, are we ready for the last step?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Guys?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Where did you go?!?
Kammen!user@192.168.122.177 PRIVMSG #Priv-IRC :Oh no...

From this we now know that there are four people in the group, Frissan, Kammen, Sippen and Hejarn, and that they are part of an operation called Nyckelpiga 17173.

We also find out that two files are being transferred somewhere and one file is being send by DCC. We also get an URL to some page, 192.168.122.129.

HTTP Traffic

Lets start by taking a look at the HTTP objects from 192.168.122.129.

HTTP objects

Here we get our first flag, CTF[bra_start].

Saving and opening the file giveup.jpg we get a QR Code.

giveup.jpg

Decoding the QR Code just returns a YouTube link to Rick Astley – Never Gonna Give You Up.

Using steghide without a password to check for hidden data we get the file flag.txt which contains our second flag, CTF[chameleon].

DCC file

In the TCP stream 270 we find the file data for Star!6.kmz which is sent via DCC. Saving the file and searching for what file type kmz is we find out that it’s a format for Google Maps and Google Earth.

When opening the file in Google Maps we get the following pattern.

Star!6.kmz in Google Maps

Lets try to open it in Google Earth instead an see if we can get another perspective. When we open the kmz file in Google Earth and put the camera in the center of the pattern we see the this instead.

Star!6.kmz in Google Earth

Now it looks like characters. When we read all characters we get the string XGU[IVHRORVMH].

This looks like some kind och cipher, and when using a cipher identifier it tells us that it probably is a Beaufort Cipher.

Since we know that the three first characters of the string should be CTF we can use dCode‘s Beaufort Decoder to recreate the key.

dCode Beaufort Decoder

It seems that the key simply is Z. When we decrypt the string using the key we get the third flag, CTF[RESILIENS].

FTP Data

Now lets take a look at the other two files that were transferred. If we filter the packets on FTP we find two FTP sessions.

220 (vsFTPd 3.0.3)
USER sippen
331 Please specify the password.
PASS R0tmosp4stej
230 Login successful.
SYST
215 UNIX Type: L8
TYPE I
200 Switching to Binary mode.
PORT 192,168,122,186,141,47
200 PORT command successful. Consider using PASV.
STOR broadcast.7z
150 Ok to send data.
226 Transfer complete.
QUIT
221 Goodbye.
220 (vsFTPd 3.0.3)
USER kammen
331 Please specify the password.
PASS sm0rdegstras1g
230 Login successful.
SYST
215 UNIX Type: L8
TYPE I
200 Switching to Binary mode.
PORT 192,168,122,177,227,133
200 PORT command successful. Consider using PASV.
STOR memdump4.7z
150 Ok to send data.
226 Transfer complete.
QUIT
221 Goodbye.

Here we see that two files, broadcast.7z and memdump4.7z, is uploaded to the FTP server.

Filtering the packets on FTP-DATA we find the data streams for both of the files. Lets save them and take a look at the contents.

Broadcast

When we try to unpack broadcast.7z we see that it’s password protected, but we got some directories and files anyway.

0:
3

4:
6

5:
11

c:
1

D:
7

h:
2

j:
10

k:
4

l:
5

m:
8

o:
9

The file names in the directory ranges from 1-11. That can mean that the files are the index of the character in the password.

If we arrange the directory names using the file in the directory as an index we get ch0kl4Dmoj5. Which is the password for the file.

When we unpack the file using the password we get two new files, Zipper/.secret/-/flag.txt and Zipper/.secret/!/broadcast.wav.

If we take a look at flag.txt we get out fourth flag, ctf[skulle_skippat_linbanan].

Listening to the file broadcast.wav we can hear some kind of signal. As hinted in the IRC conversation that the signal worked for Apollo and ISS, this should be a SSTV signal.

Decoding the signal using a SSTV decoder like QSSTV we get a picture.

Decoded SSTV signal

And we get our fifth flag, CTF[RYMDLJUD].

Memdump

Now it’s time to take a look at the last file we found. And as hinted in the IRC conversation this is a Debian memory dump. So the first thing we need to do is to download a Volatility profile for Debian and then we can start our analysis.

If we run vol2 --plugins=profiles --profile=LinuxDebian94x64 -f memdump4.dmp linux_bash we see that there’s a program named SuperSecretLogonTool running.

To get the PID for the process we run vol2 --plugins=profiles --profile=LinuxDebian94x64 -f memdump4.dmp linux_bash and get the PID 414.

To dump the process image we run vol2 --plugins=profiles --profile=LinuxDebian94x64 -f memdump4.dmp linux_procdump -p 414 -D out and we get an ELF file.

Now we can open the dumped image in Ghidra for further analysis. After fixing the disassembly and strings we get the following strings.

SuperSecretLogonTool strings

Here we see a string that starts with “Bra gjort! Här kommer flag…”. If we check where that string is used in the code we find the following function.

void UndefinedFunction_004011d6(void)

{
  int iVar1;
  byte bVar2;
  undefined8 *puVar3;
  undefined8 uStack104;
  undefined8 uStack96;
  undefined8 uStack88;
  undefined8 uStack80;
  undefined8 uStack72;
  undefined4 uStack64;
  undefined2 uStack60;
  undefined *puStack48;
  undefined8 uStack40;
  int iStack32;
  int iStack28;
  
  iStack32 = 0x16;
  uStack104 = 0x4847464544434241;
  uStack96 = 0x504f4e4d4c4b4a49;
  uStack88 = 0x5857565554535251;
  uStack80 = 0x3534333231305a59;
  uStack72 = 0x2b2d402139383736;
  uStack64 = 0x3d5d5b5f;
  uStack60 = 0x2623;
  uStack40 = 0x15;
  for (puVar3 = &uStack104; puVar3 != &uStack104; puVar3 = (undefined8 *)((long)puVar3 + -0x1000)) {
    *(undefined8 *)((long)puVar3 + -8) = *(undefined8 *)((long)puVar3 + -8);
  }
  *(undefined8 *)((long)puVar3 + -8) = *(undefined8 *)((long)puVar3 + -8);
  puStack48 = (undefined *)((long)puVar3 + -0x60);
  *(undefined4 *)((long)puVar3 + -0x60) = 0x5d;
  *(undefined4 *)((long)puVar3 + -0x5c) = 0xd6;
  *(undefined4 *)((long)puVar3 + -0x58) = 0x18c;
  *(undefined4 *)((long)puVar3 + -0x54) = 0x308;
  *(undefined4 *)((long)puVar3 + -0x50) = 0x740;
  *(undefined4 *)((long)puVar3 + -0x4c) = 0xe60;
  *(undefined4 *)((long)puVar3 + -0x48) = 0x1c80;
  *(undefined4 *)((long)puVar3 + -0x44) = 0x3c80;
  *(undefined4 *)((long)puVar3 + -0x40) = 0x4d00;
  *(undefined4 *)((long)puVar3 + -0x3c) = 0xbe00;
  *(undefined4 *)((long)puVar3 + -0x38) = 0x1cc00;
  *(undefined4 *)((long)puVar3 + -0x34) = 0x39000;
  *(undefined4 *)((long)puVar3 + -0x30) = 0x61000;
  *(undefined4 *)((long)puVar3 + -0x2c) = 0xd6000;
  *(undefined4 *)((long)puVar3 + -0x28) = 0x18c000;
  *(undefined4 *)((long)puVar3 + -0x24) = 0x308000;
  *(undefined4 *)((long)puVar3 + -0x20) = 0x740000;
  *(undefined4 *)((long)puVar3 + -0x1c) = 0xa60000;
  *(undefined4 *)((long)puVar3 + -0x18) = 0x16c0000;
  *(undefined4 *)((long)puVar3 + -0x14) = 0x2300000;
  *(undefined4 *)((long)puVar3 + -0x10) = 0x5400000;
  *(undefined4 *)((long)puVar3 + -0xc) = 0x8600000;
  *(undefined8 *)((long)puVar3 + -0x68) = 0x4013f8;
  printf(s_Bra_gjort!_H_r_kommer_flaggan:_00402008);
  for (iStack28 = iStack32 + -1; -1 < iStack28; iStack28 = iStack28 + -1) {
    iVar1 = *(int *)(puStack48 + (long)iStack28 * 4);
    bVar2 = (byte)iStack28;
    *(undefined8 *)((long)puVar3 + -0x68) = 0x401420;
    putchar(iVar1 >> (bVar2 & 0x1f));
  }
  *(undefined8 *)((long)puVar3 + -0x68) = 0x401434;
  putchar(10);
  return;
}

Here we can see that the flag is calculated using a bunch of values and then is printed character by character.

The following Python script will print the flag for us.

idx = 0x15

flag = [
  0x5d,
  0xd6,
  0x18c,
  0x308,
  0x740,
  0xe60,
  0x1c80,
  0x3c80,
  0x4d00,
  0xbe00,
  0x1cc00,
  0x39000,
  0x61000,
  0xd6000,
  0x18c000,
  0x308000,
  0x740000,
  0xa60000,
  0x16c0000,
  0x2300000,
  0x5400000,
  0x8600000
]

decoded = bytearray()

for char in flag:
    value = flag[idx] >> (idx & 0x1f)
    idx -= 1
    decoded.append(value)

print(decoded.decode())

And if we run the script we get the sixth and final flag, CTF[Stackars_Myrstack].