14 minute read

I made an attempt to get as many flags I could in one day because that’s the amount of time I could set aside for this. I got five flags out of nine. I think I might be close to one more and I think the Recycle Bin has one. The last two flags though – I have no idea.

Start

First thing I did was to check for anything readable in the provided .pcap:

strings CERT-SE_CTF2024.pcap | less

and I quickly found an IRC conversation! Super fun, especially since I use IRC on a daily basis. I noticed that the IRC conversation was between two users (An4lys3r and D3f3nd3r) and by filtering the output based on users’ IPs I was able to get something quite readable.

Extracting the IRC conversation

strings CERT-SE_CTF2024.pcap | grep '@10.0.0.' | less

I have trimmed some excessive data to make the conversation more readable.

:irc.ctf.alt 001 D3f3nd3r :Welcome to the Internet Relay Network D3f3nd3r!~user1@10.0.0.20
L:D3f3nd3r!~user1@10.0.0.20 JOIN :#emergency
:irc.ctf.alt 001 An4lys3r :Welcome to the Internet Relay Network An4lys3r!~user1@10.0.0.10
:An4lys3r!~user1@10.0.0.10 JOIN :#emergency
n:An4lys3r!~user1@10.0.0.10 JOIN :#emergency
D3f3nd3r :hello
An4lys3r :aaaah, at last, it's working!
D3f3nd3r :well done setting up the emergency environment so fast!
An4lys3r :Thanks. I'm glad we did a test run a couple of months ago
D3f3nd3r :Yes, I agree
An4lys3r :So what do we know so far, why is our production environment not accessible
D3f3nd3r :Well, I'm in the data center now and the consoles I managed to look at is showing a ransom note.....
An4lys3r :so it's that bad
D3f3nd3r :yup
An4lys3r :Have you found any clue to what group and ransom strain is used, if we are lucky enough there is a free decryptor available
D3f3nd3r :I would not bet on it, but I'll transfer the ransom note to you shortly.
D3f3nd3r :SHA-256 checksum for /home/user/emergency_net/DCC/RANSOM_NOTE.gz (remote): 7113f236b43d1672d881c6993a8a582691ed4beb4c7d49befbceb1fddfb14909
An4lys3r :Thanks, I'll have a look.
D3f3nd3r :I managed to access our FPC system and it looks like it is untouched. I will try carving out pcaps from days / weeks before the encryption started from different segments.
An4lys3r :good, put them on the ftp, I'll have a look at that later.
D3f3nd3r :by the way, Christine came by and handed me a disk image from one of the clients, see if they left any clues on disk. I'll upload it to the ftp shortly.
An4lys3r :We totally need external help, restoring and investigating this incident will be a massive task. You don't happen to have the contact info to Allsafe, I think our rep is called Elliot?
D3f3nd3r :Agree, I already called them in. He is here now sharing some interesting stuff.
D3f3nd3r :They picked up some info on a closed forum regarding our situation, someone posted a WORDLIST scraped from our public website. And they where ranting about recording network traffic from a windows workstation called CTF-PC01. I'll upload the file to the ftp.
D3f3nd3r :He also handed over a strange looking string CTF[E65D46AD10F92508F500944B53168930], does it make sense to you?
An4lys3r :not really, but why don't you ask john?
D3f3nd3r :Alright, I'll see what I can do with it.
An4lys3r :To keep in mind, he also mention they have intel about a suspicious IP address involved in C2 and exfiltration activities lately, the IP is 195.200.72.82

Flag in IRC conversation

Looking at the IRC conversation above, the first flag was right there.

Flag: CTF[E65D46AD10F92508F500944B53168930]

Flag in .pcap

While using strings I tried to just grep for more flags:

$> strings ../CERT-SE_CTF2024.pcap | grep 'CTF\['
7PASS CTF[AES128]
!PASS CTF[AES128]
W_PRIVMSG #emergency :He also handed over a strange looking string CTF[E65D46AD10F92508F500944B53168930], does it make sense to you?
r:D3f3nd3r!~user1@10.0.0.20 PRIVMSG #emergency :He also handed over a strange looking string CTF[E65D46AD10F92508F500944B53168930], does it make sense to you?

