Forensics Beginner Challenges Part 3 of 3

Let’s start the third and final installment of this series about solving forensics beginner challenges. If you haven’t, please visit part 1 . We’ll continue using this repo.

Challenge 11

Challenge 11 is called corrupted_docx. That should give us an idea of what we’re dealing with. The file is called docx.docx. Let’s verify if this is indeed a text document.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/11_corrupted_docx]
└─$ file docx.docx
docx.docx: Microsoft OOXML

It appears to be correct. Microsoft OOXML files are in essence .zip files with a specific structure, so let’s try to decompress the file to analyze its contents.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/11_corrupted_docx]
└─$ unzip docx.docx
Archive:  docx.docx
   creating: customXml/
  inflating: customXml/item1.xml
  inflating: customXml/itemProps1.xml
   creating: customXml/_rels/
  inflating: customXml/_rels/item1.xml.rels
   creating: docProps/
  inflating: docProps/app.xml
  inflating: docProps/core.xml
  inflating: docProps/custom.xml
   creating: word/
  inflating: word/document.xml
  inflating: word/fontTable.xml
  inflating: word/header1.xml
   creating: word/media/
  inflating: word/media/image1.png
  inflating: word/media/image10.png
  inflating: word/media/image11.png
  inflating: word/media/image12.png
  inflating: word/media/image13.png
  inflating: word/media/image14.png
  inflating: word/media/image2.png
  inflating: word/media/image3.png
  inflating: word/media/image4.png
  inflating: word/media/image5.png
  inflating: word/media/image6.png
  inflating: word/media/image7.png
  inflating: word/media/image8.png
  inflating: word/media/image9.png
  inflating: word/numbering.xml
  inflating: word/settings.xml
  inflating: word/styles.xml
   creating: word/theme/
  inflating: word/theme/theme1.xml
   creating: word/_rels/
  inflating: word/_rels/document.xml.rels
  inflating: word/_rels/header1.xml.rels
  inflating: [Content_Types].xml
   creating: _rels/
  inflating: _rels/.rels

After extracting the file, we obtain a long list of different files. There are 14 images. If we analyze them, we’ll notice that two of them appear to be broken. If we recover them, we’ll notice that they are dead-ends. To recover those images we can use techniques we have previously used, so they are a great exercise for the reader, which is why we won’t cover that process. We can try to grep for the flag structure, maybe we’ll find it that way.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/11_corrupted_docx/analysis]
└─$ grep -R -o -P '.{0,3}cercCTF.{0,40}' .
grep: ./docx.docx: binary file matches
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:b w:val="0"
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:b w:val="0"
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:b w:val="0"
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:b w:val="0"
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:b w:val="0"
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:b w:val="0"
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
./word/document.xml:s="cercCTF{ini_bukan_flagnya_loh}"/><w:sz w:val="1
./word/document.xml:i="cercCTF{ini_bukan_flagnya_loh}" w:hAnsi="cercCT
...

We appear to have found the flag. However, if we translate that flag, we’ll find that the text means “This is not the flag, you know”. So we are back to square one.

All of the results of that fake flag seem to originate from ./word/document.xml. So it might be a good idea to manually investigate that file. If we are patient and keep reading, we’ll find the following tag:

<flag>Y2VyY0NURntjb3JydXB0ZWRfdzFudzByZF9kYXRhX2VtYjNkZDNkX2luczFkZX0K</flag>

That text appears to be a base64 encoded string, so let’s decode it.


┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/11_corrupted_docx]
└─$ echo "Y2VyY0NURntjb3JydXB0ZWRfdzFudzByZF9kYXRhX2VtYjNkZDNkX2luczFkZX0K" | base64 -d
cercCTF{corrupted_w1nw0rd_data_emb3dd3d_ins1de}

Nice! We got the flag.

The flag is: cercCTF{corrupted_w1nw0rd_data_emb3dd3d_ins1de}

Challenge 12

Challenge 13 is called “titip absen katanya” which means “leave him absent, he said”. The file is called qr_absen.png which appears to be a QR code. Let’s scan it first.

Scanning the challenge's QR code
Scanning the challenge’s QR code

After scanning the code, we’ll get the following string:

