Class: Honeycomb::Interact
- Inherits:
-
Object
- Object
- Honeycomb::Interact
- Defined in:
- lib/honeycomb/interact/interact.rb
Instance Attribute Summary collapse
-
#base_path ⇒ Object
Returns the value of attribute base_path.
-
#bin_path ⇒ Object
Returns the value of attribute bin_path.
-
#db_path ⇒ Object
Returns the value of attribute db_path.
-
#key ⇒ Object
Returns the value of attribute key.
-
#servers ⇒ Object
Returns the value of attribute servers.
-
#username ⇒ Object
Returns the value of attribute username.
Class Method Summary collapse
-
.get_all_md5_info(dir = Pathname.new(__FILE__).dirname.dirname.dirname.dirname.expand_path.join('data').join('binaries/').to_s) ⇒ Object
This method will call the get_md5_info method on all binaries located in the provided directory.
-
.get_md5_info(md5) ⇒ Object
Only leaving this in here because it does a decent job of showing some of the stuff you can do with these DataMapper database bindings.
-
.ip_reputation_rule ⇒ Object
This method was created mainly for my own benefit, but I figured I’d leave it in here in case anyone else would like to use it.
Instance Method Summary collapse
-
#all(&block) ⇒ Object
Used for executing a query against all databases at once.
-
#check_diskspace ⇒ Object
This method will query the diskspace on all remote servers by calling the internal ssh_command method.
-
#download_binaries(server = self.servers) ⇒ Object
This method will attempt to download all binaries from all servers specified in Honeycomb::Interact.servers.
-
#download_databases(server = self.servers) ⇒ Object
This method will attempt to download all databases from all servers specified in Honeycomb::Interact.servers.
-
#execute_command(command) ⇒ Object
This method will execute a command via ssh on all servers specified in the Honeycomb::Interact.servers variable.
-
#individual(repo, &block) ⇒ Object
Used for executing a query against a single database.
-
#initialize(db_path = nil, bin_path = nil, username = nil, key = nil, servers = nil, base_path = nil) ⇒ Interact
constructor
This initializes a Honeycomb::Interact object and sets all the necessary variables which are used by other methods of the object.
-
#ssh_command(command) ⇒ Object
This method is used internally by the execute_command method.
Constructor Details
#initialize(db_path = nil, bin_path = nil, username = nil, key = nil, servers = nil, base_path = nil) ⇒ Interact
This initializes a Honeycomb::Interact object and sets all the necessary variables which are used by other methods of the object.
Variables and their purpose:
-
db_path - Path where databases are stored/saved
-
bin_path - Path where binaries are stored/saved
-
username - Username to connect to remote honeypot servers
-
key - Path to private key which is used for connections to honeypot
servers
-
servers - Array of servers to connect to
-
base_path - Base location where Dionaea is installed to (Default per installation instructions: /opt/dionaea)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/honeycomb/interact/interact.rb', line 42 def initialize(db_path = nil, bin_path = nil, username = nil, key = nil, servers = nil, base_path = nil) self.db_path = Honeycomb::Env::CONFIG[:download_databases] || self.db_path = Pathname.new(__FILE__).dirname.dirname.dirname.dirname..join('data').join('logsql/').to_s || db_path self.bin_path = Honeycomb::Env::CONFIG[:download_binaries] || self.bin_path = Pathname.new(__FILE__).dirname.dirname.dirname.dirname..join('data').join('binaries/').to_s || bin_path self.username = Honeycomb::Env::CONFIG["honey_config"]["username"] || username self.key = Honeycomb::Env::CONFIG["honey_config"]["key"] || key self.servers = Honeycomb::Env::CONFIG["honey_config"]["servers"] || servers self.base_path = Honeycomb::Env::CONFIG["honey_config"]["path"] || base_path end |
Instance Attribute Details
#base_path ⇒ Object
Returns the value of attribute base_path.
28 29 30 |
# File 'lib/honeycomb/interact/interact.rb', line 28 def base_path @base_path end |
#bin_path ⇒ Object
Returns the value of attribute bin_path.
28 29 30 |
# File 'lib/honeycomb/interact/interact.rb', line 28 def bin_path @bin_path end |
#db_path ⇒ Object
Returns the value of attribute db_path.
28 29 30 |
# File 'lib/honeycomb/interact/interact.rb', line 28 def db_path @db_path end |
#key ⇒ Object
Returns the value of attribute key.
28 29 30 |
# File 'lib/honeycomb/interact/interact.rb', line 28 def key @key end |
#servers ⇒ Object
Returns the value of attribute servers.
28 29 30 |
# File 'lib/honeycomb/interact/interact.rb', line 28 def servers @servers end |
#username ⇒ Object
Returns the value of attribute username.
28 29 30 |
# File 'lib/honeycomb/interact/interact.rb', line 28 def username @username end |
Class Method Details
.get_all_md5_info(dir = Pathname.new(__FILE__).dirname.dirname.dirname.dirname.expand_path.join('data').join('binaries/').to_s) ⇒ Object
This method will call the get_md5_info method on all binaries located in the provided directory. This information is then outputted to screen (soon to be changed).
Again, only leaving this in here because it does a decent job of showing the kind of information you can pull.
Argument:
-
dif - Directory of binaries
Retruns:
-
Nothing
Multiple items are outputted to the screen.
255 256 257 258 259 260 261 262 263 264 |
# File 'lib/honeycomb/interact/interact.rb', line 255 def self.get_all_md5_info(dir = Pathname.new(__FILE__).dirname.dirname.dirname.dirname..join('data').join('binaries/').to_s) results = [] all_binaries = Dir.entries(dir) all_binaries.each do |bin| if bin =~ /\w{32}/ require 'pp' pp self.get_md5_info(bin) end end end |
.get_md5_info(md5) ⇒ Object
Only leaving this in here because it does a decent job of showing some of the stuff you can do with these DataMapper database bindings.
This method was mainly created to be utilized for another project. It takes the md5 as in argument and performs a series of queries against all of the database to retrieve a large amount of data about that provided binary (in md5 checksum)
Multiple encounters can be returned. These encounters are uniqued based on the URL of the download. Additionally, if duplicates of a given url are discovered, the encounter with the earliest timestamp is added to the hash.
Argument:
-
md5 - MD5 String of the binary to be examined.
Returns:
-
Hash - => <md5_provided>,
:encounters = [{ :url => <url_discovered>, :original_filename => <md5_provided>, :remote_host => <ip_address>, :source_timestamp => <Time>, :source => "Honeypot - <ip_address>", :virustotal => {:url => <url>, :timestamp => <timestamp_of_vt_scan>, :results => {:scanner => <scanner>, :result => <result> } }
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 |
# File 'lib/honeycomb/interact/interact.rb', line 196 def self.get_md5_info(md5) all_encounters = [] all_instances = self.all{Honeycomb::Download.all(:download_md5_hash => md5)} all_instances.each do |instance| all_encounters << {:url => instance.download_url} end num = 0 all_encounters.uniq! {|e| e[:url] } all_encounters.each do |url| all_connections = self.all{Honeycomb::Download.all(:download_md5_hash => md5, :download_url => url[:url]).connections} connection = {} all_connections.each do |conn| if not connection[:source_timestamp].nil? if Time.at(connection[:source_timestamp]) > Time.at(conn..to_i) connection[:source_timestamp] = Time.at(conn..to_i) connection[:remote_host] = conn.remote_host connection[:source] = conn.local_host end else connection[:source_timestamp] = Time.at(conn..to_i) connection[:remote_host] = conn.remote_host connection[:source] = conn.local_host end end all_encounters[num][:original_filename] = md5 all_encounters[num][:remote_host] = connection[:remote_host] all_encounters[num][:source_timestamp] = connection[:source_timestamp] all_encounters[num][:source] = "Honeypot - #{connection[:source]}" virustotal_links = self.all{Honeycomb::Virustotal.first(:virustotal_md5_hash => md5).virustotal_permalink} = self.all{Honeycomb::Virustotal.first(:virustotal_md5_hash => md5).} virustotal_results = {} self.all{Honeycomb::Virustotal.first(:virustotal_md5_hash => md5).virustotalscans}.each do |vtscan| virustotal_results[:scanner] = vtscan.virustotalscan_scanner virustotal_results[:result] = vtscan.virustotalscan_result end all_encounters[num][:virustotal] = {:url => virustotal_links, :timestamp => , :results => virustotal_results} if virustotal_links num += 1 end return {:md5 => md5, :encounters => all_encounters} end |
.ip_reputation_rule ⇒ Object
This method was created mainly for my own benefit, but I figured I’d leave it in here in case anyone else would like to use it. Was doing some statistics for a co-worker who was looking for information about the IP addresses which has connected to my honeypots.
It’s a little clunky right now, and I ended up just performing actual SQL queries due to memory issues (Some of my databases are over 10 gigs in size). It will write a list of IP addresses and the number of times encountered to the following log file:
ip_reputation.txt
The format of the data is:
<ip_address>,<count>
In order from most encountered to least encountered. I also ignore people that have connected to these honeypots less than 200 times.
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 |
# File 'lib/honeycomb/interact/interact.rb', line 326 def self.ip_reputation_rule all_connections_hash = {} ::DataMapper::Repository.adapters.each do |repo| if repo[0] == :default next end response = repo[1].select("SELECT COUNT(remote_host), remote_host FROM connections WHERE connection_type = \"accept\" GROUP BY remote_host ORDER BY COUNT(remote_host)") response.each do |struct| ip = struct.to_a[1] count = struct.to_a[0] if all_connections_hash[ip] all_connections_hash[ip] = all_connections_hash[ip].to_i + count.to_i else all_connections_hash[ip] = count.to_i end end end all_connections_hash = all_connections_hash.sort_by { |k,v| -1*v } File.open("ip_reputation.txt", 'w') do |f| all_connections_hash.each do |ip,count| if count > 200 f.write("#{ip},#{count}\n") end end end end |
Instance Method Details
#all(&block) ⇒ Object
Used for executing a query against all databases at once.
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/honeycomb/interact/interact.rb', line 267 def all(&block) all_values = [] ::DataMapper::Repository.adapters.each do |repo| if repo[0] == :default next end begin response = DataMapper.repository(repo[0]) {yield} if response.kind_of?(DataMapper::Collection) response.each do |x| all_values << x end else all_values << response if response end rescue Exception => e #puts e.message end end all_values end |
#check_diskspace ⇒ Object
This method will query the diskspace on all remote servers by calling the internal ssh_command method. It executes the command ‘df -h /’ and parses the results. The response is then parsed to return the total percentage of diskspace being used currently on each host.
Arguments:
-
None
Returns:
-
[ {:server => “Server Hostname”, :result =>
Multiple strings with the results are outputted to the screen.
154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/honeycomb/interact/interact.rb', line 154 def check_diskspace response = self.ssh_command("df -h /") all_usage = [] response.each do |server_hash| usage = server_hash[:result] if usage =~ /^(\/\w+)+.+\S+\s+\S+\s+\S+\s+(([0-9]+)%)/m all_usage << {:server => server_hash[:server], :result => $2} end end all_usage end |
#download_binaries(server = self.servers) ⇒ Object
This method will attempt to download all binaries from all servers specified in Honeycomb::Interact.servers.
It will attempt to store all binaries into the folder specified in Honeycomb::Interact.bin_path.
Additionally, rsync is utilized to transfer these files. It was chosen to use rsync over scp in order to limit the amount of bandwidth used between the client and servers.
Arguments:
-
server - Array of servers to query
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/honeycomb/interact/interact.rb', line 71 def download_binaries(server = self.servers) server.each do |server| tries = 0 puts "Downloading binaries from #{server} ..." begin Open3::popen3("rsync -v --force --ignore-errors --times -r -u -e \"ssh -i #{self.key}\" #{self.username}@#{server}:#{self.base_path}/var/dionaea/binaries/ #{self.bin_path}") { |stdin, stdout, stderr| puts stdout.read.strip puts stderr.read.strip } rescue tries += 1 retry if tries <= 3 puts "Unable to connect. Moving on ..." next end end end |
#download_databases(server = self.servers) ⇒ Object
This method will attempt to download all databases from all servers specified in Honeycomb::Interact.servers.
It will attempt to store all binaries into the folder specified in Honeycomb::Interact.db_path.
Additionally, scp is utilized to transfer these files. During tests, it was discovered that rsync had less than ideal results when downloading these files. While the transfer would appear to occur without error, the databases were often found to be corrupt.
Arguments:
-
server - Array of servers to query
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/honeycomb/interact/interact.rb', line 102 def download_databases(server = self.servers) server.each do |server| tries = 0 begin Net::SSH.start(server, self.username, :keys => self.key) do |session| puts "Downloading database from #{server} ..." session.scp.download!(base_path + "/var/dionaea/logsql.sqlite", self.db_path + "#{server}.sqlite") end rescue Errno::ETIMEDOUT tries += 1 retry if tries <= 3 puts "Unable to connect. Moving on ..." next rescue Exception => e puts "Error encountered: #{e.}" next end end end |
#execute_command(command) ⇒ Object
This method will execute a command via ssh on all servers specified in the Honeycomb::Interact.servers variable. This command calls the internal ssh_command method in order to properly function.
Argument:
-
command - Command to execute
Returns:
-
Nothing
Multiple strings with the results are outputted to the screen.
134 135 136 137 138 139 140 |
# File 'lib/honeycomb/interact/interact.rb', line 134 def execute_command(command) response = self.ssh_command(command) response.each do |server_hash| puts "Executing #{command} on #{server_hash[:server]}:" puts "\t#{server_hash[:result].gsub!(/\n/,"\n\t")}" end end |
#individual(repo, &block) ⇒ Object
Used for executing a query against a single database.
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/honeycomb/interact/interact.rb', line 290 def individual(repo, &block) all_values = [] begin response = DataMapper.repository(repo[0]) {yield} if response.kind_of?(DataMapper::Collection) response.each do |x| all_values << x end else all_values << response if response end rescue Exception => e #puts e.message end all_values end |
#ssh_command(command) ⇒ Object
This method is used internally by the execute_command method. It will take a command as an argument and execute it on ever server that is stored in Honeycomb::Interact.servers. The results are stored in a hash which is returned in an Array.
Argument:
-
command - Command to be executed
Returns:
-
Array of hashes -
- => <server_name>, :result => <result_of_command>
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/honeycomb/interact/interact.rb', line 366 def ssh_command(command) results = [] self.servers.each do |server| begin Net::SSH.start(server, self.username, :keys => self.key) do |session| session.exec command do |ch, stream, data| if stream == :stderr results << {:server => server, :result => "ERROR: #{data}"} else results << {:server => server, :result => data} end end end rescue next end end return results end |