Note to fellow-HTBers: Only write-ups of retired HTB machines or challenges are allowed.

Challenge info

Eternal Loop [by MinatoTW]
Can you find a way out of this loop?

The challenge

We start of by downloading the Eternal_Loop.zip file and verifying it’s sha256sum with the hash displayed on the challenge page.

$ echo "4246a77b6ca2a2844749437d1a441fc759c6b8ec316187647cd9b1019da6f6fc Eternal_Loop.zip" | sha256sum -c -
Eternal_Loop.zip: OK

We then proceed to unzip this file using the password provided on the challenge page. This will give us a whole directory structure with multiple folders and files.

$ unzip Eternal_Loop.zip
Archive:  Eternal_Loop.zip
[Eternal_Loop.zip] 37366.zip password: 
 extracting: 37366.zip

This zip file contains another zip file, and is again password protected.

$ unzip -l 37366.zip 
Archive:  37366.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
   460340  2018-05-23 10:02   5900.zip
---------                     -------
   460340                     1 file

So we go ahead and crack the password. We follow the same path as we did for the fs0ciety challenge: create a hashfile and crack using john.

$ zip2john 37366.zip > 37366.zip.hash
ver 2.0 37366.zip/5900.zip PKZIP Encr: cmplen=460497, decmplen=460340, crc=4DB4F8A

$ john 37366.zip.hash 
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
5900             (37366.zip/5900.zip)
1g 0:00:00:00 DONE 1/3 (2019-09-04 12:18) 20.00g/s 320.0p/s 320.0c/s 320.0C/s z5900..Zip5900
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Note how the password is the same as the filename of the contained zip (5900).

This zip file again contains another zip file. We test using this zip’s filename as password to unzip the parent zip, and it works!

$ unzip -l 5900.zip 
Archive:  5900.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
   460067  2018-05-23 10:02   49805.zip
---------                     -------
   460067                     1 file

$ unzip 5900.zip 
Archive: 5900.zip
[5900.zip] 49805.zip password: 
 inflating: 49805.zip

Note that you can pass the unzip password using the -P parameter.

$ unzip -l 49805.zip 
Archive:  49805.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
   459794  2018-05-23 10:02   13811.zip
---------                     -------
   459794                     1 file
$ unzip -P 13811 49805.zip 
Archive:  49805.zip
  inflating: 13811.zip

Automation for the win!

By now, we know we can expect to have to unzip *a lot* of these password protected zip files. So let’s turn to automation.

We know the name of the contained zip will be the password. So we need to extract the filelist of the parent zip, extract the contained zip’s filename, pass this as a password and repeat the process for the contained zip.

My script might not be the prettiest, but with some simple grep’ing I was able to extract the filelist and use it as a password. I keep doing this until I get an unsuccessful unzip (status code != 0), which means I’ve probably reached the end.

#!/bin/bash

ZIPFILE=$1
RESULT=0

while [ $RESULT -eq 0 ]
do
PASSWORD=$( unzip -l $ZIPFILE | grep -E "^\s+[0-9]+" | grep -Eo "[0-9]+\.zip" | grep -Eo "[0-9]+" )
unzip -P "$PASSWORD" "$ZIPFILE"
RESULT=$?
echo "Unzipped $ZIPFILE using password $PASSWORD ($RESULT)"
ZIPFILE="$PASSWORD.zip"
done

Run the script, passing the filename of the last zip we manually unzipped and watch as dozens of lines flash by until we get an incorrect password.

$ ./unziprecursive.sh 13811.zip
Archive:  13811.zip
  inflating: 45133.zip               
Unzipped 13811.zip using password 45133 (0)
Archive:  45133.zip
[...]
Archive:  27833.zip
  inflating: 6969.zip                
Unzipped 27833.zip using password 6969 (0)
Archive:  6969.zip
   skipping: DoNotTouch              incorrect password
Unzipped 6969.zip using password  (82)

We now end up with 6969.zip which contains a file named DoNotTouch and who’s password is not “DoNotTouch”.

So back to cracking:

$ zip2john 6969.zip > 6969.zip.hash
$ john --wordlist=/usr/share/wordlists/rockyou.txt  6969.zip.hash 
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
letmeinplease    (6969.zip/DoNotTouch)
1g 0:00:00:00 DONE (2019-09-04 15:03) 10.00g/s 1392Kp/s 1392Kc/s 1392KC/s korn13..katiekatie
Use the "--show" option to display all of the cracked passwords reliably
Session completed
$ unzip -P letmeinplease 6969.zip 
Archive:  6969.zip
  inflating: DoNotTouch

This unzipped file appears to be a SQLite database file, as can be seen in the file header.

$ head DoNotTouch 
SQLite format 3@

Getting the flag

We could go ahead and browse the DB to look for the flag, but the DB contains quite a lot of …

$ sqlitebrowser DoNotTouch

… so let’s try something easier first ;)

$ strings DoNotTouch | grep HTB
1969-01-01 00:00:002069-01-01 00:00:00Chillin with SatanHellHTB{z1p_and_unz1p_ma_bruddahs}

And there we have it :)

HTB{z1p_and_unz1p_ma_bruddahs}