M0rsarchive
2 minutes to read
We are given these files:
$ file *
flag_999.zip: Zip archive data, at least v1.0 to extract, compression method=store
pwd.png: PNG image data, 25 x 3, 8-bit/color RGB, non-interlaced
Testing
The ZIP file is protected with password, and this is pwd.png
:
It’s quite hard to distinguish what’s encoded in the image, but it’s actually Morse code. This time, it contains “9”. We must guess that it’s the password for the ZIP archive:
$ unzip -P 9 flag_999.zip
Archive: flag_999.zip
extracting: flag/flag_998.zip
inflating: flag/pwd.png
So, we have another password-protected ZIP archive, and another pwd.png
image:
This time, the encoded word is “08”:
$ unzip -P 08 flag_998.zip
Archive: flag_998.zip
extracting: flag/flag_997.zip
inflating: flag/pwd.png
Automation
Alright, so we know how it works. We can assume that we need to do this task until we reach flag_1.zip
or flag_0.zip
. Therefore, we will need to automate it. For instance, we can use Python and OpenCV to analyze the images.
The general procedure will be:
- Analyze the image to extract Morse code
- Translate the Morse code
- Extract ZIP archive
Implementation
This is the relevant function:
def translate_to_morse(number: int) -> str:
dictionary = {1: '.', 3: '-'}
return dictionary.get(number, '')
def next_image(path: str) -> str:
img = cv2.imread(path)
dummy_pixel = img[0][0]
morse_code = []
for row in img:
morse_row_code = [0]
for pixel in row:
if (pixel == dummy_pixel).all():
if morse_row_code[-1] != 0:
morse_row_code.append(0)
else:
morse_row_code[-1] += 1
morse_row_code = [code for code in morse_row_code if code != 0]
if len(morse_row_code):
morse_code.append(''.join(map(translate_to_morse, morse_row_code)))
return ''.join(morse_alphabet.get(code, '') for code in morse_code).lower()
And this is main
, which loops until getting to the last file, which contains the flag:
def main():
path = './'
prog = log.progress('Depth')
for i in range(999, -1, -1):
prog.status(str(i))
password = next_image(f'{path}pwd.png')
os.system(f'unzip -P {password} -d flag{i} {path}flag_{i}.zip &>/dev/null')
path = f'flag{i}/flag/'
prog.success(str(i))
with open(f'{path}flag') as f:
log.success(f.read().strip())
os.system('rm -r flag[0-9]*')
It also performs some cleanup tasks to remove all ZIP archives and directories.
Flag
If we execute the script, we will get the flag:
$ python3 solve.py
[+] Depth: 0
[+] HTB{D0_y0u_L1k3_m0r53??}
The full script can be found in here: solve.py
.