BozoCrack – MD5 Password Hash Cracker

BozoCrack is a depressingly effective MD5 password hash cracker with almost zero CPU/GPU load. Instead of rainbow tables, dictionaries, or brute force, BozoCrack simply finds the plaintext password. Specifically, it googles the MD5 hash and hopes the plaintext appears somewhere on the first page of results.
It works way better than it ever should.

How?
Basic usage:
$ ruby bozocrack.rb my_md5_hashes.txt
The input file has no specified format. BozoCrack automatically picks up strings that look like MD5 hashes. A single line shouldn’t contain more than one hash.
Example with output:
$ ruby bozocrack.rb example.txt
Loaded 5 unique hashes
fcf1eed8596699624167416a1e7e122e:octopus
bed128365216c019988915ed3add75fb:passw0rd
d0763edaa9d9bd2a9516280e9044d885:monkey
dfd8c10c1b9b58c8bf102225ae3be9eb:12081977
ede6b50e7b5826fe48fc1f0fe772c48f:1q2w3e4r5t6y
Why?
To show just how bad an idea it is to use plain MD5 as a password hashing mechanism. Honestly, if the passwords can be cracked with this software, there are no excuses.
Who?
BozoCrack was written by Juuso Salonen

                                                         (bozocrack.rb)                                                                       
                                                            BozoCrack

require 'digest/md5'
require 'net/http'
class BozoCrack
  def initialize(filename)
    @hashes = Array.new
    @cache = Hash.new
    File.new(filename).each_line do |line|
      if m = line.chomp.match(/\b([a-fA-F0-9]{32})\b/)
        @hashes << m[1]
      end
    end
    @hashes.uniq!
    puts "Loaded #{@hashes.count} unique hashes"
    load_cache
  end
  def crack
    @hashes.each do |hash|
      if plaintext = @cache[hash]
        puts "#{hash}:#{plaintext}"
        next
      end
      if plaintext = crack_single_hash(hash)
        puts "#{hash}:#{plaintext}"
        append_to_cache(hash, plaintext)
      end
      sleep 1
    end
  end
  private
  def crack_single_hash(hash)
    response = Net::HTTP.get URI("http://www.google.com/search?q=#{hash}")
    wordlist = response.split(/\s+/)
    if plaintext = dictionary_attack(hash, wordlist)
      return plaintext
    end
    nil
  end
  def dictionary_attack(hash, wordlist)
    wordlist.each do |word|
      if Digest::MD5.hexdigest(word) == hash.downcase
        return word
      end
    end
    nil
  end
  def load_cache(filename = "cache")
    if File.file? filename
      File.new(filename).each_line do |line|
        if m = line.chomp.match(/^([a-fA-F0-9]{32}):(.*)$/)
          @cache[m[1]] = m[2]
        end
      end
    end
  end
  def append_to_cache(hash, plaintext, filename = "cache")
    File.open(filename, "a") do |file|
      file.write "#{hash}:#{plaintext}\n"
    end
  end
end
if ARGV.size == 1
  BozoCrack.new(ARGV[0]).crack
else
  puts "Usage example: ruby bozocrack.rb file_with_md5_hashes.txt"
end

No comments:

Post a Comment