Disclaimer, I am not a professional programmer. Everything in this article was done as a learning exercise and could possibly be done better in many ways. Success with this code is not guaranteed!
main.py
This project originally started a long time ago after reading Violent Python. For those not familiar, Violent Python is a book about using python for hacking, pentesting, and forensic analysis. In this book there was a simple script on how to crack a zip file using a wordlist in python (https://github.com/igniteflow/violent-python/blob/master/pwd-crackers/zip-crack.py).
This script is incredibly simple, but also painfully slow and does not handle large wordlists or special chars well. For the python aficionados out there some of these problems are easily fixed by threading and passing some encoding arguments to open() (https://github.com/BuckarewBanzai/ZipCrackV2/blob/master/zipcrack.py). Unfortunately, python threading has its limits thanks to GIL (Global Interpreter Lock). This began the search for something faster…
main.go
Enter Golang. Even in a single threaded prototype, an identical golang zip cracker compared to the violent python example was substantially faster.
//Lets parse our cmd flags
filePtr := flag.String("zip", "", "Path to zip file.")
wordlistPtr := flag.String("wordlist", "", "Path to wordlist.")
flag.Parse()
if *filePtr == "" {
log.Fatal("Zip file not found.")
}
if *wordlistPtr == "" {
log.Fatal("Wordlist not found.")
}
log.Printf("Contending %s against %s", *filePtr, *wordlistPtr)
r, err := zip.OpenReader(*filePtr) //Open our zipfile with a method from "github.com/alexmullins/zip"
if err != nil {
log.Fatal(err)
}
defer r.Close() //close our file when done
file, _ := os.Open(*wordlistPtr) //open the wordlist sent via cmd line
fscanner := bufio.NewScanner(file) // Iterate over each line in the file
for fscanner.Scan() {
for _, f := range r.File { //For every word in the wordlist attempt to decrypt the zip file
f.SetPassword(fscanner.Text())
rc, err := f.Open()
if err != nil {
continue
}
rc.Close()
r.Close()
elapsed := time.Since(start)
log.Printf("Found password: %s in %s", fscanner.Text(), elapsed)
os.Exit(0)
}
}
}
routines.go
By nature password cracking is a easy job to parallelize and as fast as go is we can do more work by using routines. First we have to split our decrypt work out into its own function. After this, implementing routines is trivial.
func decrypt(zipFile string, password string) {
r, err := zip.OpenReader(zipFile)
if err != nil {
log.Fatal(err)
}
defer r.Close()
for _, f := range r.File {
f.SetPassword(password)
rc, err := f.Open()
if err != nil {
continue
}
buf, err := ioutil.ReadAll(rc)
if err != nil {
continue
}
rc.Close()
r.Close()
elapsed := time.Since(start)
log.Printf("Size of %v: %v byte(s)\n", f.Name, len(buf))
log.Printf("!============= Found password: %s in %s =============!", password, elapsed)
os.Exit(0)
}
}
This is what the code in our main program should now look like. Much cleaner right?
file, _ := os.Open(*wordlistPtr)
fscanner := bufio.NewScanner(file)
for fscanner.Scan() {
go decrypt(*filePtr, fscanner.Text())
}
}
We can see now that the script is capable of saturating all cores/threads on the machine.
This was a fun exercise in Go programming and go routines. As well as the script works it still has limitations such as you can only decrypt AES256 encrypted zip files and there are no forms of throttling. Also there are much faster options such as JTR. Eventually I would like to add metrics such as percetage complete and words per second. Also would like to build out the ability to make a cracking cluster. Thanks for reading! The current code can be found here: (https://github.com/BuckarewBanzai/ZipCrack-Go)
comments powered by Disqus