# [Misc & Forensics] KCSC RECRUITMENT 2026
# Miscs
It's Misc but it's Forensics?
# Mirage Remnant

**Description**
Just some leftover...
**Solution**
The challenge gives me a text file
```
$ cat Mirage_Remnant
ZmxhZy56aXAvZmxhZy50eHQ6JHBremlwJDEqMioyKjAqNDEqMzUqMTRjYjg1NDcqMCo0MiowKjQxKjhhZDYqYjVhOTU0OGNjNDYyNjhiYTc3N2M2OTQxYTRjNzA4NjgwYTBiYmJhZjI1NWM0M2UyMzk4ODIwNThhNGU3MWMzOGMzMzViNjE2YTdhZDZmOWQ3ZTc0ZDdhZmI5Njg0MGQ1NjJlNjE3MTkzNzNmM2FiZTJjMjA3MWFmZTlmYmI5OTE3ZCokL3BremlwJDpmbGFnLnR4dDpmbGFnLnppcDo6ZmxhZy56aXA=
```
This is base64 encoding so I just decode it in a normal way and have a HASH of a zip archive

As usual, whenever I am given this type of hash, I try to crack the password using John the Ripper
```
$ john try.txt --wordlist=rockyou.txt
```

The password is `hejhej` =)) but where is the zip archive to extract???
I have another hint from author: Reverse Thinking. So I guess instead of zip archive -> hash (-> extract archive), it is hash -> zip archive (-> extract archive). Honestly, this is the first time I've thought of it, I put a lot of effort into searching for the solution and finally I came up with a Python script which is used to reconstruct a zip archive. I customize it accroding to the given challenge
```
import sys
import struct
import binascii
def create_zip(hash_file, output_zip) :
with open(hash_file, "r", encoding="utf-8") as f:
line = f.read().strip()
# --- Step 1: Parse the hash using a new, more reliable logic ---
# take part before first ':'
filename_part = line.split(":", 1)[0]
filename = filename_part.split("/")[-1].encode("utf-8")
# remove $pkzip$ to get the hash core
core = line.split("$pkzip$")[1].split("*$/pkzip$")[0]
fields = core.split("*")
#compressed_size : field 4. 41 -> 65 bytes (53 + 12 bytes ZipCrypto header)
comp_size = int(fields[4], 16)
# uncompressed_size: field 5. 35 -> 53 bytes -> flag.txt has 53 bytes
uncomp_size = int(fields[5], 16)
# crc32: field 6
crc32 = int(fields[6], 16) # 0x14cb8547
# Guess DOS date/time from fields
dos_date = int(fields[8], 16) if len(fields) > 8 else 0
dos_time = int(fields[11], 16) if len(fields) > 11 else 0
# data_blob: the last field (the long hex string)
data_blob_hex = fields[-1]
data_blob = binascii.unhexlify(data_blob_hex)
print(f"[+] Hash parsing successful:")
print(f" Filename: {filename.decode()}")
print(f" Uncompressed Size: {uncomp_size} bytes")
print(f" Data Blob Size (Compressed): {comp_size} bytes")
if len(data_blob) != comp_size:
print(f"[!] Warning: blob length {len(data_blob)} != comp_size {comp_size}")
# --- Step 2: Construct the ZIP archive using strict specifications ---
GPBF = 0x0001 | 0x0008 # bit0=encrypted, bit3=data descriptor -> 0x0009
with open(output_zip, "wb") as f:
# --- Local File Header ---
local_header_offset = 0 # To be used in Central Directory
f.write(b"PK\x03\x04") # signature
f.write(struct.pack("<H", 20)) # version needed
f.write(struct.pack("<H", GPBF)) # flags: encrypted + data descriptor
f.write(struct.pack("<H", 0)) # method: store
f.write(struct.pack("<H", dos_time)) # mod time
f.write(struct.pack("<H", dos_date)) # mod date
# Because bit3 is set, these are typically 0 in local header
f.write(struct.pack("<I", 0)) # crc32 (0 here)
f.write(struct.pack("<I", 0)) # compressed size (0 here)
f.write(struct.pack("<I", 0)) # uncompressed size (0 here)
f.write(struct.pack("<H", len(filename)))
f.write(struct.pack("<H", 0)) # extra length
f.write(filename)
# file data (ZipCrypto header + encrypted data)
f.write(data_blob)
f.write(b"PK\x07\x08")
f.write(struct.pack("<I", crc32))
f.write(struct.pack("<I", comp_size))
f.write(struct.pack("<I", uncomp_size))
# --- Central Directory File Header ---
central_dir_offset = f.tell() # Offset of this header from start of archive
f.write(b"PK\x01\x02")
f.write(struct.pack("<H", 0x0314)) # version made by
f.write(struct.pack("<H", 20)) # version needed
f.write(struct.pack("<H", GPBF)) # general purpose bit flag
f.write(struct.pack("<H", 0)) # method
f.write(struct.pack("<H", dos_time)) # mod time
f.write(struct.pack("<H", dos_date)) #mode date
f.write(struct.pack("<I", crc32))
f.write(struct.pack("<I", comp_size))
f.write(struct.pack("<I", uncomp_size))
f.write(struct.pack("<H", len(filename)))
f.write(struct.pack("<H", 0)) # extra filed length
f.write(struct.pack("<H", 0)) # comment length
f.write(struct.pack("<H", 0)) # disk number
f.write(struct.pack("<H", 0)) # internal attributes
f.write(struct.pack("<I", 0)) # external attributes
f.write(struct.pack("<I", local_header_offset)) # offset of local header
f.write(filename)
central_dir_end = f.tell() # Offset of this header from start of archive
central_dir_size = central_dir_end - central_dir_offset
f.write(b"PK\x05\x06")
f.write(struct.pack("<H", 0))
f.write(struct.pack("<H", 0))
f.write(struct.pack("<H", 1))
f.write(struct.pack("<H", 1))
f.write(struct.pack("<I", central_dir_size)) # Size of central directory
f.write(struct.pack("<I", central_dir_offset)) # Offset of central directory
f.write(struct.pack("<H", 0)) # ZIP file comment length
print(f"[+] Success! File '{output_zip}' was created using the new method.")
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <hash_file> <out.zip>")
sys.exit(1)
create_zip(sys.argv[1], sys.argv[2])
```
But do you wonder how does this script work? I've commented carefully in the code =)), check this out.
(For my better understading, I also referenced: https://en.wikipedia.org/wiki/ZIP_(file_format) - highly recommend reading this)
Finally, run the script with the beginning hash file

Ok, now I'm having the original archive, just open it up

# ?

**Description**
Are you more Passive or Active?
**Solution**
```
wireshark Challenge.pcapng
```

Initially analysing, I guessed I could collect every single one-word character that shows up to decode but i failed when decoding it. There's must be another way to use these things
Given FTP Protocol and the hint : Passive or Active -> the challenge leads me to *Passive Mode FTP* and *Active Mode FTP*
> A PASSIVE file transfer is one where the ftp client will request, by the PASV command, that the ftp server tell it what port it is listening on. Then the ftp client will initiate opening the data connection to that specified port. The ftp server will do this by sending a "227 entering Passive Mode" message to the client. In this 227 message is the ip/port to connect to.
https://www.ibm.com/support/pages/ftp-deeper-look-passive-file-transfer
> An ACTIVE file transfer is one where the ftp client will request, by the PORT command, that the ftp server initiate opening the data connection. The ftp server will do this by connecting to the client on a tcp port that the client is listening on.
https://www.ibm.com/support/pages/ftp-deeper-look-active-file-transfer
In this challenge:
227: Entering Passive Mode
200: (Refering to) Active Mode
I follow TCP stream to get info and data transfered, copy all this and write a python script to split data transfered in active mode and passive mode

```
char ="""
220
227
150
R
226
227
150
1
226
227
150
F
226
227
150
1
226
200
150
M
226
227
150
d
226
227
150
X
226
227
150
V
226
227
150
1
226
200
150
5
226
200
150
Y
226
227
150
d
226
227
150
X
226
200
150
T
226
227
150
V
226
200
150
d
226
227
150
Y
226
200
150
l
226
227
150
X
226
200
150
N
226
227
150
0
226
200
150
j
226
200
150
g
226
227
150
5
226
200
150
1
226
227
150
5
226
200
150
N
226
227
150
Y
226
200
150
D
226
227
150
W
226
227
150
F
226
227
150
u
226
227
150
X
226
227
150
z
226
227
150
F
226
200
150
J
226
227
150
z
226
200
150
j
226
200
150
M
226
227
150
X
226
200
150
T
226
227
150
0
226
200
150
g
226
200
150
2
226
200
150
N
226
200
150
2
226
227
150
N
226
200
150
M
226
200
150
5
226
200
150
Z
226
200
150
T
226
227
150
1
226
200
150
l
226
227
150
d
226
227
150
D
226
227
150
N
226
227
150
f
226
200
150
i
226
200
150
Z
226
200
150
T
226
227
150
M
226
227
150
z
226
227
150
Z
226
200
150
Q
226
227
150
h
226
200
150
5
226
227
150
Y
226
200
150
M
226
200
150
j
226
200
150
g
226
200
150
4
226
200
150
Z
226
227
150
j
226
200
150
D
226
200
150
U
226
200
150
=
226
221
"""
passive = ""
active = ""
lines = [ln.strip() for ln in char.splitlines() if ln.strip()]
print(len(lines))
for i in range (306):
if (lines[i]=="227"):
passive+=lines[i+2]
elif (lines[i]=="200"):
active+=lines[i+2]
print(passive+active)
```
The result is: `R1F1dXV1dXVYX055YWFuXzFzX0N1dDNfMzZhYjM5YTdlNjg1NDJjMTg2N2M5ZTliZTQ5Mjg4ZDU=`
Flag: `KCSC{GQuuuuuuX_Nyaan_1s_Cut3_36ab39a7e68542c1867c9e9be49288d5}`
Reference: https://www.youtube.com/watch?v=8X-DZUIZa94
# 2n0is3

**Description**
Noise goes brrrrr...
**Solution**
I open the image given but i can't see anything, it must be corrupted
```
$ pngcheck 2n0is3.png
2n0is3.png this is neither a PNG or JNG image nor a MNG stream
ERROR: 2n0is3.png
```
I do some basic image check and I find out that there's no magic bytes =))

I add magic bytes to it
```
$ printf '\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0d\x49\x48\x44\x52' | cat - 2n0is3.png > noise.png
```

and now the image can be opened

I guess there's must be something is hidden under this image so I check for it and my assumption is right:
- Forensically: https://29a.ch/photo-forensics/#forensic-magnifier

The problem here is how can I discover these things...
"Use this tool":
https://piellardj.github.io/stereogram-solver/

# Forensics
# Hide & Seek: Exfiltration

**Description**
We detected some suspicious activities on our network. Seek them out
**Solution**
The challenge name is "Exfiltration", which reminds me immidiately to data exfiltrated via DNS so i check for DNS traffic.
Scrolling down... I come across some suspicious strings appearing before tiktok.com.

I gather them together and try to decode it
```
$ tshark -r challenge.pcapng -T fields -e dns.qry.name \
| grep tiktok.com \
| sed 's/\.tiktok\.com//' \
| uniq \
| tr -d '\n' > data
$ cat data
```

and here is the flag

# C3nt3ll4 RB18x2

**Description**
Something between 18 and three.six, can u "see" ?
**Solution**
According to the hint: "Something between 18 and three.six", I focus on ICMP Protocol, which sends messages from 1.1.1.18 to 1.2.3.6

After scrolling down and then achiving nothing, I end up with a conclusion that I may need to a find way to gather these data and make something more relevant. I try to find some magic numbers here =)

I copy data to a file and I got a hex string. Decode it:
```
$ xxd -r -p data > file
$ file file
file: RAR archive data, v5
```

This file is encrypted. I use john to see the password: `princess36` =)))
```
$ rar2john file > hash
$ john hash --wordlist=/usr/share/wordlists/rockyou.txt
$ john --show hash
```

This is the sign warning me to collect more data
```
$ tshark -r Pennywort.pcap -Y 'icmp.type==8 && icmp.ident==0x1337 && ip.src==1.1.1.18 && ip.dst==1.2.3.6' \
-T fields -E separator=$'\t' -e icmp.seq -e icmp.data > data
$ sort -n -k1,1 data | awk -F'\t' '{printf "%s",$2}' > finaldata
$ xxd -r -p finaldata data.rar
$ unrar x -kb data.rar
```
Finally, I get Flag.wav
https://sstv-decoder.mathieurenaud.fr/