NjM2NTcyNjM0MzU0NDY3YjZiNjU3MjZhNjEzNDZlNWY2YjMwNmI1Zjc0MzE3NDc5NzA1ZjYxMzgzNTY1CjZlNWY2ZDMwMzM2YzMwMzM1ZjZiNjE3MDM0NmU1ZjZjMzAzMzVmNjczNDZiNWY2YjMwNzI3NTcwNzMzMQo1ZjMwMzkzMjM2N2QwYQo=

It appears to be base64 encoded, so let’s decode it.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/12_titip_absen_katanya]
└─$ echo "NjM2NTcyNjM0MzU0NDY3YjZiNjU3MjZhNjEzNDZlNWY2YjMwNmI1Zjc0MzE3NDc5NzA1ZjYxMzgzNTY1CjZlNWY2ZDMwMzM2YzMwMzM1ZjZiNjE3MDM0NmU1ZjZjMzAzMzVmNjczNDZiNWY2YjMwNzI3NTcwNzMzMQo1ZjMwMzkzMjM2N2QwYQo=" | base64 -d
636572634354467b6b65726a61346e5f6b306b5f74317479705f61383565
6e5f6d30336c30335f6b6170346e5f6c30335f67346b5f6b307275707331
5f303932367d0a

We obtain a sequence of numbers that appear to be in hex. If we use Cyberchef with the from hex recipe , we’ll find our flag.

cercCTF{kerja4n_k0k_t1typ_a85en_m03l03_kap4n_l03_g4k_k0rups1_0926}
Getting the flag

In this case, the flag was not in English, so it might be a good idea to try and translate it. If we change it from l337 to regular letters, we get the following text kerjaan kok tityp absen moeloe kapan loe gak korupsi 0926. This means: Why don’t you always leave work when you’re not corrupt 0926. Nothing seems to indicate that this is not the flag. So we were successful.

The flag is cercCTF{kerja4n_k0k_t1typ_a85en_m03l03_kap4n_l03_g4k_k0rups1_0926}

Challenge 13

This challenge is called web key and the file we get is called encoded.pcapng. The .pcapng extension corresponds to a format that is used to save network captures, it comes from packet capture next generation. We can use Wireshark to open these types of files. Let’s open the file and analyze our findings.

Opening Wireshark
Opening Wireshark

After opening the file, we’ll notice that there are many HTTP requests. There are two visible ones, one POST request and a GET request. The POST request appears to be 103 bytes long, the other one seems to be 3512 bytes long, let’s inspect the longer one, it might be interesting.

To do so, let’s right-click the request, and in the pop-up menu let’s select “Follow > HTTP Stream”. Upon selecting that option, another window will open with that request in a more readable format.

Apache's welcome page
Apache’s welcome page

If we analyze it, we’ll find that it corresponds to the default Apache welcome page in Ubuntu systems. Let’s move on to the POST request, we can close the current “Follow HTTP Stream” for that request, and repeat the same process for the POST request we previously found.

The search bar of Wireshark might have changed to tcp.stream eq 0. We can delete that text and press enter to return to the complete contents of our file.

transmit=01100011
Analyzing the POST request

An interesting detail of this POST request is that it contains this payload: transmit=01100011. A variable called transmit and eight binary digits. Maybe those bits represent something in ASCII. The byte we found represents the letter c in ASCII.

This doesn’t mean too much, but our flags start with cercCTF. So this might mean something. Let’s filter our .pcapng file so that Wireshark only presents POST requests. We can use this filter http.request.method == “POST”.

Listing POST requests
Filtering POST requests

After applying the filter, we’ll note that there are many POST requests with the same length. If we analyze the following two requests, we’ll find the following bytes 01100101 and 01110010. Those bytes represent the characters ’e’ and ‘r’ respectively. This fits our theory that those bytes might form the flag.

Let’s automate this task by using a Python script. We’ll need to install a library called pyshark with the command pip3 install pyshark. Let’s analyze a way to automate the process.

import pyshark
import codecs

