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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ec228aef049a3ad95a48ec1469fd4776485adb5
4
- data.tar.gz: 7f0feb43dffdf57ea6ac483454adfad3f88b1778
3
+ metadata.gz: 1c7c6e7d06815bcc3d0c9599c9bff96f7cf7c65c
4
+ data.tar.gz: a59f83883b5ce173f358dd514e3e9b73528984fd
5
5
  SHA512:
6
- metadata.gz: d0dda83de1f4ae91c18f25b73c9f9e3841290b24a005e69dbde75f9de260c10dc382a662ad69f6d711c711ed80998d6852f64608410605cbbb0cbc74b8a52b4a
7
- data.tar.gz: 98b68cdfbfd925293ee7264bb8cbe963598db13ddd39bed4ff8174c68d30c087fbcfef96ebb867600215540b14571dac7fff5eeec8e576e8f47248c5e125ef42
6
+ metadata.gz: a859e87170241e660147e70276322a6f1c3d33ce09d9ff906381bd40ffbf66801ffc9fd2f1cbfbaeae6efceb0d08fd285ede9620137955ae677c47120ad1f082
7
+ data.tar.gz: 7bb9dac6700d925f8b188798b1655a4cd99a6388e1d6da1d01ec8ad1b734968e5c688cc5ee52a91427d2246913bfa4affa5258e05a2f0c60e56537e0ec37b949
data/.gitignore CHANGED
@@ -12,9 +12,7 @@ lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
14
  spec/reports
15
- test/tmp
16
15
  test/version_tmp
17
- tmp
18
16
  *.bundle
19
17
  *.so
20
18
  *.o
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RubyHashcat
2
2
 
3
- TODO: Write a gem description
3
+ Ruby wrapper created to run oclHashcat cracking jobs from inside of ruby. Initially created to integrate with a Rest API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,11 +18,11 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ Check out the test folder to see some examples of running a crack job.
22
22
 
23
23
  ## Contributing
24
24
 
