Forensics - Bad Memory

A user came to us and said they forgot their password. Can you recover it? The flag is the MD5 hash of the recovered password wrapped in the proper flag format.

We get a zip file with a file inside called “image.bin”. As this looks like a memory dump file, we can use volatility3 to analyse and dump data.

Volatility3 setup

We clone the repo and then download the needed symbol files, which is metadata that enabled volatility3 to decode and interpret accurately, for our operating system (linux) in the “volatility3/volatility3/symbols” folder.

 1$ sudo git clone https://github.com/volatilityfoundation/volatility3.git
 2[sudo] password for kali: 
 3Cloning into 'volatility3'...
 4remote: Enumerating objects: 31324, done.
 5remote: Counting objects: 100% (2168/2168), done.
 6remote: Compressing objects: 100% (908/908), done.
 7remote: Total 31324 (delta 1516), reused 1777 (delta 1246), pack-reused 29156
 8Receiving objects: 100% (31324/31324), 6.31 MiB | 416.00 KiB/s, done.
 9Resolving deltas: 100% (23697/23697), done.
10$ cd volatility3/symbols 
11$ wget https://downloads.volatilityfoundation.org/volatility3/symbols/linux.zip

Volatility3 usage

We can now enumerate the image.bin file and gather info by calling windows.info.Info.

 1$ sudo python3 vol.py -f /media/sf_Shared/image.bin windows.info.Info   
 2[sudo] password for kali: 
 3Volatility 3 Framework 2.5.2
 4Progress:  100.00               PDB scanning finished                          
 5Variable        Value
 6
 7Kernel Base     0xf8047e200000
 8DTB     0x1aa000
 9Symbols file:///opt/volatility3/volatility3/symbols/windows/ntkrnlmp.pdb/81BC5C377C525081645F9958F209C527-1.json.xz
10Is64Bit True
11IsPAE   False
12layer_name      0 WindowsIntel32e
13memory_layer    1 FileLayer
14KdVersionBlock  0xf8047ee0f2a8
15Major/Minor     15.19041
16MachineType     34404
17KeNumberProcessors      1
18SystemTime      2020-10-03 11:45:39
19NtSystemRoot    C:\Windows
20NtProductType   NtProductWinNt
21NtMajorVersion  10
22NtMinorVersion  0
23PE MajorOperatingSystemVersion  10
24PE MinorOperatingSystemVersion  0
25PE Machine      34404
26PE TimeDateStamp        Sun Aug 11 05:47:24 2069

We can dump the SAM hashes via windows.hashdump.Hashdump.

 1$ sudo python3 vol.py -f /media/sf_Shared/image.bin windows.hashdump.Hashdump  
 2Volatility 3 Framework 2.5.2
 3...
 4...
 5...
 6Progress:  100.00               PDB scanning finished                                                                                              
 7User    rid     lmhash  nthash
 8
 9Administrator   500     aad3b435b51404eeaad3b435b51404ee        31d6cfe0d16ae931b73c59d7e0c089c0
10Guest   501     aad3b435b51404eeaad3b435b51404ee        31d6cfe0d16ae931b73c59d7e0c089c0
11DefaultAccount  503     aad3b435b51404eeaad3b435b51404ee        31d6cfe0d16ae931b73c59d7e0c089c0
12WDAGUtilityAccount      504     aad3b435b51404eeaad3b435b51404ee        4cff1380be22a7b2e12d22ac19e2cdc0
13congo   1001    aad3b435b51404eeaad3b435b51404ee        ab395607d3779239b83eed9906b4fb92

Cracking the hash and finding the flag

We can crack the hash for the “congo” user via john as these are nthashes we can provide the option --format=NT.

1$ john --format=NT hashdump.txt --wordlist=~/wordlists/rockyou.txt 
2Using default input encoding: UTF-8
3Loaded 1 password hash (NT [MD4 128/128 SSE2 4x3])
4Warning: no OpenMP support for this hash type, consider --fork=3
5Press 'q' or Ctrl-C to abort, almost any other key for status
6goldfish#        (congo)     
71g 0:00:00:00 DONE (2023-10-24 22:16) 1.250g/s 9785Kp/s 9785Kc/s 9785KC/s 
8Session completed.                                               

We now have the plaintext password, but the flag needs to be an MD5 hash, so we can hash plaintext password, and we get the flag.

1$ echo -n "goldfish#" | md5sum                                    
22eb53da441962150ae7d3840444dfdde

