Module: NmapAutoAnalyzer
- Defined in:
- lib/nmap_auto_analyzer.rb,
lib/nmap_auto_analyzer/version.rb
Constant Summary collapse
- VERSION =
"0.0.1"
Instance Attribute Summary collapse
-
#execute ⇒ Object
Returns the value of attribute execute.
-
#options ⇒ Object
Returns the value of attribute options.
-
#parsed_hosts ⇒ Object
Returns the value of attribute parsed_hosts.
-
#scan_files ⇒ Object
Returns the value of attribute scan_files.
-
#scanned_files ⇒ Object
Returns the value of attribute scanned_files.
-
#valid_entries ⇒ Object
Returns the value of attribute valid_entries.
Class Method Summary collapse
- .excel_report ⇒ Object
- .execute(commandlineopts) ⇒ Object
-
.html_report ⇒ Object
Generates an HTML report with the results.
-
.parse_files ⇒ Object
Parses the nmap xml files and populates the arrays needed by the report.
-
.report ⇒ Object
Generates a kramdown compatible report that we can use to generate an HTML report.
-
.run ⇒ Object
Sets up the process for scanning the xml files and calls the individual methods depending on the scan type.
-
.scan_dirs ⇒ Object
Adds all the xml files in the directory being scanned to the scan_files array.
Instance Attribute Details
#execute ⇒ Object
Returns the value of attribute execute.
5 6 7 |
# File 'lib/nmap_auto_analyzer.rb', line 5 def execute @execute end |
#options ⇒ Object
Returns the value of attribute options.
5 6 7 |
# File 'lib/nmap_auto_analyzer.rb', line 5 def @options end |
#parsed_hosts ⇒ Object
Returns the value of attribute parsed_hosts.
5 6 7 |
# File 'lib/nmap_auto_analyzer.rb', line 5 def parsed_hosts @parsed_hosts end |
#scan_files ⇒ Object
Returns the value of attribute scan_files.
5 6 7 |
# File 'lib/nmap_auto_analyzer.rb', line 5 def scan_files @scan_files end |
#scanned_files ⇒ Object
Returns the value of attribute scanned_files.
5 6 7 |
# File 'lib/nmap_auto_analyzer.rb', line 5 def scanned_files @scanned_files end |
#valid_entries ⇒ Object
Returns the value of attribute valid_entries.
5 6 7 |
# File 'lib/nmap_auto_analyzer.rb', line 5 def valid_entries @valid_entries end |
Class Method Details
.excel_report ⇒ Object
317 318 319 320 321 322 323 324 325 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 354 |
# File 'lib/nmap_auto_analyzer.rb', line 317 def self.excel_report begin require 'rubyXL' rescue LoadError puts "Couldn't load rubyXL, try gem install rubyXL" exit end workbook = RubyXL::Workbook.new sheet = workbook.worksheets[0] sheet.add_cell(0,0,"IP Address") sheet.add_cell(0,1,"TCP Ports") sheet.add_cell(0,2,"UDP Ports") curr_row = 1 sorted_hosts = @parsed_hosts.sort_by {|address,find| address.split('.').map{ |digits| digits.to_i}} sorted_hosts.each do |entry| host, ports = entry[0], entry[1] next if ports.length == 0 tcp_ports = Array.new udp_ports = Array.new ports.each do |port,data| portnum, protocol = port.split(' - ') if protocol == 'TCP' tcp_ports << portnum elsif protocol == 'UDP' udp_ports << portnum end end sheet.add_cell(curr_row,0,host) sheet.add_cell(curr_row,1,tcp_ports.join(', ')) sheet.add_cell(curr_row,2,udp_ports.join(', ')) curr_row = curr_row + 1 end workbook.write(@excel_report_file_name) end |
.execute(commandlineopts) ⇒ Object
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 |
# File 'lib/nmap_auto_analyzer.rb', line 7 def self.execute(commandlineopts) @options = commandlineopts require 'rubygems' require 'logger' @base_dir = @options.report_directory @scan_dir = @options.scan_directory if !File.exists?(@base_dir) Dir.mkdirs(@base_dir) end @log = Logger.new(@base_dir + '/nmap-analyzer-log') @log.level = Logger::DEBUG @log.debug("Log created at " + Time.now.to_s) @log.debug("Scan type is : #{@options.scan_type}") @log.debug("Directory being scanned is : #{@options.scan_directory}") if @options.scan_type == :directory @log.debug("File being scanned is : #{@options.scan_file}") if @options.scan_type == :file @report_file_name = @base_dir + '/' + @options.report_file @report_file = File.new(@report_file_name + '.txt','w+') @html_report_file = File.new(@report_file_name + '.html','w+') @excel_report_file_name = @report_file_name + '.xlsx' @log.info("New report file created #{@report_file_name}") run end |
.html_report ⇒ Object
Generates an HTML report with the results
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/nmap_auto_analyzer.rb', line 300 def self.html_report begin require 'kramdown' rescue LoadError puts "Couldn't load kramdown, try gem install kramdown" exit end base_report = File.open(@report_file_name + '.txt','r').read report = Kramdown::Document.new(base_report) @html_report_file.puts report.to_html end |
.parse_files ⇒ Object
Parses the nmap xml files and populates the arrays needed by the report
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/nmap_auto_analyzer.rb', line 78 def self.parse_files #Hash to put the information for each host into @parsed_hosts = Hash.new @scanned_files = Hash.new @closed_ports = Array.new #Ports is an array to contain a list of the unique ports encountered for later feeding to Nessus @ports = Array.new #port_hash is a hash to contain a list of ports and what hosts have them open @port_hash = Hash.new @traceroute_hash = Hash.new @os_hash = Hash.new @web_headers_hash = Hash.new @scan_files.each do |file| begin parser = Nmap::Parser.parsefile(file) rescue IOError => e @log.warn("Warning couldn't parse file #{file}") puts "Couldn't parse file #{file}, check to make sure it wasn't critical!!" next rescue REXML::ParseException @log.warn("Warning, couldn't parse file #{file} due to an XML parse error") puts "Warning, couldn't parse file #{file} due to an XML parse error" next end @scanned_files[file] = Hash.new unless @scanned_files[file] @scanned_files[file][:scan_args] = parser.session.scan_args if parser.session.scan_args @scanned_files[file][:scan_time] = parser.session.scan_time if parser.session.scan_time parser.hosts("up") do |host| #TODO: we should add UDP here too, but watch for no-response otherwise we'll get false positive centraled. next if @options.ignore_chatty && host.tcp_ports("open").length > 900 @parsed_hosts[host.addr] = Hash.new unless @parsed_hosts[host.addr] host.extraports.each do |portstate| if portstate.state == "closed" && portstate.count > 1 @closed_ports << host.addr end end #Add Traceroute information and grab the last hop before the host #It's either the last hop or the one before it #So it looks to me that nmaps traceroute isn't quite right for this #produces different results to traceroute... #if host.traceroute # @log.debug("host address is " + host.addr + "Last traceroute is" + host.traceroute.hops[-1].addr) # if host.traceroute.hops[-1].addr != host.addr || host.traceroute.hops.length == 1 # last_hop = host.traceroute.hops[-1].addr.to_s # else # last_hop = host.traceroute.hops[-2].addr.to_s # end # @traceroute_hash[host.addr] = last_hop #end #Add OS guess information if host.os.name @os_hash[host.addr] = host.os.name + ', ' + host.os.name_accuracy.to_s end host.tcp_ports("open") do |port| #Add the port to the ports array @ports << port.num.to_s #Add the port to the port hash if @port_hash[port.num.to_s + '-TCP'] @port_hash[port.num.to_s + '-TCP'] << host.addr else @port_hash[port.num.to_s + '-TCP'] = Array.new @port_hash[port.num.to_s + '-TCP'] << host.addr end @parsed_hosts[host.addr][port.num.to_s + ' - TCP'] = Hash.new @parsed_hosts[host.addr][port.num.to_s + ' - TCP'][:service] = port.service.name if port.service.name @parsed_hosts[host.addr][port.num.to_s + ' - TCP'][:reason] = port.reason if port.reason @parsed_hosts[host.addr][port.num.to_s + ' - TCP'][:product] = port.service.product if port.service.product if host.tcp_script(port.num.to_s, 'http-methods') @web_headers_hash[host.addr + ':' + port.num.to_s] = host.tcp_script(port.num.to_s, 'http-methods').output.split("\n")[0] end end host.udp_ports("open") do |port| next if port.reason == "no-response" #Add the port to the ports array @ports << port.num.to_s #Add the port to the port hash if @port_hash[port.num.to_s + '-UDP'] @port_hash[port.num.to_s + '-UDP'] << host.addr else @port_hash[port.num.to_s + '-UDP'] = Array.new @port_hash[port.num.to_s + '-UDP'] << host.addr end @parsed_hosts[host.addr][port.num.to_s + ' - UDP'] = Hash.new @parsed_hosts[host.addr][port.num.to_s + ' - UDP'][:service] = port.service.name if port.service.name @parsed_hosts[host.addr][port.num.to_s + ' - UDP'][:reason] = port.reason if port.reason @parsed_hosts[host.addr][port.num.to_s + ' - UDP'][:product] = port.service.product if port.service.product end end end #Once we're done with the files clean up the ports array @ports.uniq! end |
.report ⇒ Object
Generates a kramdown compatible report that we can use to generate an HTML report
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 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 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/nmap_auto_analyzer.rb', line 179 def self.report @report_file.puts "NMAP AUTO analysis" @report_file.puts "===================\n\n" @report_file.puts "Unique ports open" @report_file.puts "-------------------\n\n" @report_file.puts @ports.join(', ') @report_file.puts "\n\n" @report_file.puts "NMAP Host Analysis" @report_file.puts "-------------------" @report_file.puts "" @report_file.puts "Active Host List" @report_file.puts "---------" active_ipaddresses = Array.new inactive_ipaddresses = Array.new @parsed_hosts.each do |entry| host, ports = entry[0], entry[1] if ports.length > 0 active_ipaddresses << host else inactive_ipaddresses << host end end @report_file.puts active_ipaddresses.uniq.join(', ') @report_file.puts "" @report_file.puts "" @report_file.puts "Inactive Host List" @report_file.puts "---------" @report_file.puts inactive_ipaddresses.uniq.join(', ') @report_file.puts "" @report_file.puts "" if @traceroute_hash.length > 0 @report_file.puts "Traceroute Information" @report_file.puts "---------" @report_file.puts "Target Address, Last Hop" @traceroute_hash.each do |addr, last_hop| @report_file.puts addr + ", " + last_hop end @report_file.puts "" @report_file.puts "" end if @os_hash.length > 0 @report_file.puts "Operating System Information" @report_file.puts "---------" @report_file.puts "Target Address, OS Guess, OS Accuracy" @os_hash.each do |addr, os| @report_file.puts addr + ", " + os end @report_file.puts "" @report_file.puts "" end if @web_headers_hash.length > 0 @report_file.puts "Operating System Information" @report_file.puts "---------" @report_file.puts "Target Web Server, Supported Methods" @web_headers_hash.each do |addr, methods| @report_file.puts addr + ", " + methods end @report_file.puts "" @report_file.puts "" end #sorted_hosts = @parsed_hosts.sort {|a,b| b[1].length <=> a[1].length} sorted_hosts = @parsed_hosts.sort_by {|address,find| address.split('.').map{ |digits| digits.to_i}} sorted_hosts.each do |entry| host, ports = entry[0], entry[1] #This omits any hosts that were deemed up but had no open ports #TODO: Make this an option in reporting (verbose against concise) next if ports.length == 0 @report_file.puts "Host address: #{host} was detected as up by nmap" @report_file.puts "------------------------------------------------" @report_file.puts "" if ports.length == 0 @report_file.puts "No Ports detected as open on this host" end ports.each do |port, data| @report_file.print "Port #{port} is open " @report_file.print ", Service name is #{data[:service]}" if data[:service] @report_file.print ", Service Product name is #{data[:product]}" if data[:product] @report_file.print ", Up reason is #{data[:reason]}" if data[:reason] @report_file.puts "" end @report_file.puts "" @report_file.puts "-------------------" @report_file.puts "" end @report_file.puts "\n\nReport of hosts with a given port open" @report_file.puts "--------------------\n\n" @port_hash.each do |port,hosts| @report_file.puts port + ' - ' + hosts.uniq.length.to_s + ' hosts have this port open' @report_file.puts "-----------------" @report_file.puts hosts.uniq.join(', ') @report_file.puts "\n\n" end @report_file.puts "\n\nActive Hosts with Closed Ports" @report_file.puts "--------------------\n\n" @report_file.puts @closed_ports.uniq.join(', ') @report_file.puts "--------------------\n\n" active_ipaddresses.each do |add| result = "n" result = "y" if @closed_ports.include?(add) @report_file.puts add + ', ' + result end #TODO: Make this an option in terms of reporting volume @report_file.puts "\n\nNMAP runs analysed" @scanned_files.each do |file, data| @report_file.puts "\n-------------------" @report_file.puts file @report_file.puts "Scan arguments were #{data[:scan_args]}" @report_file.puts "Scan Time was #{data[:scan_time]}" end @report_file.close end |
.run ⇒ Object
Sets up the process for scanning the xml files and calls the individual methods depending on the scan type
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/nmap_auto_analyzer.rb', line 37 def self.run case @options.scan_type #Directory Mode when :directory @valid_entries = Array.new @valid_entries << '' scan_dirs parse_files report excel_report if @options.html_report html_report end #File Mode when :file @scan_files = Array.new @scan_files << @options.scan_file parse_files report excel_report if @options.html_report html_report end end end |
.scan_dirs ⇒ Object
Adds all the xml files in the directory being scanned to the scan_files array
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/nmap_auto_analyzer.rb', line 65 def self.scan_dirs @scan_files = Array.new @valid_entries.each do |dir| Dir.entries(@scan_dir + dir).each do |scan| if scan =~ /xml$/ @scan_files << @scan_dir + dir + '/' + scan end end end end |