#!/bin/ruby
characters_to_use="ABCD"
minimum_password_length=5
maximum_password_length=15
def password_correct?(test_password)
# This is just for testing. There's no need to alter this bit!
return true if test_password == "DCBAAAA"
return false
end
char_array=characters_to_use.split(//)
is_access_granted = false
(minimum_password_length..maximum_password_length).each do |password_length| # loop to gradually increase password length
combinations=char_array.length**password_length
(0..combinations-1).each do |perm_number| # loop through combinations for a given length
password=""
(1..password_length).each do |char_number| # loop through characters
char_reference = (perm_number / char_array.length**(char_number-1)).floor % char_array.length
character = char_array[char_reference]
password << character
end
if password_correct?(password)
puts "#{password} | Access Denied | #{perm_number} / #{combinations}"
else
puts "#{password} | Access Granted"
is_access_granted = true
break
end
end
break if is_access_granted
end
Refactorings
No refactoring yet !
Ishkur
October 11, 2008, October 11, 2008 02:36, permalink
Hmmm, I certainly can't speak for everyone here (nor do I care to, for that matter), but um... wtfm8?
I just don't see that as the greatest idea. And also, why Ruby?
John Sietsma
October 13, 2008, October 13, 2008 11:07, permalink
Here is a first pass refactor.
A few quick notes:
* password check was the wrong way around.
* no need for the returns in password_correct?
* use the range object rather then two separate min and max variables.
I'm suss on anything that is nested more then once and functions that go on too long. Breaking out the loops into functions lets you remove the is_access_granted flag and the multiple breaks. I think it makes it more readable, but you may disagree! It allows you to give a functions reasonable names and users don't have to grok the code.
I think there still some way to go in refactoring this code.
#!/bin/ruby
class Cracker
def initialize(char_array, password_range)
@char_array = char_array
@password_range = password_range
end
def password_correct?(test_password)
test_password == "DCBAAAA"
end
def generate_password( perm_number, password_length )
password=""
(1..password_length).each do |char_number| # loop through characters
char_reference = (perm_number / @char_array.length**(char_number-1)).floor % @char_array.length
character = @char_array[char_reference]
password << character
end
password
end
def do_combination( num_combinations, password_length )
(0..num_combinations-1).each do |perm_number| # loop through combinations for a given length
password = generate_password( perm_number, password_length )
return password, perm_number if password_correct?(password)
end
end
def crack()
(@password_range).each do |password_length| # loop to gradually increase password length
num_combinations=@char_array.length**password_length
password, perm_number = do_combination(num_combinations, password_length)
if password
puts "#{password} | Access Granted | #{perm_number} / #{num_combinations}"
return password
end
end
end
end
cracker = Cracker.new( "ABCD".split(//), (5..15) )
password = cracker.crack()
John Sietsma
October 14, 2008, October 14, 2008 01:20, permalink
*EDIT* Removed smart-arse comments about trolls.
In this refactor I've tried to flatten the nested loops and bring the important code back to the caller. The closures and co-routines of Ruby (and other languages) make this easy without excessive memory usage.
I'm curious to know whether people think this sort refactoring is worthwhile? I'm not entirely sure if it's worth the extra code. Perhaps just a yield in the original code would bring the code to the caller without the extra bloat from flattening the nestings.
#!/bin/ruby
class Cracker
def initialize(char_array, password_range)
@char_array = char_array
@password_range = password_range
end
def make_password( perm_number, password_length )
password = (1..password_length).map do |char_number|
char_reference = (perm_number / @char_array.length**(char_number-1)).floor % @char_array.length
@char_array[char_reference]
end
password.to_s
end
def password_combinations( password_length )
num_combinations = @char_array.length**password_length
(0..num_combinations-1).map do |perm_number|
yield make_password( perm_number, password_length )
end
end
def all_passwords()
@password_range.map do |password_length|
password_combinations(password_length) do |password|
yield password;
end
end
end
def crack()
all_passwords() do |password|
return password if yield password
end
return nil
end
end
#-------------------------------------
# Caller code
def password_correct?(test_password)
test_password == "DCBAAAA"
end
cracker = Cracker.new( "ABCD".split(//), (5..15) )
password = cracker.crack() do |test_password|
password_correct? test_password
end
if password
puts "#{password} | Access Granted"
end
Adam
October 14, 2008, October 14, 2008 04:50, permalink
Array#combination requires Ruby 1.9. If you re-implement it, it should otherwise work with earlier Ruby versions.
require 'set'
module Cracker
class Password
attr_reader :characters, :range
def initialize(characters, range)
@characters, @range = characters.split(''), Array(range)
end
def each(&block)
range.each { |length| Combination.new(characters, length).each(&block) }
end
end
class Combination < Struct.new(:characters, :length)
def characters
super * length
end
def each(&block)
combinations = Set.new
characters.combination(length).each do |combination|
yield(combination.join) unless combinations.include?(combination)
combinations << combination
end
end
end
end
Cracker::Password.new("ABCD", 5..15).each do |password|
password_correct?(password)
end
Xac Stegner
April 14, 2009, April 14, 2009 21:44, permalink
This is what I came up with.
class Cracker
attr_accessor :current
OPTS = [('a'..'z'),('A'..'Z'),('0'..'9')].map{|n| n.to_a }.flatten
def initialize(pass)
@current = OPTS.first
crack while @current != pass
puts "Password is #{@current}"
end
def crack
current_array = @current.split(//)
if current_array.all? {|o| o == OPTS.last}
current_array = [OPTS.first]*(current_array.length+1)
else
poped = []
poped << current_array.pop while current_array.last == OPTS.last
last = current_array.pop
current_array.push OPTS[OPTS.index(last)+1]
current_array += ([OPTS.first]*poped.length)
end
@current = current_array.join
end
end
Just a quick-and-dirty for a brute force attack. I made this to break into my router, because I wanted to check the settings (so a hard system restore wouldn't work because it would wipe them). I've included a little test method instead of the actual login script and reduced the selection of characters (characters_to_use) to help with speed of testing. I'd be interested to see what people come up with.