flag{2eb53da441962150ae7d3840444dfdde}

Malware - Opendir

A threat actor exposed an open directory on the public internet! We could explore their tools for some further intelligence. Can you find a flag they might be hiding?

We get a link to an open directory, which is a directory that is available to access via a URL, with a username and password. We can download the directory via wget and then search through to files with grep to find the hidden flag.

 1$ wget --user opendir --password opendir --no-parent -r http://chal.ctf.games:30169/
 2$ cd chal.ctf.games:30169 
 3$ ls
 4def1.bat        hyp.bat     LOGOFALL1.bat  NG1.bat  NG3.bat    poshC2.bat    sir
 5dropper_cs.exe  index.html  LOGOFALL.bat   NG2.bat  ngrok.exe  RDPtoALL.bat  VmManagedSetup.exe        
 6$ grep -r "flag*"                                
 7grep: sir/hydra/hydra.exe: binary file matches
 8sir/LOGOFF.bat:  set flag=false
 9sir/LOGOFF.bat:  if "%username%" neq "!user!" (set flag=true) else (if "!status!" neq "Active" set flag=true)
10sir/LOGOFF.bat:  if !flag!==true (logoff !ID!& Echo user=!user! ID=!ID! Status=!status! was log off.)
11sir/64_bit_new/oui.txt:                         Chiefland FL 32626
12sir/64_bit_new/oui.txt:44-4A-65   (hex)         Silverflare Ltd
13sir/64_bit_new/oui.txt:444A65     (base 16)             Silverflare Ltd
14sir/64_bit_new/oui.txt:00-0A-68   (hex)         Solarflare Communications Inc.
15sir/64_bit_new/oui.txt:000A68     (base 16)             Solarflare Communications Inc.
16sir/64_bit_new/oui.txt:                         Efland NC 27243
17sir/64_bit_new/oui.txt:flag{9eb4ebf423b4e5b2a88aa92b0578cbd9}
18sir/64_bit_new/oui.txt:00-0F-53   (hex)         Solarflare Communications Inc.
19sir/64_bit_new/oui.txt:000F53     (base 16)             Solarflare Communications Inc.

Malware - BlackCat

We’ve been hit by the infamous BlackCat Ransomware Group! We need you to help restore the encrypted files. Please help! My favorite rock got encrypted and I’m a wreck right now!

We get a zipped file that contains a ransomware decryption tool. The files contain an executable file that asks for a key to decrypt the files, and if a key is provided, tries to decrypt the files in the “victim-files” directory.

├── DecryptMyFiles.exe
├── NOTE.png
└── victim-files
    ├── Bliss_Windows_XP.png.encry
    ├── flag.txt.encry
    ├── Huntress-Labs-Logo-and-Text-Black.png.encry
    ├── my-favorite-rock.jpg.encry
    ├── the-entire-text-of-hamlet.txt.encry

blackcat-start

When disassembling the executable, we find out the XOR cipher is being used. XOR is considered a weak cipher because it’s vulnerable to Known-plain-text attacks (KPA), which is basically when you have two values you can always derive the third value:

  • plain-text x key = encrypted_text
  • encrypted_text x plain-text = key
  • encrypted_text x key = plain-text If the key is smaller than the plaintext, the key is repeated.

We now have to find out if we can find out plaintext that we can use in this attack. We see a bunch of images being encrypted, we know that the magic bytes (file signatures) at the start of a file are always the same. We can find the hex value by extracting them from any PNG file, in this case we use “notes.png” that was also supplied in the compressed archive.

1$ xxd ../NOTE.png| head -1        
200000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR

We can use this hex value as the plaintext and any encrypted png in CyberChef while decrypting using the XOR cipher.

encrypted_text x plain-text = key
-> contentOf(Huntress-Labs-Logo-and-Text-Black.png.encry) x 89504e470d0a1a0a = key

blackcat-cyberchef

We find the key is “cosmoboi”, located on the location where the magic bytes would be (.PNG).

When putting in the key in “DecryptMyFiles.exe”, we get the decrypted flag.txt:

Keeping my flag here so it's safe:
flag{092744b55420033c5eb9d609eac5e823}

Malware - BlackCat II

Be advised analyst: BlackCat is back! And they’re mad. Very mad. Help our poor user recover the images that they downloaded while browsing their favorite art site. Quickly!

We’ve received a zipped file that contains a decryption tool for ransomware. Inside the files, we find an executable Decryptor.exe that launches a GUI prompting for a decryption key. If a valid key is provided, it attempts to decrypt the files located in the “victim-files” directory.

