Created
February 7, 2012 00:44
-
-
Save cwade12c/1756242 to your computer and use it in GitHub Desktop.
hash bruteforcer in ruby, supporting multiple attack vectors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/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