Idk if this is too obvious, but the instructions from Cert say flags should have the format CTF[...], so…

Flag: CTF[AES128]

Flag in RANSOME_NOTE.gz (DCC)

In their IRC conversation, the users talk about a file RANSOM_NOTE.gz which they have apparently received from the hackers. For some reason they opted to send this using DCC instead of using the FTP-server they’ll be using throughout the rest of their conversation :p

By grepping for DCC in the .pcap I was able to find the initialisation message:

DCC SEND RANSOM_NOTE.gz 167772170 40899 95285 221

The above contains the integer representation of the IP address (167772170 -> 10.0.0.10) and the port being used for the transfer (40899). The documentation does not mention the last two numbers that is part of the message, but I presume they are the size of the transfer (95285) and maybe the block size used(?).

I opened up Wireshark and filtered accordingly:

ip.addr == 10.0.0.10 && tcp.port == 40899

whereafter I right-clicked on the first package in the list, chose Follow -> TCP Stream, made sure to go to the bottom left of the dialogue and choose only one side of the conversation (the one that is 95kB), choose Show data as Raw and then save the data to a file called RANSOM_NOTE.gz.

The IRC conversation kindly contains the sha256sum for the ransom note and I was able to verify that my file had the same hash: 7113f236b43d1672d881c6993a8a582691ed4beb4c7d49befbceb1fddfb14909.

After decompressing the file:

gunzip RANSOM_NOTE.gz

I got a 279943 byte large text file, starting like this:

CCCCCCCCCCCTCCCCCFCCCCC[CCCCCOCCCCCRCCCCTCCCCCTTCCCCTFCCCCT[CCCCTOCCCCTRCCCCFCCCCCFTCCCCFFCCCCF[CCCCFOCCCCFRCCCC[CCCCC[TCCCC[FCCCC[[CCCC

I tried a handful of different things to no avail, but after talking a little bit to a friend he said there was only one ] in the entire file (something I thought I had already checked) and because of this I tested to just grep for flags:

$> grep -o -E 'CTF\[[a-zA-Z0-9]*\]' ransom_note
CTF[OR]

I felt so stupid. I really thought I checked this one.

Flag: CTF[OR]

FTP Files in original .pcap

In the IRC conversation we can see multiple references to files being uploaded to an FTP server. By filtering on ftp in Wireshark we can practically follow the progress of all of these files (gotta love encryption, right?).

I show the entire communication for file 1, below, but for the other files I have only included the relevant parts.

$> tshark -r CERT-SE_CTF2024.pcap -Y "ftp" -T fields -e _ws.col.Info

-- file 1 --

Response: 220 INetSim FTP Service ready.
Request: USER anonymous
Response: 331 Please specify the password.
Request: PASS NcFTP@
Response: 230 Login successful.
Request: PWD
Response: 257 "/"
Request: FEAT
Response: 500 Unknown command.
Request: HELP SITE
Response: 214-The following commands are recognized.
Response:  ABOR CDUP CWD  DELE HELP LIST MKD  MODE
Request: CLNT NcFTPPut 3.2.6 linux-x86_64-libc5
Response: 500 Unknown command.
Request: CWD /
Response: 250 Directory successfully changed.
Request: TYPE I
Response: 200 Switching to BINARY mode.
Request: SIZE corp_net1.pcap
Response: 500 Unknown command.
Request: PORT 10,0,0,20,143,63
Response: 200 PORT command successful.
Request: STOR corp_net1.pcap
Response: 150 Ok to send data.
Response: 226 File receive OK.
Request: MDTM 20240904045628 corp_net1.pcap
Response: 500 Unknown command.
Request: QUIT
Response: 221 Goodbye.

-- file 2 --

Response: 220 INetSim FTP Service ready.
Request: SIZE corp_net2.pcap
Request: PORT 10,0,0,20,151,169

-- file 3 --

Request: SIZE disk1.img.gz
Request: PORT 10,0,0,20,228,239

-- file 4 --

Request: SIZE WORDLIST.txt
Request: PORT 10,0,0,20,146,93

The approach for fetching the content of each file is the same:

  1. Find the IP:port being used, which in this case is 10.0.0.20 followed by <first integer> * 256 + <second integer>. For the first file the port is: 143 * 256 + 63 = 36 671.

  2. Use Wireshark the same way we got the DCC file:

    • Follow
    • TCP Stream
    • Choose one side of the communication
    • Save Raw data

corp_net1.pcap (from FTP in original .pcap)

I used the same approach for this .pcap as I did for the first one: strings. After quickly scanning through the file I noticed more FTP traffic. More specifically, this (truncated):

$> tshark -r corp_net1.pcap -Y "ftp" -T fields -e _ws.col.Info

Request: SIZE puzzle.exe
Request: PORT 192,168,137,28,136,69

Request: SIZE Recycle-Bin.zip
Request: PORT 192,168,137,28,199,239

Request: SIZE archive
Request: PORT 192,168,137,28,206,7

As before, I retrieved the files by following the TCP Streams.

Flag in puzzle.exe (from FTP in corp_net1.pcap)

A natural approach here would be to execute the program, but I don’t own a Windows PC….

Instead, the first thing I tried was to hexdump the file. The last segment of the dump showed this:

01239050  2e 2e 77 2e 2e 2e 3f 2e  2e 2e 37 2e 2e 2e 2e 38  |..w...?...7....8|
01239060  70 79 74 68 6f 6e 33 31  32 2e 64 6c 6c 2e 2e 2e  |python312.dll...|
01239070  2e 2e 2e 2e 2e 2e 2e 2e  2e 2e 2e 2e 2e 2e 2e 2e  |................|
*
012390a0

and

$> strings your_program.exe | grep -i pyinstaller

._pyi_main_co....Traceback is disabled via bootloader option.....PYINSTALLER_RESET_ENVIRONMENT...1......._PYI_ARCHIVE_FILE......._PYI_APPLICATION_HOME_DIR......._PYI_PARENT_PROCESS_LEVEL......._PYI_SPLASH_IPC.0.......Invalid value in _PYI_PARENT_PROCESS_LEVEL: %s
.PYINSTALLER_STRICT_UNPACK_MODE..Failed to initialize security descriptor for temporary directory!
.....pyi-python-flag.Py_GIL_DISABLED.pyi-runtime-tmpdir......pyi-contents-directory..pyi-disable-windowed-traceback..PYINSTALLER_SUPPRESS_SPLASH_SCREEN......Failed to load splash screen resources!
.........Could not load PyInstaller's embedded PKG archive from the executable (%s)
.....Could not side-load PyInstaller's PKG archive from external file (%s)
.._pyinstaller_pyz........PYZ archive entry not found in the TOC!

indicates that the .exe was created using PyInstaller.

I tried pyinstxtractor.py but it throws the error:

[+] Processing puzzle.exe
[!] Error : Missing cookie, unsupported pyinstaller version or not a pyinstaller archive]

and my conclusion is that pyinstxtractor.py does not support Python 3.12 (which seems to be the version used for the .exe).


Second thing I tried was actually starting the .exe in Wine. That did not work, so I tried dosbox. That did not work either…


Third thing was to enlist a friend with a Windows computer! He was able to start the application and found that it’s a puzzle game (who would’ve thought…). If you do enough of the puzzle the flag can be read of the screen.

Flag: CTF[HAPPYBIRTHDAY] (potentially with a space between Y and B)

Recycle-Bin.zip (from FTP in corp_net1.pcap)

I started with the obvious:

$> unzip Recycle-Bin.zip 
Archive:  Recycle-Bin.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of Recycle-Bin.zip or
        Recycle-Bin.zip.zip, and cannot find Recycle-Bin.zip.ZIP, period.

I tried repairing the archive:

$> zip -FF Recycle-Bin.zip --out Recycle-Bin-fixed.zip && unzip Recycle-Bin-fixed.zip

which yielded a new directory: C in which I could find some stuff:

C/$Recycle.Bin/S-1-5-21-2433278764-4034921937-2507072421-1164 $> ll
total 1.8M
'$I0BN3IA.pdf'
'$I0DKZRU.txt'
'$I0G1V6C.txt'
'$I0P8KGD.txt'
'$I0S90LB.txt'
'$I1341CT.txt'
'$I15ZRRO.txt'
'$I161W3Y.txt'
'$I18MLB2.txt'
'$I1APZ4K.txt'
'$I1E5HE8.txt'
'$I1QVT66.txt'
'$I27B4VA.txt'
'$I283B2L.txt'
'$I2UBK07.jpg'
-- and much more --

I wrote a simple script to check whether any flags were hiding in plain sight:

find . -type f | while read -r file; do
    grep -Eo 'CTF' "$file" && echo "Found in: $file"
done

but was unable to find anything.

Then I wrote another script to check the output of file for each file. The output is summarised below:

-- the majority of files were identified as Matlab files --
$I0BN3IA.pdf Matlab v4 mat-file (little endian) \330\367\332\0018, sparse, rows 0, columns 17051
$IZQJF50.txt Matlab v4 mat-file (little endian) \326\367\332\001=, sparse, rows 0, columns 4
...

-- second most common file type was ASCII or ASCII with CRLF line terminators -- 
$R0G1V6C.txt ASCII text
$R0P8KGD.txt ASCII text, with CRLF line terminators
...

-- then I found some images and some other files --
$R2UBK07.jpg JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 614x460, components 3
$R5QEV86.jpg JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 614x460, components 3
$RAUCOEZ.jpg JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 614x460, components 3
$RKKFUN8.jpg JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 614x460, components 3

$RDE2VJ7.ps1 Unicode text, UTF-8 (with BOM) text, with no line terminators
$R7ZRFQY.ps1 Unicode text, UTF-8 (with BOM) text, with no line terminators

$RCXHUFJ.zip Zip archive data, at least v2.0 to extract, compression method=deflate

$RL7SXXI.exe PE32 executable (GUI) Intel 80386, for MS Windows

$R0BN3IA.pdf PDF document, version 1.7, 1 pages (zip deflate encoded)
$R92DY1S.pdf PDF document, version 1.7, 1 pages (zip deflate encoded)
$RGRASUC.pdf PDF document, version 1.7, 1 pages (zip deflate encoded)
$RJLEGV5.pdf PDF document, version 1.7, 1 pages (zip deflate encoded)

The .pdf files listed above all contained a lorem ipsum paragraph and nothing more.

The images were hand drawn images of cats and dogs (and one image just had CAT written by hand in it).

Both powershell scripts contained: Write-Host "Räkna ut din riktiga ålder"

The zip archive contained a NewFileTime.txt with the following content:

Server:

https://www.softwareok.de/?Download=NewFileTime
https://www.softwareok.com/?Download=NewFileTime
https://www.softwareok.eu/?Download=NewFileTime

http://www.softwareok.de/?Download=NewFileTime
http://www.softwareok.com/?Download=NewFileTime
http://www.softwareok.eu/?Download=NewFileTime

and a NewFileTime_x64.exe.

Running the NewFileTime_x64.exe seems to launch the application which can be downloaded from softwareok.com. What a lovely website – but I don’t know what good the program is for…


I then checked the dates for the files created. Two files stood out as they were created years ago (not weeks like the other files).

$> ls -lat
160 Jun  6  1984 '$I80Z3YX.txt'
 84 Jun  6  1984 '$R80Z3YX.txt'

and the contents of those files are:

$> cat \$I80Z3YX.txt       
T�)�����BC:\Users\aleksej.pazjitnov\Downloads\INKEMW2QIVHFIT2NJFHE6U25.txt%

$> cat \$R80Z3YX.txt       
Jamborino Jamboro Archipelago Island Apple Horse
Monkey Dog
Kit Kat House Flower

Aleksej Pazjitnov created Tetris in 1984. This has to be some sort of clue?

Flag in archive (from FTP in corp_net1.pcap)

According to file, archive is a gzip compressed archive:

$> file archive
archive: gzip compressed data, from Unix, original size modulo 2^32 847

so I added a .gz extension to the file and attempted to unpack it using gunzip:

$> gunzip archive.gz    
gzip: archive already exists; do you wish to overwrite (y or n)? y

Out the other end came a new file, which was also a gzip archive. And then another one. And another one.

But I kept at it, running my one liner:

$> mv archive archive.gz && gunzip archive.gz && file archive && cat archive

until finally:

$> mv archive archive.gz && gunzip archive.gz && file archive && cat archive
archive: POSIX tar archive (GNU)
input0000664000175000017500000000100714661054721010664 0ustar  useruser�����`f�S�����͌>��9��H���%00�S:v��G��c!�wO����1?��~R���?�S�f���ykr�ey�g��~wnl^����kq�١��e��b�"6>|��:����WS�'9�{ċ^��'g���I��k�ѓ����>ޗ�ss��Uǚ]��_������mk��������U֍�ߛ�?�z�����I����]Ͽ[[yi���=����*��������R![]�������n����z�����������ﻷ�[_U����+w����������/�?U7��z}����ìs�~�x������u�������)�o�~����7u�_o.���2���/m�~�����}��ׂSU�k��ߟ[��w׷/�O���o����������[?��r��ӐM_sS�O&�1V�UTr�y~���]BB�\F��������[m�<f��-�f��੭u�������|�9@����W6iј���46+�y�����%       

A TAR!!

$> tar xvf archive
input

$> cat input 
�����`f�S�����͌>��9��H���%00�S:v��G��c!�wO����1?��~R���?�S�f���ykr�ey�g��~wnl^����kq�١��e��b�"6>|��:����WS�'9�{ċ^��'g���I��k�ѓ����>ޗ�ss��Uǚ]��_������mk��������U֍�ߛ�?�z�����I����]Ͽ[[yi���=����*��������R![]�������n����z�����������ﻷ�[_U����+w����������/�?U7��z}����ìs�~�x������u�������)�o�~����7u�_o.���2���/m�~�����}��ׂSU�k��ߟ[��w׷/�O���o����������[?��r��ӐM_sS�O&�1V�UTr�y~���]BB�\F��������[m�<f��-�f��੭u�������|�9@����W6iј���46+�y�����%                                   erik@pop-os: ~/Nextcloud/-shared/ctf $> file input 
input: gzip compressed data, from Unix, original size modulo 2^32 496

really ?

After repeating the process of alternating gunzip and tar I finally was rewarded:

$> mv input input.gz && gunzip input.gz && file input && cat input
input: ASCII text
CTF[IRRITATING]

Flag: CTF[IRRITATING]

corp_net2.pcap (from FTP in original .pcap)

A bunch of TLS traffic. Haven’t investigated this further.

disk1.img.gz (from FTP in corp_net1.pcap)

$> file disk1.img
disk1.img: DOS/MBR boot sector; partition 1 : ID=0xc, start-CHS (0x0,32,33), end-CHS (0x82,138,8), startsector 2048, 2095104 sectors

Let’s mount this using the offset calculated as:

Offset = Start Sector × Sector Size
       = 2048 × 512 bytes
       = 1,048,576 bytes
$> sudo mount -o loop,offset=1048576 disk1.img $(pwd)/diskmount

$> ls -la diskmount
total 12
drwxr-xr-x 2 root root 4096 Jan  1  1970 .
drwxrwxr-x 3 erik erik 4096 Oct  1 10:39 ..
-rwxr-xr-x 1 root root   48 Sep 24 09:54 secret.encrypted

$> file diskmount/secret.encrypted 
diskmount/secret.encrypted: openssl enc'd data with salted password

I fetched openssl2john.py from GitHub and used it to convert the encrypted secret to a hash.

python openssl2john.py diskmount/secret.encrypted > secret.hash

I then downloaded John the Ripper and tried to use the WORDLIST.txt we found earlier to see if we could find a match:

$> ./john --wordlist=WORDLIST.txt secret.hash
Loaded 1 password hash (openssl-enc, OpenSSL "enc" encryption [32/64])
NATHAN           (secret.encrypted)     
1g 0:00:00:00 DONE (2024-10-01 11:24) 50.00g/s 10000p/s 10000c/s 10000C/s 123456..SEPTEMBER
Session completed. 

But I believe NATHAN was a false positive as I was unable to use it for decrypting the secret.encrypeted file.

$> openssl enc -d -aes-256-cbc -md sha256 -in diskmount/secret.encrypted -pass pass:NATHAN
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
40F7EEBFD27E0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:../providers/implementations/ciphers/ciphercommon_block.c:124:
� �P6�i�@�^EiR%   

I also tried adding the pbkdf2 flag:

$> openssl enc -d -pbkdf2 -aes-256-cbc -md sha256 -in diskmount/secret.encrypted -pass pass:NATHAN
bad decrypt
40572AB1327D0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:../providers/implementations/ciphers/ciphercommon_block.c:124:
˺4�G�ҹ��8=�%

I then skipped wrote a little script that tried all passwords in WORDLIST.txt and found several matches (NICOLE, BEAUTIFUL, …) but they all turned out to be false positives.

When I tested John the Ripper with rockyou.txt I got thousands of false positives and somewhere around here I gave up for now.

I also tried all passwords in WORDLIST.txt (after removing the brackets) in combination with all ciphers and digests using this script:

#!/bin/bash

ENCRYPTED_FILE="diskmount/secret.encrypted"
WORDLIST="WORDLIST.txt"
OUTPUT_FILE="secret.decrypted"
CIPHERS=("aes-256-cbc" "aes-192-cbc" "aes-128-cbc" "des3" "des")
DIGESTS=("md5" "sha1" "sha256" "sha512")

check_decryption() {
    FILE_TYPE=$(file -b "$1")
    if [[ "$FILE_TYPE" != "data" ]]; then
        return 0
    else
        return 1
    fi
}

while IFS= read -r PASSWORD; do
    for CIPHER in "${CIPHERS[@]}"; do
        for DIGEST in "${DIGESTS[@]}"; do
            openssl enc -d -"${CIPHER}" -md "${DIGEST}" -in "${ENCRYPTED_FILE}" -out "${OUTPUT_FILE}" -pass pass:"${PASSWORD}" 2>/dev/null
            if [ $? -eq 0 ] && check_decryption "${OUTPUT_FILE}"; then
                echo "Success with password: $PASSWORD, cipher: $CIPHER, digest: $DIGEST"
                echo "Content of decrypted file:"
                echo "$(cat ${OUTPUT_FILE})"
                mv ${OUTPUT_FILE} "${OUTPUT_FILE}$(date)"
            fi
        done
    done
done < "${WORDLIST}"
erik@pop-os: ~/Nextcloud/-shared/ctf/disk1 $> bash script.sh
Success with password: BEAUTIFUL, cipher: aes-128-cbc, digest: sha256
Content of decrypted file:
���70̙�Kt��
��[f�
�W��0jo d�_3

Note that the bash script found BEAUTIFUL with cipher aes-128-cbc which I sort of take as a hint that I’m on the right way, because one flag was literally: CTF[AES128]. That has to be a hint?!

$> file secret.decrypted 
secret.decrypted: Non-ISO extended-ASCII text

I actually tried running this file through the same script (maybe it’s double-encrypted?!), but got nothing out of it.

WORDLIST.txt (from FTP in corp_net1.pcap)

I think it makes sense that this file should be used to decrypt the file in the image mounted above…

Updated: