Eternal Loop
4 minutes to read
We are given a ZIP file called Eternal Loop.zip
:
$ file Eternal\ Loop.zip
Eternal Loop.zip: Zip archive data, at least v2.0 to extract, compression method=store
$ du -h Eternal\ Loop.zip
452K Eternal Loop.zip
$ unzip -v Eternal\ Loop.zip
Archive: Eternal Loop.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
460611 Stored 460611 0% 05-23-2018 01:03 b74de99a 37366.zip
-------- ------- --- -------
460611 460611 0% 1 file
Decompressing archives
The ZIP archive can be decompressed with password hacktkebox
:
$ unzip -P hackthebox Eternal\ Loop.zip
Archive: Eternal Loop.zip
extracting: 37366.zip
$ file 37366.zip
37366.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
$ unzip -v 37366.zip
Archive: 37366.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
460340 Defl:N 460485 0% 05-23-2018 10:02 04db4f8a 5900.zip
-------- ------- --- -------
460340 460485 0% 1 file
The result is another ZIP archive, which stores yet another ZIP archive and is protected with password:
$ unzip 37366.zip
Archive: 37366.zip
[37366.zip] 5900.zip password:
Here, we can guess that the password is the name of the ZIP file stored inside (5900
):
$ unzip -P 5900 37366.zip
Archive: 37366.zip
inflating: 5900.zip
$ file 5900.zip
5900.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
$ unzip -v 5900.zip
Archive: 5900.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
460067 Defl:N 460212 0% 05-23-2018 10:02 3dda373a 49805.zip
-------- ------- --- -------
460067 460212 0% 1 file
Automation
The above procedure repeats a lot of times, so we will need to automate the process. The algorithm is:
- Call
unzip
with a wrong password to see the inner ZIP filename - Call
unzip
with the correct password - Remove the old ZIP file
- Continue with the new ZIP archive
I decided to use a program in Go. These are the relevant lines:
// ...
func main() {
r := regexp.MustCompile(`(skipping|inflating): (\d+)\.zip`)
output, _ := exec.Command("unzip", "-P", "xxx", "Eternal Loop.zip").CombinedOutput()
password := r.FindStringSubmatch(string(output))[2]
newPassword := "hackthebox"
stage := 1
exec.Command("unzip", "-P", newPassword, "Eternal Loop.zip").Run()
for {
output, _ := exec.Command("unzip", "-P", newPassword, password + ".zip").CombinedOutput()
matches := r.FindStringSubmatch(string(output))
if len(matches) == 0 {
break
}
newPassword = matches[2]
err := exec.Command("unzip", "-P", newPassword, password + ".zip").Run()
if err != nil {
exec.Command("rm", "-r", newPassword + ".zip").Run()
if exec.Command("unzip", "-P", newPassword, password + ".zip").Run() != nil {
break
}
}
exec.Command("rm", "-r", password + ".zip").Run()
password = newPassword
fmt.Printf("[+] Stage: %d\r", stage)
stage++
}
fmt.Println()
}
If we run the above program, we will have this:
$ go run solve.go
[+] Stage: 500
$ ls
6969.zip 'Eternal Loop.zip' solve.go
Last ZIP archive
This last ZIP archive stores a file called DoNotTouch
, and again it is protected with password:
$ unzip -v 6969.zip
Archive: 6969.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
884736 Defl:N 335169 62% 03-31-2018 07:54 e8183254 DoNotTouch
-------- ------- --- -------
884736 335169 62% 1 file
$ unzip 6969.zip
Archive: 6969.zip
[6969.zip] DoNotTouch password:
This time, the password is not DoNotTouch
:
$ unzip -P DoNotTouch 6969.zip
Archive: 6969.zip
skipping: DoNotTouch incorrect password
Password brute force
Let’s try to find the password using fcrackzip
and rockyou.txt
(brute force attack):
$ fcrackzip -uDp $WORDLISTS/rockyou.txt 6969.zip
PASSWORD FOUND!!!!: pw == letmeinplease
There it is, now we can decompress the archive:
$ unzip -P letmeinplease 6969.zip
Archive: 6969.zip
inflating: DoNotTouch
$ file DoNotTouch
DoNotTouch: SQLite 3.x database, last written using SQLite version 3021000, page size 1024, file counter 26, database pages 864, cookie 0x22, schema 1, UTF-8, version-valid-for 26
Flag
There is a SQLite3 database in DoNotTouch
, the flag must be stored there. The best way to find it is using strings
:
$ strings DoNotTouch | grep HTB
1969-01-01 00:00:002069-01-01 00:00:00Chillin with SatanHellHTB{z1p_and_unz1p_ma_bruddahs}
$ strings DoNotTouch | grep -oE 'HTB{.*?}'
HTB{z1p_and_unz1p_ma_bruddahs}
Additionally, I added all the process in the solution script:
$ go run solve.go $WORDLISTS/rockyou.txt
[+] Stage: 500
[*] Starting brute force attack
[+] Found password: letmeinplease
[*] Running `strings` on file 'DoNotTouch'
[+] Flag: HTB{z1p_and_unz1p_ma_bruddahs}
The full script can be found in here: solve.go
.