Eternal Loop
4 minutos de lectura
Se nos proporciona un archivo ZIP llamado 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
Archivos incompensadores
El archivo ZIP se puede descomprimir con la contraseña 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
El resultado es otro archivo ZIP, que almacena otro archivo ZIP y está protegido con contraseña:
$ unzip 37366.zip
Archive:  37366.zip
[37366.zip] 5900.zip password:
Aquí, podemos deducir que la contraseña es el nombre del archivo ZIP almacenado dentro (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
Automatización
El procedimiento anterior se repite muchas veces, por lo que necesitaremos automatizar el proceso. El algoritmo es:
- Ejecutar unzipcon una contraseña incorrecta para ver el nombre de archivo ZIP interno
- Ejecutar Unzipcon la contraseña correcta
- Eliminar el archivo ZIP antiguo
- Continuar con el nuevo archivo ZIP
Decidí usar un programa en Go. Estas son las líneas relevantes:
// ...
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()
}
Si ejecutamos el programa anterior, tendremos esto:
$ go run solve.go
[+] Stage: 500
$ ls
6969.zip   'Eternal Loop.zip'   solve.go
Último archivo ZIP
Este último archivo ZIP almacena un archivo llamado DoNotTouch, y nuevamente está protegido con contraseña:
$ 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:
Esta vez, la contraseña no es DoNotTouch:
$ unzip -P DoNotTouch 6969.zip
Archive:  6969.zip
   skipping: DoNotTouch              incorrect password
Ataque de fuerza bruta
Intentemos encontrar la contraseña usando fcrackzip y rockyou.txt:
$ fcrackzip -uDp $WORDLISTS/rockyou.txt 6969.zip
PASSWORD FOUND!!!!: pw == letmeinplease
Ahí está, ahora podemos descomprimir el archivo:
$ 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
Hay una base de datos SQLite3 en DoNotTouch, la flag debe tiene que estar ahí. La mejor manera para encontrarla es usar 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}
Además, incluí todo el proceso en el programa en Go:
$ 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}
El script completo se puede encontrar aquí: solve.go.