forked from digininja/RSMangler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rsmangler.rb
executable file
·526 lines (468 loc) · 11.1 KB
/
rsmangler.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
#!/usr/bin/env ruby
# == RSMangler: Take a wordlist and mangle it
#
# RSMangler will take a wordlist and perform various manipulations on it similar to
# those done by John the Ripper with a few extras, the main one being permutations mode
# which takes each word in the list and combines it with the others to produce all
# possible permutations (not combinations, order matters).
#
# See the README for full information
#
# Author:: Robin Wood (robin@digininja.org)
# Version:: 1.4-alt
# Copyright:: Copyright(c) 2012, RandomStorm Limited - www.randomstorm.com
# Licence:: Creative Commons Attribution-Share Alike 2.0
#
# Changes:
# 1.4 - Added full leetspeak option, thanks Felipe Molina (@felmoltor)
#
# 1.4-alt - Added option to dump straight to disk, because my expanded options were filling all ram.
require "date"
require 'getoptlong'
filename = "/root/rsmangler-output.txt"
puts "Opening the file... #{filename}"
target = open(filename, 'w')
puts "Truncating the file. Goodbye!"
target.truncate(0)
# The left hand character is what you are looking for
# and the right hand one is the one you are replacing it
# with
leet_swap = {
"s" => "$",
"S" => "$",
"e" => "3",
"E" => "3",
"a" => "4",
"A" => "4",
"o" => "0",
"O" => "0",
"i" => "1",
"I" => "1",
"l" => "1",
"L" => "1",
"t" => "7",
"T" => "7"
}
# Common words to append and prepend if --common is allowed
common_words = [
"pw",
"pwd",
"admin",
"sys"
]
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--file', '-f', GetoptLong::REQUIRED_ARGUMENT ],
[ '--min', '-m', GetoptLong::REQUIRED_ARGUMENT ],
[ '--max', '-x', GetoptLong::REQUIRED_ARGUMENT ],
[ '--perms', '-p', GetoptLong::NO_ARGUMENT ],
[ '--double', '-d', GetoptLong::NO_ARGUMENT ],
[ '--reverse', '-r', GetoptLong::NO_ARGUMENT ],
[ '--leet', '-t', GetoptLong::NO_ARGUMENT ],
[ '--full-leet', '-T', GetoptLong::NO_ARGUMENT ],
[ '--capital', '-c', GetoptLong::NO_ARGUMENT ],
[ '--upper', '-u', GetoptLong::NO_ARGUMENT ],
[ '--lower', '-l', GetoptLong::NO_ARGUMENT ],
[ '--swap', '-s', GetoptLong::NO_ARGUMENT ],
[ '--ed', '-e', GetoptLong::NO_ARGUMENT ],
[ '--ing', '-i', GetoptLong::NO_ARGUMENT ],
[ '--punctuation', GetoptLong::NO_ARGUMENT ],
[ '--years', "-y", GetoptLong::NO_ARGUMENT ],
[ '--acronym', "-a", GetoptLong::NO_ARGUMENT ],
[ '--common', "-C", GetoptLong::NO_ARGUMENT ],
[ '--pnb', GetoptLong::NO_ARGUMENT ],
[ '--pna', GetoptLong::NO_ARGUMENT ],
[ '--nb', GetoptLong::NO_ARGUMENT ],
[ '--na', GetoptLong::NO_ARGUMENT ],
[ '--force', GetoptLong::NO_ARGUMENT ],
[ '--space', GetoptLong::NO_ARGUMENT ],
[ "-v" , GetoptLong::NO_ARGUMENT ],
[ '--dump', "-D", GetoptLong::NO_ARGUMENT ]
)
def good_call
puts
puts "Good call, either reduce the size of your word list or use the --perms option to disable permutations"
puts
exit
end
# Display the usage
def usage
puts "rsmangler v 1.4 Robin Wood (robin@digininja.org) <www.randomstorm.com>
To pass the initial words in on standard in do:
cat wordlist.txt | ./rsmangler.rb --file - > new_wordlist.rb
All options are ON by default, these parameters turn them OFF
Usage: rsmangler.rb [OPTION]
--help, -h: show help
--file, -f: the input file, use - for STDIN
--max, -x: maximum word length
--min, -m: minimum word length
--perms, -p: permutate all the words
--double, -d: double each word
--reverse, -r: reverser the word
--leet, -t: l33t speak the word
--full-leet, -T: all posibilities l33t
--capital, -c: capitalise the word
--upper, -u: uppercase the word
--lower, -l: lowercase the word
--swap, -s: swap the case of the word
--ed, -e: add ed to the end of the word
--ing, -i: add ing to the end of the word
--punctuation: add common punctuation to the end of the word
--years, -y: add all years from 1990 to current year to start and end
--acronym, -a: create an acronym based on all the words entered in order and add to word list
--common, -C: add the following words to start and end: admin, sys, pw, pwd
--pna: add 01 - 09 to the end of the word
--pnb: add 01 - 09 to the beginning of the word
--na: add 1 - 123 to the end of the word
--nb: add 1 - 123 to the beginning of the word
--force - don't check ooutput size
--space - add spaces between words
--dump -D: dump results straight to file, no need to fill ram fall over and die!
"
exit
end
def binaryincrement(binarray)
index = binarray.size-1
incremented = false
while !incremented and index>=0
if (binarray[index]==0)
binarray[index] = 1
incremented = true
break
else
binarray[index]=0
end
index -= 1
end
return binarray
end
def leet_variations(word, swap_array)
count = 0
swap_array.keys.each do |key|
count += word.count(key)
end
variation = Array.new(count,0)
leetletterpos = Array.new(count,0)
variationarr = []
# Save the indexes where the leet letters can be substituted
pos = 0
iter = 0
tmpword = word.dup
swap_array.each do |char, replace|
pos = 0
while (!(pos=tmpword.index(char)).nil?)
leetletterpos[iter] = pos
tmpword[pos]="$"
iter += 1
end
end
# Create all posible combinations of subtitutions
src_chars = swap_array.keys.join
dst_chars = swap_array.values.join
begin
tmpword = word.dup
variation = binaryincrement(variation)
idx = 0
variation.each{|changeletter|
if (changeletter==1)
# Tried tr! but it won't replace inline, probably because it doesn't know where the slice is happening
tmpword[leetletterpos[idx],1] = tmpword[leetletterpos[idx],1].tr(src_chars, dst_chars)
end
idx += 1
}
variationarr << tmpword
end while (variation != Array.new(count,1))
return variationarr
end
verbose=false
leet=true
full_leet=true
perms=true
double=true
reverse=true
capital=true
upper=true
lower=true
swap=true
ed=true
ing=true
punctuation=true
years=true
acronym=true
common=true
pna=true
pnb=true
na=true
nb=true
force=false
space=false
dump=false
file_handle = nil
min_length = nil
max_length = nil
begin
opts.each do |opt, arg|
case opt
when '--help'
usage
when '--file'
if arg == "-"
file_handle = STDIN
else
if File.exist? arg
file_handle = File.new(arg, "r")
else
puts "The specified file does not exist"
exit
end
end
when "--max"
max_length = arg.to_i
when "--min"
min_length = arg.to_i
when "--leet"
leet = false
when "--full-leet"
full_leet = false
when "--perms"
perms = false
when "--double"
double = false
when "--reverse"
reverse = false
when "--capital"
capital = false
when "--upper"
upper = false
when "--lower"
lower = false
when "--swap"
swap = false
when "--ed"
ed = false
when "--ing"
ing = false
when "--common"
common = false
when "--acronym"
acronym = false
when "--years"
years = false
when "--punctuation"
punctuation = false
when "--pna"
pna = false
when "--pnb"
pnb = false
when "--na"
na = false
when "--nb"
nb = false
when "--space"
space = true
when "--force"
force = true
when '-v'
verbose=true
when '--dump'
dump=true
end
end
rescue => e
puts e
usage
end
if file_handle.nil?
puts "No input file specified"
puts
usage
exit
end
file_words = []
while (x = file_handle.gets)
x.chomp!
file_words << x
end
file_handle.close
if !force and perms and file_words.length > 5
puts "5 words in a start list creates a dictionary of nearly 100,000 words."
puts "You have " + file_words.length.to_s + " words in your list, are you sure you wish to continue?"
puts "Hit ctrl-c to abort"
puts
interrupted = false
trap("INT") { interrupted = true }
5.downto(1) { |i|
print i.to_s + " "
STDOUT.flush
sleep 1
if interrupted
good_call
end
}
if interrupted
good_call
end
end
wordlist = []
if perms
for i in (1..file_words.length)
file_words.permutation(i) { |c|
wordlist << c.join
}
end
else
wordlist = file_words
end
acro = nil
if acronym
acro = ""
file_words.each { |c|
acro += c[0, 1]
}
wordlist << acro
end
results = []
xcommon = false
if dump
wordlist.each do |x|
target.write(x + "\n")
if common
common_words.each do |word|
target.write(word + x + "\n")
target.write(x + word + "\n")
end
end
if full_leet
leetarr = leet_variations(x, leet_swap)
leetarr.each do |leetvar|
target.write(leetvar + "\n")
end
else
# Only look at doing this if full leet is not enabled
# Have to clone it otherwise the assignment is done
# by reference and the gsub! updates both x and all_swapped
all_swapped = x.clone
if leet
leet_swap.each_pair do |find, rep|
all_swapped.gsub!(/#{find}/, rep)
target.write( x.gsub(/#{find}/, rep) + "\n")
end
target.write(all_swapped + "\n")
end
end
if punctuation
for i in ("!@$%^&*()".scan(/./)) # todo; expand & add special chars
target.write( x + i.to_s + "\n")
target.write( i.to_s + x + "\n")
end
end
if years
for i in (1940..2020)
target.write( i.to_s + x + "\n")
target.write( x + i.to_s + "\n")
end
end
if (pna or pnb)
for i in (1..9)
if pnb
target.write( "0" + i.to_s + x + "\n")
target.write( "00" + i.to_s + x + "\n")
end
if pna
target.write( x + "0" + i.to_s + "\n")
target.write( x + "00" + i.to_s + "\n")
end
end
end
if (na or nb)
for i in (1..99999)
if nb
target.write( i.to_s + x + "\n")
end
if na
target.write( x + i.to_s + "\n")
end
end
end
end
else
wordlist.each do |x|
results << x
results << x+x if double
results << x.reverse if reverse
results << x.capitalize if capital
results << x.downcase if lower
results << x.upcase if upper
results << x.swapcase if swap
results << x + "ed" if ed
results << x + "ing" if ing
if common
common_words.each do |word|
results << word + x
results << x + word
end
end
if full_leet
leetarr = leet_variations(x, leet_swap)
leetarr.each do |leetvar|
results << leetvar
end
else
# Only look at doing this if full leet is not enabled
# Have to clone it otherwise the assignment is done
# by reference and the gsub! updates both x and all_swapped
all_swapped = x.clone
if leet
leet_swap.each_pair do |find, rep|
all_swapped.gsub!(/#{find}/, rep)
results << x.gsub(/#{find}/, rep)
end
results << all_swapped
end
end
if punctuation
for i in ("!@$%^&*()".scan(/./))
results << x + i.to_s
results << i.to_s + x
end
end
if years
for i in (1940..2020)
results << i.to_s + x
results << x + i.to_s
end
end
if (pna or pnb)
for i in (1..9)
results << "0" + i.to_s + x if pnb
results << "00" + i.to_s + x if pnb
results << x + "0" + i.to_s if pna
results << x + "00" + i.to_s if pna
end
end
if (na or nb)
for i in (1..99999)
results << i.to_s + x if nb
results << x + i.to_s if na
end
end
end
end
# end of wordlist doing stuff
results.uniq!
if !max_length.nil? or !min_length.nil?
results.delete_if { |x|
res = false
if !max_length.nil? and !min_length.nil?
res = x.length < min_length || x.length > max_length
elsif !min_length.nil?
res = x.length < min_length
elsif !max_length.nil?
res = x.length > max_length
end
res
}
end
target.close
puts results
# end of script