def extract_post_payloads(pcapng_file_path):
    # Load the pcapng file
    cap = pyshark.FileCapture(pcapng_file_path, display_filter='http.request.method == "POST"')
    flag = ""
    for packet in cap:
        try:
            http_layer = packet.http

            if hasattr(http_layer, 'file_data'):
                print("POST Request to:", http_layer.request_full_uri)
                print("Payload:")
                payload = http_layer.file_data.replace("\\r\\n", "\n")
                print(payload)
                decoded_payload=codecs.decode(payload.replace(":",""), 'hex').decode('utf-8')
                print(decoded_payload)
                str_byte=decoded_payload.replace("transmit=","")
                integer_value = int(str_byte, 2)
                # Convert the integer to a character
                character = chr(integer_value)
                print(character)
                flag = flag + character
                print("="*50)  # Separator for readability
        except AttributeError as e:
            print("Error processing packet:", e)
    print(flag)

pcapng_file_path = 'encoded.pcapng'
extract_post_payloads(pcapng_file_path)

The script reads the file and uses a loop to analyze every packet. If the packet represents a POST request, it prints it and extracts the byte after the transmit= string. With each byte represented as a string, it transforms it into an integer and then into a character.

Finally, the script concatenates each of those characters and when the loop finishes, the string presents what should be the flag. Let’s execute it and check the output.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/13_web_key]
└─$ python3 parser.py
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:31:31
transmit=01100011
c
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:31:30:31
transmit=01100101
e
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:30:31:30
transmit=01110010
r
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:31:31
transmit=01100011
c
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:30:30:30:31:31
transmit=01000011
C
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:31:30:31:30:30
transmit=01010100
T
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:30:30:31:31:30
transmit=01000110
F
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:31:30:31:31
transmit=01111011
{
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:31:30:30
transmit=01110100
t
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:30:31:30
transmit=01110010
r
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:30:31
transmit=01100001
a
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:31:31:30
transmit=01101110
n
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:30:31:31
transmit=01110011
s
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:31:30:31
transmit=01101101
m
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:30:30:31
transmit=01101001
i
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:31:30:30
transmit=01110100
t
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:31:31:31:31:31
transmit=01011111
_
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:30:31
transmit=01100001
a
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:30:31:31
transmit=01110011
s
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:31:31
transmit=01100011
c
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:31:30:30:30
transmit=01111000
x
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:30:30:31
transmit=01101001
i
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:31:31:31:31:31
transmit=01011111
_
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:31:30:30
transmit=01100100
d
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:30:31:31:30:31:30:30
transmit=00110100
4
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:31:30:30
transmit=01110100
t
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:30:31:31:30:31:30:30
transmit=00110100
4
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:31:31:31:31:31
transmit=01011111
_
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:31:30
transmit=01100010
b
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:31:30:31
transmit=01100101
e
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:30:30:30
transmit=01101000
h
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:30:31:31:30:30:30:31
transmit=00110001
1
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:31:31:30
transmit=01101110
n
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:31:30:30
transmit=01100100
d
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:31:31:31:31:31
transmit=01011111
_
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:30:30:31:30
transmit=01100010
b
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:30:31:31:30:30:30:31
transmit=00110001
1
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:31:31:30
transmit=01101110
n
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:30:31:31:30:31:30:30
transmit=00110100
4
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:30:31:30
transmit=01110010
r
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:31:30:30:31
transmit=01111001
y
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:30:31:31:31:31:31
transmit=01011111
_
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:31:31:30
transmit=01101110
n
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:31:30:31
transmit=01110101
u
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:30:31:31:30:31
transmit=01101101
m
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:30:30:31:31
transmit=01110011
s
==================================================
POST Request to: http://localhost/
Payload:
74:72:61:6e:73:6d:69:74:3d:30:31:31:31:31:31:30:31
transmit=01111101
}
==================================================
cercCTF{transmit_ascxi_d4t4_beh1nd_b1n4ry_nums}

After executing our script, we can note that the concatenation of all the bytes is our flag.

The flag is cercCTF{transmit_ascxi_d4t4_beh1nd_b1n4ry_nums}

Challenge 14

This challenge is named “least significant bit,” and the file involved is called least.png. This scenario hints at a straightforward approach: understanding and utilizing the Least Significant Bit (LSB) technique.

LSB steganography is a method used to hide information within the least significant bits of the pixel values in certain image files, notably those using lossless formats like .bmp and .png. This technique allows for the concealment of data without significantly altering the appearance of the image. It’s crucial to note that this method is not suitable for lossy formats such as jpg, as the compression process in such formats can modify or eliminate the least significant bits, potentially destroying the hidden information.

With that in mind, we’ll try to use a tool called zsteg which focuses on steganography on .png and .bmp files. Let’s run zsteg with the -a flag so that it tests all possible methods.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/14_least_significant_bit]
└─$ zsteg -a least.png
b1,r,lsb,xy         .. text: "_ :aS2_ 3j"
b1,r,msb,xy         .. text: "l@zHxHhhxHF"
b1,rgb,lsb,xy       .. text: "Sebelum mengirim astronot wanita pertama, Badan Penerbangan dan Antariksa Amerika Seirikat, NASA, berencana akan mendaratkan robot rover atau robot penjelajah tanpa awak seukuran mobil golf ke bulan. NASA berharap bisa mendaratkan rover bulan itu di kutub "
b1,rgba,msb,xy      .. file: OpenPGP Public Key
b1,abgr,msb,xy      .. file: OpenPGP Secret Key
...
b1,bgr,msb,Xy       .. text: "A askiratnA nad nagnabreneP nadaB ,amatrep atinaw tonortsa mirignem mulebeSep tobor uata revor tobor naktaradnem naka anacnereb ,ASAN ,takirieS akiremradnem asib parahreb ASAN .nalub ek flog libom narukues kawa apnat hajalejn adap ria rebmus iracnem kutnu "
...

Out of all of the possibilities zsteg tries, only two appear to have legible data. We find two paragraphs written in Indonesian.

After translating them into English, they say:

“Before sending the first female astronaut, the United States Aeronautics and Space Administration, NASA, plans to land a rover or unmanned robot explorer the size of a golf cart on the moon. NASA hopes to land the lunar rover on the poles”

The other one seems to be reversed, so after reversing it, its translation says:

“to search for water sources on a golf cart-sized unmanned rover to the moon. NASA hopes to be able to unite America, NASA, plans to land a rover robot or pe robot Before sending the first female astronaut, Aeronautics and Space Agency A”

Both seem to refer to NASA and Space, but they don’t contain the flag. An important detail to keep in mind about zsteg is that when it tests for all the possibilities, it doesn’t provide the complete output of every case, just a snippet. So let’s have it return the complete text of the first paragraph. To do this, we need the name of the payload, which is b1,rgb,lsb,xy.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/14_least_significant_bit]
└─$ zsteg -E b1,rgb,lsb,xy least.png
Sebelum mengirim astronot wanita pertama, Badan Penerbangan dan Antariksa Amerika Seirikat, NASA, berencana akan mendaratkan robot rover atau robot penjelajah tanpa awak seukuran mobil golf ke bulan. NASA berharap bisa mendaratkan rover bulan itu di kutub selatan bulan untuk mencari sumber air pada Desember 2022.

Pesawat ruang angkasa baru telah diumumkan pada Jumat (25/10/2019) di International Astronautical Congress, sebuah konferensi tahunan di mana banyak komunitas penerbang internasional berkumpul.
Rencananya Volatiles Investigating Polar Exploration Rover, atau VIPER, akan melakukan perjalanan beberapa mil di bulan selama 100 hari, mencari air di dalam permukaan bulan. Temuannya akan membantu NASA memilih tempat mengirim astronot sebagai bagian dari program Artemis yang bertujuan mengirimkan manusia kembali ke bulan. Badan antariksa ingin memilih lokasi pendaratan dengan banyak air es untuk digunakan sebagai sumber daya.

VIPER akan memiliki empat instrumen utama untuk mendeteksi air seperti Neutron Spectrometer System yang akan mendeteksi area basah di bawah permukaan. Setelah suatu daerah terlihat menjanjikan, rover akan mengerahkan mesin penggali TRIDENT untuk menggali ke dalam tanah. cercCTF{l34st_s1gnific4nt_bit_i5_n0t_lea57} Sementara itu dua instrumen lain akan menganalisis sampel tanah.

Dalam misi tersebut, VIPER akan mengumpulkan berbagai jenis tanah dari berbagai wilayah bulan, membiarkan para ilmuwan memetakan lokasi yang tepat sumber air berada.

Dengan misi Artemis yang dimulai pada tahun 2020-an, air akan menjadi sumber daya utama di bulan - dan endapan air es yang penting untuk umur panjang bagi manusia bermukim di luar angkasa. Tidak hanya air minum, dengan menambang air es para astronot mungkin dapat mengekstraksinya menjadi hidrogen dan oksigen yang kemudian akan digunakannya untuk membuat bahan bakar roket. Jika terealisasi maka hal itu bisa mengurangi jumlah bahan bakar dan pasokan yang harus dibawa astronot ke bulan, dan bahkan mendukung misi masa depan ke planet Mars.

If we read the complete output, we’ll find our flag!

The flag is cercCTF{l34st_s1gnific4nt_bit_i5_n0t_lea57}

Challenge 15

This challenge is called edihgets, if we reverse it we get steghide. Steghide is the name of a popular steganography tool that can hide content by using a password. The file is called file.jpg, if we verify that this is indeed a jpg and not a png or bmp image, it means that lsb is out of the question.

The goal of this challenge is to crack the file’s password. There’s a tool called stegcracker that can do this. However, when we run Stegcracker it recommends using stegseek instead.

Let’s try to crack the file’s password using a famous password dictionary called rockyou.txt. Usually, Kali VMs have this dictionary but it’s usually compressed, we can decompress it with gunzip /usr/share/wordlists/rockyou.txt.gz. Let’s proceed to try and crack the file with stegseek.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/15_edihgets]
└─$ stegseek -sf file.jpg -wl /usr/share/wordlists/rockyou.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek

[i] Progress: 99.94% (133.4 MB)
[!] error: Could not find a valid passphrase.

The dictionary we used failed. This means we might need a more specialized dictionary. If we check the image it contains a character called Asuna. We could try to create a custom dictionary by running cewl on a Wikia site that corresponds to that character. However, it wouldn’t work as that site does not contain the password we need.

Another option is to download another dictionary. We can download a repo called SecLists and use another wordlist.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/15_edihgets]
└─$ git clone https://github.com/danielmiessler/SecLists
Cloning into 'SecLists'...
remote: Enumerating objects: 17399, done.
remote: Counting objects: 100% (47/47), done.
remote: Compressing objects: 100% (44/44), done.
remote: Total 17399 (delta 6), reused 40 (delta 3), pack-reused 17352
Receiving objects: 100% (17399/17399), 1.15 GiB | 19.19 MiB/s, done.
Resolving deltas: 100% (9620/9620), done.
Updating files: 100% (5736/5736), done.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/15_edihgets]
└─$ stegseek -sf file.jpg -wl ./SecLists/Passwords/xato-net-10-million-passwords.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek

[i] Found passphrase: "unch"B)
[i] Original filename: "flag.txt".
[i] Extracting to "file.jpg.out".

After downloading the repo, we can execute stegseek again with the ./SecLists/Passwords/xato-net-10-million-passwords.txt file from SecLists. Upon executing the command, we found that the passphrase is unch. The image was hiding a file called flag.txt, and the tool extracted the contents to file.jpg.out. Let’s open the file and try to find our flag.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/15_edihgets]
└─$ cat file.jpg.out
WTJWeVkwTlVSbnR6ZERNNWFHbGtaVjlwTlY5aGJsODBjblI5Q2c9PQo=

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/15_edihgets]
└─$ cat file.jpg.out | base64 -d
Y2VyY0NURntzdDM5aGlkZV9pNV9hbl80cnR9Cg==

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/15_edihgets]
└─$ cat file.jpg.out | base64 -d | base64 -d
cercCTF{st39hide_i5_an_4rt}

After reading the file, we’ll find a text that appears to be a base64 encoded string. If we decode it, we’ll find another string that appears to be base64 encoded. If we decode it twice, we’ll get our flag.

The flag is cercCTF{st39hide_i5_an_4rt}

Challenge 16

