D5145c421cd25af6fa577c15219add90

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.

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
#!/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 !

6dc0e9a07bcff97ac9b111f36e12f1f6

Ishkur

October 11, 2008, October 11, 2008 02:36, permalink

No rating. Login to rate!

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?

37ce1520d319fa8095d05aa475951616

John Sietsma

October 13, 2008, October 13, 2008 11:07, permalink

No rating. Login to rate!

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.

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
#!/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()
37ce1520d319fa8095d05aa475951616

John Sietsma

October 14, 2008, October 14, 2008 01:20, permalink

No rating. Login to rate!

*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.

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
#!/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
A8d3f35baafdaea851914b17dae9e1fc

Adam

October 14, 2008, October 14, 2008 04:50, permalink

2 ratings. Login to rate!

Array#combination requires Ruby 1.9. If you re-implement it, it should otherwise work with earlier Ruby versions.

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
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

Your refactoring





Format Copy from initial code

or Cancel