Directory Structure:

├── Decryptor.exe
└── victim-files
    ├── A_Sunday_Afternoon_on_the_Island_of_La_Grande_Jatte_by_Georges_Seurat_5773ff06-a03e-401b-8914-6106bc277bfd_large.jpg.encry
    ├── Cafe_Terrace_at_Night_by_Vincent_van_Gogh_large.jpg.encry
    ├── flag.txt.encry
    ├── Guernica_by_Pablo_Picasso_large.jpg.encry
    ├── Impression_Sunrise_by_Claude_Monet_large.jpg.encry
    └── Wanderer_above_the_Sea_of_Fog_by_Caspar_David_Friedrich_large.jpg.encry

blackcat2-start

Upon loading “Decryptor.exe” in DotPeek, we can access the source code, revealing a couple of noteworthy methods.

The AESDecryptFile method stands out, utilizing a hardcoded initialization vector (IV):

 1    private static void AESDecryptFile(string inputFile, string outputFile, string key, byte[] iv)
 2    {
 3      try
 4      {
 5        using (Aes aes = Aes.Create())
 6        {
 7          byte[] aesKeyFromPassword = DecryptorUtil.GenerateAesKeyFromPassword(key);
 8          aes.Key = aesKeyFromPassword;
 9          aes.IV = iv;
10          aes.Mode = CipherMode.CFB;
11          aes.Padding = PaddingMode.Zeros;
12          using (FileStream fileStream1 = new FileStream(inputFile, FileMode.Open))
13          {
14            using (FileStream fileStream2 = new FileStream(outputFile, FileMode.Create))
15            {
16              using (ICryptoTransform decryptor = aes.CreateDecryptor())
17              {
18                using (CryptoStream cryptoStream = new CryptoStream((Stream) fileStream2, decryptor, CryptoStreamMode.Write))
19                {
20                  byte[] buffer = new byte[4096];
21                  int count;
22                  while ((count = fileStream1.Read(buffer, 0, buffer.Length)) > 0)
23                    cryptoStream.Write(buffer, 0, count);
24                }
25              }
26            }
27          }
28        }
29      }

However, the most interesting one is DecryptFiles, which utilizes the SHA256 hash of the plaintext file as a decryption key when provided with the filepath`.

 1    public static void DecryptFiles(string directoryPath, string decryptionKey)
 2    {
 3      string[] files = Directory.GetFiles(directoryPath, "*.encry");
 4      if (files.Length == 0)
 5        return;
 6      string filePath = (string) null;
 7      foreach (string str in files)
 8      {
 9        string key = filePath != null ? DecryptorUtil.CalculateSHA256Hash(filePath) : decryptionKey;
10        string outputFile = Path.Combine(directoryPath, Path.GetFileNameWithoutExtension(str) + ".decry");
11        DecryptorUtil.AESDecryptFile(str, outputFile, key, DecryptorUtil.hardcodedIV);
12        filePath = outputFile;
13      }
14      Console.WriteLine("[*] Decryption completed.");
15    }
16
17    private static string CalculateSHA256Hash(string filePath)
18    {
19      using (SHA256 shA256 = SHA256.Create())
20      {
21        using (FileStream inputStream = File.OpenRead(filePath))
22          return BitConverter.ToString(shA256.ComputeHash((Stream) inputStream)).Replace("-", "").ToLower();
23      }
24    }

If we have the plaintext version of those encrypted files, we could decrypt all of our victim-files. We see a bunch of images in the “victim-files” folder. One that sticks out is “A_Sunday_Afternoon_on_the_Island_of_La_Grande_Jatte_by_Georges_Seurat_5773ff06-a03e-401b-8914-6106bc277bfd_large.jpg” as appears to contain a universally unique identifier (UUID).

UUIDs are 128-bit values typically represented as a hexadecimal string with hyphens to separate different parts of the identifier. UUIDs are often used to uniquely identify resources or entities, and they have a very low probability of collision, making them suitable for various applications like database records, filenames, or other scenarios where unique identification is important.

We search these images on Google Images, and as we stumble on one website that seems to have all of them: atxfinearts.com. Upon saving “A Sunday Afternoon on the Island of La Grande Jatte,” we observe that the downloaded file matches the encrypted file’s name but with a .webp extension instead of .jpg.

We can calculate the SHA256 hash of the downloaded webp image to obtain the decryption key.

Linux

1$ sha256sum A_Sunday_Afternoon_on_the_Island_of_La_Grande_Jatte_by_Georges_Seurat_5773ff06-a03e-401b-8914-6106bc277bfd_large.webp 
280d60bddb3b57a28d7c7259103a514cc05507c7b9cf0c42d709bdc93ffc69191  A_Sunday_Afternoon_on_the_Island_of_La_Grande_Jatte_by_Georges_Seurat_5773ff06-a03e-401b-8914-6106bc277bfd_large.webp

Windows

1> Get-FileHash -Algorithm SHA256 -Path .\A_Sunday_Afternoon_on_the_Island_of_La_Grande_Jatte_by_Georges_Seurat_5773ff06-a03e-401b-8914-6106bc277bfd_large.webp
2Algorithm       Hash
3---------       ----
4SHA256          80d60bddb3b57a28d7c7259103a514cc05507c7b9cf0c42d709bdc93ffc69191

With this decryption key and the filepath to the victim-files folder, we can input them into the Decryptor executable.

blackcat2-decrypt

Opening “flag.txt.decry” in a text editor reveals the flag:

Keeping another flag here for safe keeping again!

flag{03365961aa6aca589b59c683eecc9659}

Miscellaneous - Who is Real?

This is not a technical challenge, but it is a good test of your eye!

Now we live in a world of generative AI, for better or for worse. The fact of the matter is, threat actors can scheme up fake personas to lure you into a scam or social engineering… so, can you determine which profile picture is real and which is fake?

Play a game to train yourself on identifying what stands out for AI generated people. After a streak of 10 correct selections, you’ll receive the flag!

We get a webpage where we need to choose between an AI-generated picture and a real picture. The method that worked best for me is to focus on the background as the AI pictures often have backgrounds that have little flaws in them, as you can see in the screenshot below.

flag-real

Miscellaneous - Indirect Payload

We saw this odd technique in a previous malware sample, where it would uncover it’s next payload by… well, you’ll see.

homepage-payload

We accessed a website featuring a button that redirects users to a “/flag.php” endpoint. Following this initial redirection, a series of subsequent redirects occurred, each leading to a distinct hash-based URL. Within the response of each redirection, a fragment of the flag was provided.

Request URL: http://chal.ctf.games:30483/site/flag.php
Status code: 302
Date: Wed, 18 Oct 2023 13:36:12 GMT
Location: /site/fe3cbf06ef09be78eb8ae144888eeeae.php
Response Content:

Redirecting to: http://chal.ctf.games:30483/site/fe3cbf06ef09be78eb8ae144888eeeae.php

Request URL: http://chal.ctf.games:30483/site/fe3cbf06ef09be78eb8ae144888eeeae.php
Status code: 302
Date: Wed, 18 Oct 2023 13:36:12 GMT
Location: /site/f99cc7e975c1fdfd1b803bd248bac515.php
Response Content:

Redirecting to: http://chal.ctf.games:30483/site/f99cc7e975c1fdfd1b803bd248bac515.php

Request URL: http://chal.ctf.games:30483/site/f99cc7e975c1fdfd1b803bd248bac515.php
Status code: 302
Date: Wed, 18 Oct 2023 13:36:13 GMT
Location: /site/0eb108f40ad71158d396d396e825fab7.php
Response Content:
character 0 of the payload is f

The Python script below helps navigate a website’s redirects and gather parts of a hidden flag from the response. By following the redirects, the script extracts characters from the response text, revealing the flag.

 1import requests
 2import sys
 3from urllib.parse import urljoin
 4
 5base_url = sys.argv[1]
 6url = urljoin(base_url, "site/flag.php")
 7flag = ''
 8while '}' not in flag:
 9    try:
10        response = requests.get(url, allow_redirects=False)
11        print(f"flag: {flag} - URL: {response.url}")
12        if response.text:
13            flag += response.text.split()[-1]
14
15        # Check if it's a redirect
16        if response.status_code == 302:
17            location = response.headers['Location']
18            url = urljoin(base_url, location)
19        else:
20            break  # Stop if it's not a redirect
21    except requests.exceptions.RequestException as e:
22        print(f"An error occurred: {e}")
23        break
24if flag:
25    print(f"FLAG FOUND: {flag}")

Output:

flag:  - URL: http://chal.ctf.games:32522/site/flag.php
flag:  - URL: http://chal.ctf.games:32522/site/fe3cbf06ef09be78eb8ae144888eeeae.php
flag:  - URL: http://chal.ctf.games:32522/site/f99cc7e975c1fdfd1b803bd248bac515.php
flag: f - URL: http://chal.ctf.games:32522/site/0eb108f40ad71158d396d396e825fab7.php
flag: f - URL: http://chal.ctf.games:32522/site/e318c81f0211a5b17060ddab1fcc8fb0.php
flag: fl - URL: http://chal.ctf.games:32522/site/bdbbadb4fe344b998f98ca54c2e97b01.php
...
...
...
flag: flag{448c05ab3e3a7d68e3509eb85e87206 - URL: http://chal.ctf.games:32522/site/bc3d27d4ea43d4da9464eb03d753db61.php
flag: flag{448c05ab3e3a7d68e3509eb85e87206f - URL: http://chal.ctf.games:32522/site/1fb764ff4dd3eb7bcfb0a3e7c064f975.php
flag: flag{448c05ab3e3a7d68e3509eb85e87206f - URL: http://chal.ctf.games:32522/site/b9e277d8277ae70b3402edff6a4a6764.php
FLAG FOUND: flag{448c05ab3e3a7d68e3509eb85e87206f}

Miscellaneous - Rock, Paper, Psychic

Wanna play a game of rock, paper, scissors against a computer that can read your mind? Sounds fun, right?

We can open the binary with IDA and go through the source code. In the main function, we see a jnz (jump if not zero) check that jumps to playerWins if it’s not zero otherwise it continues in main and calls computerWins.

rps-before

As the computer knows our choice, this check is always true and the computer always wins. We can patch the source code (Edit > Patch > Assemble) and change it to jz (jump if zero).

rps-after

We can now debug through the program (or apply the patches and run the patched exe file) and get the flag even though we lose.

rps-flag

Miscellaneous - Discord Snowflake Scramble

Someone sent message on a Discord server which contains a flag! They did mention something about being able to embed a list of online users on their own website…

Can you figure out how to join that Discord server and see the message?

Note: Discord phone verification is NOT required for this challenge.

Connect here: https://discord.com/channels/1156647699362361364/1156648139516817519/1156648284237074552

We get a discord link that redirects to an empty space.

discord-start

We have a URL with IDs. We can look around for tools that might give us more information about the discord server. We come across discordlookup.com (GitHub).

We can use the Snowflake IDs in the URL to retrieve this information. Discord uses Snowflake IDs to uniquely identify various entities like users, channels, servers, messages, and more.

In the URL that was provided (https://discord.com/channels/1156647699362361364/1156648139516817519/1156648284237074552), these IDs represent the following:

  • 1156647699362361364: Server (guild) ID.
  • 1156648139516817519: Channel ID.
  • 1156648284237074552: Message ID.

discord-lookup

We can follow the “Instant Invite URL” and gain access to the server that contains the flag message.

discord-flag

OSINT - Operation Not Found

We get a link to a challenge on osint.golf.

We see construction happening on a build by the company “Brasfield & Gorrie”. The picture seems to date from maps 2019.

We can go to their portfolio page and look through the different projects they have done.

Brasfield & Gorrie Blog Post Google Maps location

operation-notfound

OSINT - Under The Bridge

Can you find this iconic location? We again get a link to a challenge on osint.golf.

bridge

We can see a number on the bridge “HC13”, additionally, all the warning signs are in English, and the plates on the cars seem to indicate that this bridge is located in England. When we search “HC13 bridge England” we find out that this is the bridge that appears in the Rick Roll music video. This bridge is located on “150 Freston Rd, London”.

bridge

Steganography - Land Before Time

This trick is nothing new, you know what to do: iSteg. Look for the tail that’s older than time, this Spike, you shouldn’t climb.

The flag can be extracted using iSteg.

 1~/Downloads ➜ cd iSteg-v2.01_CLI
 2~/Downloads/iSteg-v2.01_CLI ➜ java -jar iSteg-v2.01_CLI.jar
 3iSteg CLI v-2.01
 4Enter your choice:
 5    1. Hide a file with Steg
 6    2. Hide a message with Steg
 7    3. Extract stuff from Steg
 8    Enter any things to exit.
 93
10Enter file name with extension: 
11dinosaurs1.png
12Password (Press enter if the steganographic data wasn't encrypted):
13
14Message extraction successful. The text is:
15flag{da1e2bf9951c9eb1c33b1d2008064fee}