The last challenge is called multi. Its name appears to be related to the fact that it contains multiple files rad.wav and undip.png.

To analyze .wav files we can use exiftool to find metadata. Also, in some cases, it’s possible to hide information in the audio’s spectrogram. Tools like Audacity can help us analyze the spectrogram. However, let’s start with the basics. Let’s use strings.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi]
└─$ strings rad.wav
RIFF@
WAVEfmt
data
password: unch$
...

After running strings, we find that there’s a password. It’s the same string that was used as a password in the previous challenge: unch. Let’s make a note of that, and continue with the image. Let’s check if the image has anything hidden inside it by using binwalk, we’ll also include -e to extract everything it may find.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi]
└─$ binwalk -e undip.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 381 x 446, 8-bit/color RGBA, non-interlaced
122           0x7A            Zlib compressed data, best compression

WARNING: Extractor.execute failed to run external extractor 'jar xvf '%e'': [Errno 2] No such file or directory: 'jar', 'jar xvf '%e'' might not be installed correctly
197062        0x301C6         Zip archive data, encrypted at least v2.0 to extract, compressed size: 19857, uncompressed size: 21548, name: a
216994        0x34FA2         Zip archive data, encrypted at least v2.0 to extract, compressed size: 8577, uncompressed size: 8828, name: b
225788        0x371FC         End of Zip archive, footer length: 22


┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi]
└─$ ll
total 744
drwxr-xr-x 2 jorge jorge   4096 Mar 30 15:00 _undip.png.extracted
-rw-r--r-- 1 jorge jorge 524360 Mar 20 22:18 rad.wav
-rw-r--r-- 1 jorge jorge 225810 Mar 20 22:18 undip.png

After running binwalk, we’ll find that there are hidden files inside the image. Let’s try to inspect inside the new directory called _undip.png.extracted that binwalk created.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi]
└─$ cd _undip.png.extracted

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi/_undip.png.extracted]
└─$ ll
total 924
-rw-r--r-- 1 jorge jorge  28748 Mar 30 15:00 301C6.zip
-rw-r--r-- 1 jorge jorge 680150 Mar 30 15:00 7A
-rw-r--r-- 1 jorge jorge 225688 Mar 30 15:00 7A.zlib

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi/_undip.png.extracted]
└─$ file 301C6.zip
301C6.zip: Zip archive data, at least v2.0 to extract, compression method=deflate

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi/_undip.png.extracted]
└─$ unzip 301C6.zip
Archive:  301C6.zip
[301C6.zip] a password:

If we enter the new directory, we’ll find a zip file, if we try to extract its contents it’ll prompt for a password. Let’s use unch.

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi/_undip.png.extracted]
└─$ unzip 301C6.zip
Archive:  301C6.zip
[301C6.zip] a password:
  inflating: a
  inflating: b

With that password, we’ll get two files, let’s analyze them both:

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi/_undip.png.extracted]
└─$ file a
a: JPEG image data, JFIF standard 1.01, aspect ratio, density 100x100, segment length 16, progressive, precision 8, 817x490, components 3

┌──(jorge㉿eternatus)-[~/forensics/forensic-beginner-challenges/16_multi/_undip.png.extracted]
└─$ file b
b: PNG image data, 739 x 74, 8-bit/color RGBA, non-interlaced

Both files appear to be images. The a file is an image that says “Congrats”. However, if we open b, we’ll find our flag.

cercCTF{comb1n3_teq_f0r_w1n5}
Getting the last flag

The flag is: cercCTF{comb1n3_teq_f0r_w1n5}

This was our final challenge from this repo. In the third part of this series, we analyzed a few steganography concepts and we also automated the extraction of a flag with Python from a network packet capture.

I hope you enjoyed these challenges, keep practicing.

Related Posts

Forensics Beginner Challenges Part 2 of 3

Forensics Beginner Challenges Part 2 of 3

Let’s start the second installment of this series about solving forensics beginner challenges.

Read More
Fixing Asymmetric Routing Issues in a Homelab

Fixing Asymmetric Routing Issues in a Homelab

Discovering the Asymmetric Routing Problem This week I wanted to improve the network monitoring strategy of my homelab.

Read More