ruby_hashcat 0.1.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/README.md +3 -3
- data/lib/ruby_hashcat.rb +20 -0
- data/lib/ruby_hashcat/api.rb +22 -0
- data/lib/ruby_hashcat/objects/hash.rb +419 -0
- data/lib/ruby_hashcat/objects/init.rb +2 -0
- data/lib/ruby_hashcat/parse.rb +245 -0
- data/lib/ruby_hashcat/program.rb +12 -3
- data/lib/ruby_hashcat/routes/clean.rb +23 -0
- data/lib/ruby_hashcat/routes/crack.rb +85 -0
- data/lib/ruby_hashcat/routes/init.rb +7 -0
- data/lib/ruby_hashcat/routes/results.rb +25 -0
- data/lib/ruby_hashcat/routes/settings.rb +26 -0
- data/lib/ruby_hashcat/routes/status.rb +44 -0
- data/lib/ruby_hashcat/task.rb +12 -3
- data/lib/ruby_hashcat/tee.rb +11 -0
- data/lib/ruby_hashcat/tmp/.touch +0 -0
- data/lib/ruby_hashcat/tools.rb +42 -0
- data/lib/ruby_hashcat/validation.rb +4 -0
- data/lib/ruby_hashcat/version.rb +1 -1
- data/ruby_hashcat.gemspec +11 -6
- data/test/hashes/md5.txt +6494 -0
- data/test/hashes/md5crypt.txt +2 -0
- data/test/hashes/phpass.txt +1 -0
- data/test/rules/InsidePro-PasswordsPro.rule +3275 -0
- data/test/rules/best64.rule +103 -0
- data/test/test_api.rb +188 -0
- data/test/test_library.rb +90 -0
- data/test/test_results.rb +5 -0
- data/test/test_status.rb +7 -0
- data/test/test_wrapper.rb +61 -0
- data/test/tmp/automat.txt +2 -0
- data/test/tmp/cracked.pot +2906 -0
- data/test/tmp/stdout.txt +696 -0
- data/test/wordlists/wordlist.dict +129988 -0
- metadata +108 -8
@@ -0,0 +1,245 @@
|
|
1
|
+
path = File.dirname(__FILE__)
|
2
|
+
require "#{path}/tools"
|
3
|
+
|
4
|
+
###########################################################################
|
5
|
+
# Author: Coleton Pierson #
|
6
|
+
# Company: Praetorian #
|
7
|
+
# Date: August 20, 2014 #
|
8
|
+
# Project: Ruby Hashcat #
|
9
|
+
# Description: Main parser class. Parses ocl stdout and pot file. #
|
10
|
+
###########################################################################
|
11
|
+
|
12
|
+
module RubyHashcat
|
13
|
+
module Parse
|
14
|
+
|
15
|
+
###########################################################################
|
16
|
+
# @method RubyHashcat::Parse.stdout(file) #
|
17
|
+
# @param file: [String] Path to oclHashcat stdout file #
|
18
|
+
# @description Parses the oclHashcat stdout file into hashes. #
|
19
|
+
# @return [Array][Hash] Array of Hashes with oclHashcat status. #
|
20
|
+
###########################################################################
|
21
|
+
def self.stdout(file)
|
22
|
+
array = []
|
23
|
+
return array unless File.exists?(file)
|
24
|
+
placement = -1
|
25
|
+
string = []
|
26
|
+
File.open(file).each_line do |x|
|
27
|
+
string << x
|
28
|
+
end
|
29
|
+
string.each do |line|
|
30
|
+
if line.include?('Session.Name.')
|
31
|
+
placement += 1
|
32
|
+
array[placement] = {}
|
33
|
+
elsif placement < 0
|
34
|
+
next
|
35
|
+
elsif line.include?('Status.')
|
36
|
+
tmp = line.split(':')
|
37
|
+
array[placement][:status] = tmp[-1].chomp.strip
|
38
|
+
elsif line.include?('Rules.Type.')
|
39
|
+
tmp = line.split(':')
|
40
|
+
array[placement][:rules] = tmp[-1].chomp.strip
|
41
|
+
elsif line.include?('Input.Mode.')
|
42
|
+
tmp = line.split(':')
|
43
|
+
array[placement][:input] = tmp[-1].chomp.strip
|
44
|
+
elsif line.include?('Input.Base.')
|
45
|
+
# Label only used in combination attack
|
46
|
+
tmp = line.split(':')
|
47
|
+
array[placement][:input_base] = tmp[-1].chomp.strip
|
48
|
+
elsif line.include?('Input.Mod.')
|
49
|
+
# Label only used in combination attack
|
50
|
+
tmp = line.split(':')
|
51
|
+
array[placement][:input_mod] = tmp[-1].chomp.strip
|
52
|
+
elsif line.include?('Hash.Target.')
|
53
|
+
tmp = line.split(':')
|
54
|
+
array[placement][:target] = tmp[-1].chomp.strip
|
55
|
+
elsif line.include?('Hash.Type.')
|
56
|
+
tmp = line.split(':')
|
57
|
+
array[placement][:type] = tmp[-1].chomp.strip
|
58
|
+
elsif line.include?('Time.Started.')
|
59
|
+
tmp = line.split(':')
|
60
|
+
tmp.delete_at(0)
|
61
|
+
tmp = tmp.join(':')
|
62
|
+
array[placement][:started] = tmp.chomp.strip
|
63
|
+
elsif line.include?('Time.Estimated.')
|
64
|
+
tmp = line.split(':')
|
65
|
+
tmp.delete_at(0)
|
66
|
+
tmp = tmp.join(':')
|
67
|
+
array[placement][:estimated] = tmp.chomp.strip
|
68
|
+
elsif line.include?('Speed.GPU.')
|
69
|
+
# Must account for x amount of GPUs
|
70
|
+
tmp = line.split(':')
|
71
|
+
tmp[0].gsub!('Speed.GPU.', '')
|
72
|
+
tmp[0].gsub!('.', '')
|
73
|
+
tmp[0].gsub!('#', '')
|
74
|
+
num = tmp[0].to_i
|
75
|
+
if num == 1
|
76
|
+
array[placement][:speed] = []
|
77
|
+
end
|
78
|
+
array[placement][:speed][num-1] = tmp[-1].chomp.strip
|
79
|
+
elsif line.include?('Recovered.')
|
80
|
+
tmp = line.split(':')
|
81
|
+
array[placement][:recovered] = tmp[-1].chomp.strip
|
82
|
+
elsif line.include?('Progress.')
|
83
|
+
tmp = line.split(':')
|
84
|
+
array[placement][:progress] = tmp[-1].chomp.strip
|
85
|
+
elsif line.include?('Rejected.')
|
86
|
+
tmp = line.split(':')
|
87
|
+
array[placement][:rejected] = tmp[-1].chomp.strip
|
88
|
+
elsif line.include?('HWMon.GPU.')
|
89
|
+
# Must account for x amount of GPUs
|
90
|
+
tmp = line.split(':')
|
91
|
+
tmp[0].gsub!('HWMon.GPU.', '')
|
92
|
+
tmp[0].gsub!('.', '')
|
93
|
+
tmp[0].gsub!('#', '')
|
94
|
+
num = tmp[0].to_i
|
95
|
+
if num == 1
|
96
|
+
array[placement][:hwmon] = []
|
97
|
+
end
|
98
|
+
array[placement][:hwmon][num-1] = tmp[-1].chomp.strip
|
99
|
+
end
|
100
|
+
end
|
101
|
+
array
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
###########################################################################
|
106
|
+
# @method RubyHashcat::Parse.status_automat(file) #
|
107
|
+
# @param file: [String] Path to oclHashcat stdout file #
|
108
|
+
# @description Parses the oclHashcat status-automat stdout format. #
|
109
|
+
# @return [Array][Hash] Array of Hashes with oclHashcat status. #
|
110
|
+
###########################################################################
|
111
|
+
def self.status_automat(file)
|
112
|
+
array = []
|
113
|
+
return array unless File.exists?(file)
|
114
|
+
string = []
|
115
|
+
File.open(file).each_line do |x|
|
116
|
+
string << x
|
117
|
+
end
|
118
|
+
string.each do |line|
|
119
|
+
line = line.chomp
|
120
|
+
line = line.strip
|
121
|
+
line = line.gsub(' ', ' ')
|
122
|
+
unless line.include?('STATUS')
|
123
|
+
next
|
124
|
+
end
|
125
|
+
split = line.split(' ')
|
126
|
+
stat = {}
|
127
|
+
i = 0
|
128
|
+
if split[i] == 'STATUS'
|
129
|
+
stat[:status] = split[i+1].chomp.strip
|
130
|
+
i += 2
|
131
|
+
end
|
132
|
+
if split[i] == 'SPEED'
|
133
|
+
i += 1
|
134
|
+
speed = 0
|
135
|
+
si = 0
|
136
|
+
while split[i] != 'CURKU'
|
137
|
+
calc = split[i].to_f
|
138
|
+
duration = split[i+1].to_f
|
139
|
+
if calc == 0.0 and duration == 0.0
|
140
|
+
stat["speed_gpu_#{si+1}".to_sym] = 0
|
141
|
+
else
|
142
|
+
stat["speed_gpu_#{si+1}".to_sym] = (calc/duration).round
|
143
|
+
speed += (calc/duration).round
|
144
|
+
end
|
145
|
+
si += 1
|
146
|
+
i += 2
|
147
|
+
end
|
148
|
+
stat[:total_speed] = speed
|
149
|
+
end
|
150
|
+
if split[i] == 'CURKU'
|
151
|
+
stat[:checkpoint] = split[i+1]
|
152
|
+
i += 2
|
153
|
+
end
|
154
|
+
if split[i] == 'PROGRESS'
|
155
|
+
current_prog = split[i+1].to_f
|
156
|
+
total_prog = split[i+2].to_f
|
157
|
+
stat[:progress] = ((((current_prog + 0.0)/(total_prog + 0.0)) * 10000).round)/10000.0
|
158
|
+
i += 3
|
159
|
+
end
|
160
|
+
if split[i] == 'RECHASH'
|
161
|
+
rec_count = split[i+1].to_f.to_i
|
162
|
+
rec_total = split[i+2].to_f.to_i
|
163
|
+
stat[:rec_hash] = "#{rec_count}/#{rec_total}"
|
164
|
+
i += 3
|
165
|
+
end
|
166
|
+
if split[i] == 'RECSALT'
|
167
|
+
rec_count = split[i+1].to_f.to_i
|
168
|
+
rec_total = split[i+2].to_f.to_i
|
169
|
+
stat[:rec_salt] = "#{rec_count}/#{rec_total}"
|
170
|
+
i += 3
|
171
|
+
end
|
172
|
+
if split[i] == 'TEMP'
|
173
|
+
i += 1
|
174
|
+
si = 0
|
175
|
+
while i < split.count
|
176
|
+
stat["temp_gpu_#{si+1}".to_sym] = split[i].to_i
|
177
|
+
si += 1
|
178
|
+
i += 1
|
179
|
+
end
|
180
|
+
end
|
181
|
+
array << stat
|
182
|
+
end
|
183
|
+
array
|
184
|
+
end
|
185
|
+
|
186
|
+
###########################################################################
|
187
|
+
# @method RubyHashcat::Parse.pot_file(file) #
|
188
|
+
# @param file: [String] Path to oclHashcat cracked passwords #
|
189
|
+
# @description Parses the cracked passwords into a hash. #
|
190
|
+
# @return [Array][Hash] Array of Hashes with cracked passwords. #
|
191
|
+
###########################################################################
|
192
|
+
def self.pot_file(file)
|
193
|
+
arr = []
|
194
|
+
return arr unless File.exists?(file)
|
195
|
+
File.open(file).each_line do |x|
|
196
|
+
split = x.split(':')
|
197
|
+
plain = self.hex_to_bin(split[-1])
|
198
|
+
split.delete_at(-1)
|
199
|
+
hash = split.join(':')
|
200
|
+
arr << {:hash => hash, :plain => plain}
|
201
|
+
end
|
202
|
+
arr
|
203
|
+
end
|
204
|
+
|
205
|
+
###########################################################################
|
206
|
+
# @method RubyHashcat::Parse.hash(hash) #
|
207
|
+
# @param hash: [Hash] Original Hash with strings as keys. #
|
208
|
+
# @description Parses a hash with strings as keys and converts them #
|
209
|
+
# to symbols. #
|
210
|
+
# @return [Hash] Hash with all keys as symbols. #
|
211
|
+
###########################################################################
|
212
|
+
def self.hash(obj)
|
213
|
+
return obj.reduce({}) do |memo, (k, v)|
|
214
|
+
memo.tap { |m| m[k.to_sym] = hash(v) }
|
215
|
+
end if obj.is_a? Hash
|
216
|
+
|
217
|
+
return obj.reduce([]) do |memo, v|
|
218
|
+
memo << hash(v); memo
|
219
|
+
end if obj.is_a? Array
|
220
|
+
|
221
|
+
obj
|
222
|
+
end
|
223
|
+
|
224
|
+
###########################################################################
|
225
|
+
# @method RubyHashcat::Parse.bin_to_hex(s) #
|
226
|
+
# @param s: [String] Normal String #
|
227
|
+
# @description Converts a string to hex #
|
228
|
+
# @return [String] Hexed String #
|
229
|
+
###########################################################################
|
230
|
+
def self.bin_to_hex(s)
|
231
|
+
s.each_byte.map { |b| b.to_s(16) }.join
|
232
|
+
end
|
233
|
+
|
234
|
+
###########################################################################
|
235
|
+
# @method RubyHashcat::Parse.hex_to_bin(s) #
|
236
|
+
# @param s: [String] Hexed String #
|
237
|
+
# @description Converts hex to a string #
|
238
|
+
# @return [String] Normal String #
|
239
|
+
###########################################################################
|
240
|
+
def self.hex_to_bin(s)
|
241
|
+
s.scan(/../).map { |x| x.hex.chr }.join
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
end
|
data/lib/ruby_hashcat/program.rb
CHANGED
@@ -1,16 +1,25 @@
|
|
1
1
|
require 'rprogram/program'
|
2
2
|
|
3
|
+
###########################################################################
|
4
|
+
# Author: Coleton Pierson #
|
5
|
+
# Company: Praetorian #
|
6
|
+
# Date: June 28, 2014 #
|
7
|
+
# Project: Ruby Hashcat #
|
8
|
+
# Description: Main program wrapper class. Holds the main method #
|
9
|
+
# for initializing a cli session. #
|
10
|
+
###########################################################################
|
11
|
+
|
3
12
|
module RubyHashcat
|
4
13
|
class Program < RProgram::Program
|
5
14
|
|
6
15
|
# Add a top-level method which finds and runs the program.
|
7
16
|
def self.crack(options={}, &block)
|
8
|
-
self.find.crack(options
|
17
|
+
self.find.crack(options, &block)
|
9
18
|
end
|
10
19
|
|
11
20
|
# Add a method which runs the program with hashcat_task
|
12
|
-
def crack(options={}
|
13
|
-
run_task(HashcatTask.new(options
|
21
|
+
def crack(options={}, &block)
|
22
|
+
run_task(HashcatTask.new(options, &block))
|
14
23
|
end
|
15
24
|
|
16
25
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubyHashcat
|
2
|
+
class API < Sinatra::Application
|
3
|
+
post '/clean.json' do
|
4
|
+
content_type :json
|
5
|
+
|
6
|
+
if settings.debug
|
7
|
+
pp params
|
8
|
+
end
|
9
|
+
|
10
|
+
begin
|
11
|
+
hc = RubyHashcat::Objects::Hash.new(params[:id].to_i, settings.ocl_location)
|
12
|
+
if hc.exists?
|
13
|
+
hc.clean
|
14
|
+
return {:status => 'success'}.to_json
|
15
|
+
else
|
16
|
+
return {:status => 'error', :message => 'Invalid ID.'}.to_json
|
17
|
+
end
|
18
|
+
rescue => e
|
19
|
+
return {:status => 'error'}.to_json
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module RubyHashcat
|
2
|
+
class API < Sinatra::Application
|
3
|
+
post '/crack.json' do
|
4
|
+
content_type :json
|
5
|
+
|
6
|
+
if settings.debug
|
7
|
+
pp params
|
8
|
+
end
|
9
|
+
|
10
|
+
path = File.dirname(__FILE__)
|
11
|
+
|
12
|
+
tmp = params.clone
|
13
|
+
params = RubyHashcat::Parse.hash(tmp)
|
14
|
+
|
15
|
+
# Validate required parameters
|
16
|
+
unless params[:id] and params[:type] and params[:attack] and params[:hash]
|
17
|
+
return {error: 'Invalid Parameters. Please check the documentation.'}.to_json
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
hc = RubyHashcat::Objects::Hash.new(params[:id].to_i, settings.ocl_location)
|
22
|
+
if hc.exists? and not hc.running?
|
23
|
+
hc.clean
|
24
|
+
end
|
25
|
+
id = params[:id].to_i
|
26
|
+
attack = params[:attack].to_i
|
27
|
+
type = params[:type].to_i
|
28
|
+
hash = "#{path}/../tmp/#{id}.hash"
|
29
|
+
|
30
|
+
hc.attack = attack
|
31
|
+
|
32
|
+
case attack
|
33
|
+
when 1
|
34
|
+
raise RubyHashcat::Objects::Hash::InvalidCombinationAttack unless File.exists?(params[:word_list][:tempfile]) and File.exists?(params[:word_list_2][:tempfile])
|
35
|
+
word_list = "#{path}/../tmp/#{id}.dict"
|
36
|
+
word_list_2 = "#{path}/../tmp/#{id}.dict2"
|
37
|
+
tmp = []
|
38
|
+
tmp << word_list.clone
|
39
|
+
tmp << word_list_2.clone
|
40
|
+
File.rename(params[:word_list][:tempfile], word_list)
|
41
|
+
File.rename(params[:word_list_2][:tempfile], word_list_2)
|
42
|
+
word_list = tmp
|
43
|
+
else
|
44
|
+
if params[:word_list]
|
45
|
+
if params[:word_list][:tempfile]
|
46
|
+
if File.exists?(params[:word_list][:tempfile])
|
47
|
+
word_list = "#{path}/../tmp/#{id}.dict"
|
48
|
+
File.rename(params[:word_list][:tempfile], word_list)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if params[:rule_sets]
|
55
|
+
hc.rules = params[:rule_sets]
|
56
|
+
end
|
57
|
+
if params[:username]
|
58
|
+
hc.username = true
|
59
|
+
end
|
60
|
+
if params[:charset]
|
61
|
+
hc.charset = params[:charset]
|
62
|
+
end
|
63
|
+
|
64
|
+
File.rename(params[:hash][:tempfile], hash)
|
65
|
+
|
66
|
+
hc.hash = hash
|
67
|
+
|
68
|
+
if word_list
|
69
|
+
hc.word_list = word_list
|
70
|
+
end
|
71
|
+
|
72
|
+
hc.type = type
|
73
|
+
|
74
|
+
hc.crack(true)
|
75
|
+
|
76
|
+
return {:status => 'success'}.to_json
|
77
|
+
rescue RubyHashcat::Objects::Hash::RubyHashcatError => e
|
78
|
+
return {:error => e.message}.to_json
|
79
|
+
rescue => e
|
80
|
+
return {:error => e.message}.to_json
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RubyHashcat
|
2
|
+
class API < Sinatra::Application
|
3
|
+
get '/results.json' do
|
4
|
+
content_type :json
|
5
|
+
|
6
|
+
if settings.debug
|
7
|
+
pp params
|
8
|
+
end
|
9
|
+
|
10
|
+
begin
|
11
|
+
hc = RubyHashcat::Objects::Hash.new(params[:id].to_i, settings.ocl_location)
|
12
|
+
unless hc.exists?
|
13
|
+
return {:status => 'error', :message => 'Invalid ID.'}.to_json
|
14
|
+
end
|
15
|
+
if hc.running?
|
16
|
+
return {:status => 'running'}.to_json
|
17
|
+
else
|
18
|
+
return {:results => hc.results}.to_json
|
19
|
+
end
|
20
|
+
rescue => e
|
21
|
+
return {:status => 'error', :message => e.message}.to_json
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubyHashcat
|
2
|
+
class API < Sinatra::Application
|
3
|
+
get '/location.json' do
|
4
|
+
content_type :json
|
5
|
+
|
6
|
+
if settings.debug
|
7
|
+
pp params
|
8
|
+
end
|
9
|
+
|
10
|
+
{:location => settings.ocl_location}.to_json
|
11
|
+
end
|
12
|
+
|
13
|
+
get '/rules.json' do
|
14
|
+
content_type :json
|
15
|
+
|
16
|
+
if settings.debug
|
17
|
+
pp params
|
18
|
+
end
|
19
|
+
|
20
|
+
list = Dir.entries("#{settings.ocl_location}/rules/")
|
21
|
+
list.delete('.')
|
22
|
+
list.delete('..')
|
23
|
+
{:rules => list}.to_json
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|