25
- 1. Fork it ( https://github.com/[my-github-username]/ruby_hashcat/fork )
25
+ 1. Fork it ( https://github.com/coleton/ruby_hashcat/fork )
26
26
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
27
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
28
  4. Push to the branch (`git push origin my-new-feature`)
@@ -1,3 +1,23 @@
1
+ require 'ruby_hashcat/objects/init'
2
+ require 'ruby_hashcat/api'
3
+ require 'ruby_hashcat/parse'
1
4
  require 'ruby_hashcat/program'
2
5
  require 'ruby_hashcat/task'
6
+ require 'ruby_hashcat/tools'
7
+ require 'ruby_hashcat/validation'
3
8
  require 'ruby_hashcat/version'
9
+
10
+ module RubyHashcat
11
+ # Hashcat Rest API
12
+ def self.start_api(hashcat_location, debug=false)
13
+ RubyHashcat::API.set :ocl_location, hashcat_location
14
+ RubyHashcat::API.set :debug, debug
15
+ RubyHashcat::API.run!
16
+ end
17
+ end
18
+
19
+ if __FILE__ == $0
20
+ path = File.dirname(__FILE__)
21
+ puts File.exists?("#{path}/../../cudaHashcat-1.30/cudaHashcat64.bin")
22
+ RubyHashcat.start_api("#{path}/../../cudaHashcat-1.30/cudaHashcat64.bin", true)
23
+ end
@@ -0,0 +1,22 @@
1
+ require 'sinatra/base'
2
+ require 'thin'
3
+ require 'sucker_punch'
4
+ require 'json'
5
+ require 'pp'
6
+
7
+ ###########################################################################
8
+ # Author: Coleton Pierson #
9
+ # Company: Praetorian #
10
+ # Date: August 20, 2014 #
11
+ # Project: Ruby Hashcat #
12
+ # Description: Main API class. Loads routes and sinatra methods. #
13
+ ###########################################################################
14
+
15
+ module RubyHashcat
16
+
17
+ class API < Sinatra::Application
18
+ path = File.dirname(__FILE__)
19
+ require "#{path}/routes/init"
20
+ end
21
+
22
+ end
@@ -0,0 +1,419 @@
1
+ require 'sucker_punch'
2
+
3
+ ###########################################################################
4
+ # Author: Coleton Pierson #
5
+ # Company: Praetorian #
6
+ # Date: August 20, 2014 #
7
+ # Project: Ruby Hashcat #
8
+ # Description: Main hash class. Interfaces with cli wrapper #
9
+ # and processes async tasks. #
10
+ ###########################################################################
11
+
12
+ module RubyHashcat
13
+ module Objects
14
+ class Hash
15
+
16
+ ###########################################################################
17
+ # @method initialize(id, path) #
18
+ # @param id: [Integer] Hash ID #
19
+ # @param path: [String] oclHashcat Path #
20
+ # @description Initialize a new hash. #
21
+ ###########################################################################
22
+ def initialize(id, path)
23
+ raise RubyHashcat::Objects::Hash::InvalidHashId unless id.is_a? Integer
24
+ raise RubyHashcat::Objects::Hash::InvalidHashCatLocation unless Dir.exists?(File.dirname(path))
25
+ @id = id
26
+ @path = File.dirname(path)
27
+ @ocl = path
28
+ end
29
+
30
+ ###########################################################################
31
+ # @method crack(async) #
32
+ # @param async: [Boolean] Crack Async #
33
+ # @description Crack the hash with the current settings. #
34
+ ###########################################################################
35
+ def crack(async=false)
36
+
37
+ # Check if async
38
+ if async
39
+ # SuckerPunch the crack method
40
+ RubyHashcat::Objects::Hash::Async.new.async.crack(self)
41
+ else
42
+ path = File.dirname(__FILE__)
43
+
44
+ # Write standard output to a file without redirecting it.
45
+ tee_out = TeeIO.new($stdout, File.new("#{path}/../tmp/#{@id}_output.txt", 'w'))
46
+ $stdout = tee_out
47
+
48
+ # Write standard error to a file without redirecting it.
49
+ tee_err = TeeIO.new($stderr, File.new("#{path}/../tmp/#{@id}_errors.txt", 'w'))
50
+ $stderr = tee_err
51
+
52
+ # Create PID file for this hash ID
53
+ File.touch("#{path}/../tmp/.hashcat_#{@id}_pid")
54
+
55
+ # oclHashcat Object
56
+ worker = RubyHashcat::Program.new(@ocl)
57
+
58
+ # Start cracking with wrapper
59
+ worker.crack do |crack|
60
+
61
+ # Hash Type
62
+ crack.hash_type = @type
63
+ # Output
64
+ crack.outfile = "#{path}/../tmp/#{@id}.crack"
65
+ crack.outfile_format = 5
66
+ # Status Output
67
+ crack.status = true
68
+ crack.status_timer = 15
69
+
70
+ # Disable Restore and Pot File (not needed)
71
+ crack.disable_restore = true
72
+ crack.disable_potfile = true
73
+
74
+ # Rules
75
+ crack.rules = @rule if @rule
76
+
77
+ # Runtime limit
78
+ crack.runtime = @runtime if @runtime
79
+
80
+ # Contains Username
81
+ crack.username = true if @username
82
+
83
+ # Combination Rules
84
+ if @attack == 1
85
+ crack.rule_left = @left_rule if @left_rule
86
+ crack.rule_right = @right_rule if @right_rule
87
+ end
88
+
89
+ # Attack Mode
90
+ crack.attack_mode = @attack
91
+
92
+ # Hash
93
+ crack.hash = @hash
94
+
95
+ # Attack mode config
96
+ case @attack
97
+ when 0
98
+ # Dictionary Attack
99
+ crack.wordlist = @word_list
100
+ when 1
101
+ # Combination Attack
102
+ raise RubyHashcat::Objects::Hash::InvalidCombinationAttack unless @word_list.count == 2
103
+ crack.wordlist = @word_list
104
+ when 3
105
+ # Bruteforce/Mask Attack
106
+ raise RubyHashcat::Objects::Hash::InvalidMaskAttack unless @charset
107
+ crack.charset = @charset
108
+ when 6
109
+ # Hybrid Dict + Mask Attack
110
+ raise RubyHashcat::Objects::Hash::InvalidHybridAttack unless @word_list and @charset
111
+ crack.wordlist = @word_list
112
+ crack.charset = @charset
113
+ when 7
114
+ # Hybrid Mask + Dict Attack
115
+ raise RubyHashcat::Objects::Hash::InvalidHybridAttack unless @word_list and @charset
116
+ crack.charset = @charset
117
+ crack.wordlist = @word_list
118
+ else
119
+ raise RubyHashcat::Objects::Hash::InvalidAttack
120
+ end
121
+
122
+ end
123
+
124
+ # Delete PID
125
+ File.delete("#{path}/../tmp/.hashcat_#{@id}_pid") if File.exists?("#{path}/../tmp/.hashcat_#{@id}_pid")
126
+ end
127
+ end
128
+
129
+ ###########################################################################
130
+ # @method clean #
131
+ # @description Deletes all files created by cracking. #
132
+ ###########################################################################
133
+ def clean
134
+ path = File.dirname(__FILE__)
135
+ File.delete("#{path}/../tmp/.hashcat_#{@id}_pid") if File.exists?("#{path}/../tmp/.hashcat_#{@id}_pid")
136
+ File.delete("#{path}/../tmp/#{@id}_output.txt") if File.exists?("#{path}/../tmp/#{@id}_output.txt")
137
+ File.delete("#{path}/../tmp/#{@id}_errors.txt") if File.exists?("#{path}/../tmp/#{@id}_errors.txt")
138
+ File.delete("#{path}/../tmp/#{@id}.crack") if File.exists?("#{path}/../tmp/#{@id}.crack")
139
+ end
140
+
141
+ ###########################################################################
142
+ # @method status #
143
+ # @description Reads oclHashcat output and parses the status. #
144
+ # @return [Hash] Hash with status and errors #
145
+ ###########################################################################
146
+ def status
147
+ path = File.dirname(__FILE__)
148
+ if File.exists?("#{path}/../tmp/#{@id}_output.txt") and File.exists?("#{path}/../tmp/#{@id}_errors.txt")
149
+ arr = RubyHashcat::Parse.stdout("#{path}/../tmp/#{@id}_output.txt")
150
+ if arr.is_a? Array
151
+ arr_dat = arr[-1]
152
+ end
153
+ err = File.read("#{path}/../tmp/#{@id}_errors.txt").chomp.strip
154
+ {:data => arr_dat, :errors => err}
155
+ else
156
+ return false
157
+ end
158
+ end
159
+
160
+ ###########################################################################
161
+ # @method running? #
162
+ # @description Checks pid file to see if oclhashcat is running. #
163
+ # @return [Boolean] oclHashcat Running #
164
+ ###########################################################################
165
+ def running?
166
+ path = File.dirname(__FILE__)
167
+ File.exists?("#{path}/../tmp/.hashcat_#{@id}_pid")
168
+ end
169
+
170
+ ###########################################################################
171
+ # @method exists? #
172
+ # @description Checks to see if the object has initiated cracking. #
173
+ # @return [Boolean] #
174
+ ###########################################################################
175
+ def exists?
176
+ path = File.dirname(__FILE__)
177
+ File.exists?("#{path}/../tmp/#{@id}_output.txt")
178
+ end
179
+
180
+ ###########################################################################
181
+ # @method status #
182
+ # @description Reads oclHashcat pot file and parses the cracked hashes. #
183
+ # @return [Hash] Returns cracked hashes and their plaintext passwords. #
184
+ ###########################################################################
185
+ def results
186
+ path = File.dirname(__FILE__)
187
+ RubyHashcat::Parse.pot_file("#{path}/../tmp/#{@id}.crack")
188
+ end
189
+
190
+ ####################
191
+ # Modifier Methods #
192
+ ####################
193
+
194
+ ###########################################################################
195
+ # @method word_list=(value) #
196
+ # @param value: [Array] Word List Paths #
197
+ # [String] Word List Path #
198
+ # @description Set word list(s). #
199
+ ###########################################################################
200
+ def word_list=(value)
201
+ @word_list = []
202
+ if value.is_a? Array
203
+ value.each do |x|
204
+ raise RubyHashcat::Objects::Hash::InvalidHashFile unless File.exists?(x)
205
+ @word_list << x
206
+ end
207
+ else
208
+ raise RubyHashcat::Objects::Hash::InvalidHashFile unless File.exists?(value)
209
+ @word_list << value
210
+ end
211
+ end
212
+
213
+ ###########################################################################
214
+ # @method hash=(value) #
215
+ # @param value: [String] Hash File Path #
216
+ # @description Set hash. #
217
+ ###########################################################################
218
+ def hash=(value)
219
+ raise RubyHashcat::Objects::Hash::InvalidHashFile unless File.exists?(value)
220
+ @hash = value
221
+ end
222
+
223
+ ###########################################################################
224
+ # @method type=(value) #
225
+ # @param value: [Integer] Hash Type #
226
+ # @description Set hash type. #
227
+ ###########################################################################
228
+ def type=(value)
229
+ raise RubyHashcat::Objects::Hash::InvalidHashId unless value.is_a? Integer
230
+ @type = value
231
+ end
232
+
233
+ ###########################################################################
234
+ # @method attack=(value) #
235
+ # @param value: [Integer] Attack Type #
236
+ # @description Set attack type. #
237
+ ###########################################################################
238
+ def attack=(value)
239
+ raise RubyHashcat::Objects::Hash::InvalidAttack unless value.is_a? Integer and [0, 1, 3, 6, 7].include?(value)
240
+ @attack = value
241
+ end
242
+
243
+ ###########################################################################
244
+ # @method char_word=(value) #
245
+ # @param value: [Boolean] Charset first in Hybrid attack order #
246
+ # @description Set attack order for hybrid attack to (charset #
247
+ # + word list) instead of (word list + charset). #
248
+ ###########################################################################
249
+ def char_word=(value)
250
+ @char_word = !!value
251
+ end
252
+
253
+ ###########################################################################
254
+ # @method rules=(value) #
255
+ # @param value: [Array] Rule File Names #
256
+ # [String] Rule File Name #
257
+ # @description Set rules for word lists. Verifies rules #
258
+ # are in the ocl rule folder (/ocl/rules). #
259
+ ###########################################################################
260
+ def rules=(value)
261
+ list = Dir.entries("#{@path}/rules/")
262
+ @rule = []
263
+ if value.is_a? Array
264
+ raise RubyHashcat::Objects::Hash::InvalidRuleFile unless (value - list).empty?
265
+ value.each do |x|
266
+ @rule << "#{@path}/rules/#{x}"
267
+ end
268
+ else
269
+ raise RubyHashcat::Objects::Hash::InvalidRuleFile unless list.include?(value)
270
+ @rule << "#{@path}/rules/#{value}"
271
+ end
272
+ end
273
+
274
+ ###########################################################################
275
+ # @method max_runtime=(value) #
276
+ # @param value: [Integer] Seconds #
277
+ # @description Set max time for cracking to last. #
278
+ ###########################################################################
279
+ def max_runtime=(value)
280
+ raise RubyHashcat::Objects::Hash::InvalidRuntime unless value.is_a? Integer and value >= 300
281
+ @runtime = value
282
+ end
283
+
284
+ ###########################################################################
285
+ # @method username=(value) #
286
+ # @param value: [Boolean] Username #
287
+ # @description Set true if hash file contains user names. #
288
+ ###########################################################################
289
+ def username=(value)
290
+ @username = !!value
291
+ end
292
+
293
+ ###########################################################################
294
+ # @method charset=(value) #
295
+ # @param value: [String] Charset #
296
+ # @description Set charset for brute forcing or hybrid attack. #
297
+ # Must follow oclHashcat's charset pattern: #
298
+ # ?l - lowercase #
299
+ # ?u - uppercase #
300
+ # ?d - digit #
301
+ # ?s - special #
302
+ # ?a - all #
303
+ ###########################################################################
304
+ def charset=(value)
305
+ raise RubyHashcat::Objects::Hash::InvalidCharset unless value.match(/(\?[lasdu]{1})+/)
306
+ @charset = value
307
+ end
308
+
309
+ ###########################################################################
310
+ # @method left_rule=(value) #
311
+ # @param value: [String] Charset #
312
+ # @description Set rules for left dict on hybrid attack. #
313
+ ###########################################################################
314
+ def left_rule=(value)
315
+ raise RubyHashcat::Objects::Hash::InvalidRule unless value.match(/([:lucCtrdfq\{\}\[\]]{1})||(T[0-9]+)||(p[0-9]+)||(\$[0-9]+)||(\^[0-9]+)||(D[0-9]+)||(x[0-9]{2,})||(i[0-9]{2,})||(o[0-9]{2,})||('[0-9]+)||(s[0-9]{2,})||(@[0-9]+)||(z[0-9]+)||(Z[0-9]+)/) and value != ''
316
+ @left_rule = value
317
+ end
318
+
319
+ ###########################################################################
320
+ # @method right_rule=(value) #
321
+ # @param value: [String] Charset #
322
+ # @description Set rules for right dict on hybrid attack. #
323
+ ###########################################################################
324
+ def right_rule=(value)
325
+ raise RubyHashcat::Objects::Hash::InvalidRule unless value.match(/([:lucCtrdfq\{\}\[\]]{1})||(T[0-9]+)||(p[0-9]+)||(\$[0-9]+)||(\^[0-9]+)||(D[0-9]+)||(x[0-9]{2,})||(i[0-9]{2,})||(o[0-9]{2,})||('[0-9]+)||(s[0-9]{2,})||(@[0-9]+)||(z[0-9]+)||(Z[0-9]+)/) and value != ''
326
+ @right_rule = value
327
+ end
328
+
329
+ ####################
330
+ # Class Exceptions #
331
+ ####################
332
+ class RubyHashcatError < StandardError
333
+ end
334
+ class InvalidHashType < RubyHashcatError
335
+ def message
336
+ 'Invalid Hash Type. Hash type must be an integer.'
337
+ end
338
+ end
339
+ class InvalidHashFile < RubyHashcatError
340
+ def message
341
+ 'Invalid Hash File. Check your hash file.'
342
+ end
343
+ end
344
+ class InvalidHashWordList < RubyHashcatError
345
+ def message
346
+ 'Invalid Word List File. Please check your post request'
347
+ end
348
+ end
349
+ class InvalidRuleFile < RubyHashcatError
350
+ def message
351
+ 'Invalid Rule File. To view the default rule files packaged with hashcat, please check the documentation or GET /rules.json'
352
+ end
353
+ end
354
+ class InvalidCharset < RubyHashcatError
355
+ def message
356
+ 'Invalid Charset String. To view a list of valid charsets, please check the documentation.'
357
+ end
358
+ end
359
+ class InvalidRule < RubyHashcatError
360
+ def message
361
+ 'Invalid Rule. To view a list of valid rules, please check the documentation.'
362
+ end
363
+ end
364
+ class InvalidAttack < RubyHashcatError
365
+ def message
366
+ 'Invalid Attack. To view a list of attacks, please check the documentation.'
367
+ end
368
+ end
369
+ class InvalidHashId < RubyHashcatError
370
+ def message
371
+ 'Invalid Hash ID. Hash ID must be an integer.'
372
+ end
373
+ end
374
+ class InvalidHashCatLocation < RubyHashcatError
375
+ def message
376
+ 'Invalid HashCat path. HashCat path must exist.'
377
+ end
378
+ end
379
+ class InvalidRuntime < RubyHashcatError
380
+ def message
381
+ 'Invalid HashCat runtime. Runtime must be an integer and greater or equal to 300.'
382
+ end
383
+ end
384
+ class InvalidMaskAttack < RubyHashcatError
385
+ def message
386
+ 'Invalid HashCat mask attack. You must specify a valid charset.'
387
+ end
388
+ end
389
+ class InvalidHybridAttack < RubyHashcatError
390
+ def message
391
+ 'Invalid HashCat hybrid attack. You must specify a valid charset and word list.'
392
+ end
393
+ end
394
+ class InvalidCombinationAttack < RubyHashcatError
395
+ def message
396
+ 'Invalid HashCat combination attack. You must specify an array of 2 word lists.'
397
+ end
398
+ end
399
+ class HashIDAlreadyExists < RubyHashcatError
400
+ def message
401
+ 'The ID you chose for this hash already exists. Please choose another.'
402
+ end
403
+ end
404
+
405
+ #########################
406
+ # Sucker Punch Subclass #
407
+ #########################
408
+ class Async
409
+ include ::SuckerPunch::Job
410
+ workers 3
411
+
412
+ def crack(obj)
413
+ obj.crack
414
+ end
415
+
416
+ end
417
+ end
418
+ end
419
+ end