Skip to content

Instantly share code, notes, and snippets.

@cwade12c
Created February 7, 2012 00:44
Show Gist options
  • Save cwade12c/1756242 to your computer and use it in GitHub Desktop.
Save cwade12c/1756242 to your computer and use it in GitHub Desktop.
hash bruteforcer in ruby, supporting multiple attack vectors
#/usr/bin/ruby
=begin
@bin hashmilker -- by cwade12c 20 February 2012
@site https://haxme.org
@version v1.3.2
@description Bruteforcer via wordlist and other [OPTIONS]. Support for multiple hash algorithms
=end
#housecleaning
require 'digest'
require 'net/http'
require 'optparse'
require 'rexml/document'
class HM
#construct (wordlist, hash algorithm, hash checksum)
def initialize( checksum, file )
#Options array
@options = {}
#list,hash properties (strings)
@list = file
@hash = checksum
#configurables
@charmap = ( 'a'..'z' ).to_a + ( 'A'..'Z' ).to_a + ( '0'..'9' ).to_a
@max = 5
@URL = "http://cwade12c.darchoods.net/md5.php?hash="
#source : https://gist.github.com/1335484
#create new OptionParser object (for cli switches)
rbParse = OptionParser.new do |op|
op.banner = "Usage: ruby hashmilker.rb <hash> <list> [-a ALGORITHM | -b [MAX] | -s SALT | -v]"
#-a
@options[ :alg ] = "md5"
op.on( '-a', '--optional [ALG]', 'Define hash algorithm' ) do |a|
@options[ :alg ] = a
end
#-b
@options[ :brute ] = false
op.on( '-b', '--brute [BRUTE]', 'CPU bruteforce fallback' ) do |m|
@options[ :brute ] = ( m.to_i > 0 ? m.to_i : @max )
end
#-h
op.on( '-h', '--help', 'Display help' ) do
puts op.banner
exit(0)
end
#-s
@options[ :salt ] = false
op.on( '-s', '--optional [SALT]', 'Append a salt' ) do |s|
@options[ :salt ] = s
end
#-v
@options[ :verbose ] = false
op.on( '-v', '--verbose', 'Output more info' ) do
@options[ :verbose ] = true
end
end
#look for switches
rbParse.parse!
#raise opt exceptions
if @options[ :alg ].nil? || @options[ :salt ].nil?
puts "See: ruby hashmilker.rb --help"
raise OptionParser::MissingArgument
exit(0)
end
#get timestamp (just in case --verbose == true)
@t1 = Time.now
#check for valid hash
if !@options[ :alg ].match(/\A(md5|sha256|sha512)\Z/) || @hash.length < 32
puts "Enter a valid hash..."
exit(0)
end
#puts credits
self.credits
#multithreading methods
t1 = Thread.new{ self.setList }
t1.abort_on_exception = true
t2 = Thread.new{ self.netCheck( @hash ) }
t2.abort_on_exception = true
t1.join
t2.join
end
#wordlist sifting method
def setList
list = "#{@list}"
#main,exception
begin
if @options[ :verbose ]
#count lines for --verbose purposes
w = IO.readlines( list ).size
puts "--verbose mode enabled...\nLoading #{list} with ~ #{w} words\n\n"
if @options[ :salt ] != false
puts "Appending salt . #{@options[ :salt ]}\n "
end
end
#instead of adding to array, just read the lines through a method directly
f = IO.foreach( list ) { |word| self.compare( word.strip ) }
puts "wordlist [FAIL]"
#if no hash found, fallback to bruteforce in new thread (IF -b)
if @options[ :brute ] != false
t3 = Thread.new{ self.brute }
t3.join
end
#exception
rescue => e
puts "Exception : #{e}"
e
end
end
#compare calculated string to hash method
def compare( word, target=@hash, salt=@options[ :salt ] )
#are we using a salt?
if @options[ :salt ] != false
if self.calcHash( word << salt.strip ) == target
#cleanup
word.slice! salt
puts "#{target} : #{word} (with salt #{salt})"
if @options[ :verbose ]
time = Time.now - @t1
puts "Done! Completed in ...... #{time} seconds!"
end
exit
end
else
if self.calcHash( word ) == target
puts "#{target} : #{word}"
if @options[ :verbose ]
time = Time.now - @t1
puts "Done! Completed in ...... #{time} seconds!"
end
exit(0)
end
end
end
#calculate hash based param[1] algorithm
def calcHash( string, alg=@options[ :alg ] )
#CONSTANT method
case alg.upcase
when "MD5"
return Digest::MD5.hexdigest( string.strip )
when "SHA1"
return Digest::SHA1.hexdigest( string.strip )
when "SHA256"
return Digest::SHA256.hexdigest( string.strip )
when "SHA512"
return Digest::SHA512.hexdigest( string.strip )
else
return Digest::MD5.hexdigest( string.strip )
end
end
#reverse hash lookup method
def netCheck( string )
#Only supports md5 atm... so we'll check for it
if @options[ :alg ].downcase == 'md5'
#new REXML, using HTTP get method and parsing result
xml = REXML::Document.new( Net::HTTP.get( URI.parse( @URL << string ) ) )
if REXML::XPath.first( xml, "//md5lookup" )
puts "#{@hash} : " << xml.root.elements[ "//string" ].text
if @options[ :verbose ]
time = Time.now - @t1
puts "Done! Completed in ...... #{time} seconds!"
end
exit(0)
else
puts "reverse lookup [FAIL]"
end
end
end
#bruteforce method - max length,target hash
def brute( max=@options[ :brute ], hash=@hash )
puts "Falling back to bruteforce"
( 0 .. max ).each { |k|
recurse( 0, k, '' )
}
puts "bruteforce [FAIL]"
end
#recursive method (based off of my php md5 bruteforcer : http://tinyurl.com/7t6audt)
def recurse( pos, wid, str )
( 0 .. @charmap.length ).each { |n|
pass = "#{str}#{@charmap[n]}"
#is current position less than max?
if pos < wid - 1
#repeat
recurse( pos + 1, wid, pass )
end
self.compare( pass )
}
end
#credits method
def credits
puts "\n#hashmilker by cwade12c\n#https://haxme.org\n#Community Coding #1\n\n"
end
end
#make sure script is being used correctly
if ARGV.length < 2
if ARGV[0].nil? || !ARGV[0].match(/\A(-h|--help)\Z/)
puts 'See: ruby hashmilker.rb --help'
exit(0)
end
end
Apeling = HM.new( ARGV[0], ARGV[1] )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment