Skip to content

Instantly share code, notes, and snippets.

@sstelfox
Last active August 29, 2015 14:08
Show Gist options
  • Save sstelfox/24166a636cb0aebe1f3f to your computer and use it in GitHub Desktop.
Save sstelfox/24166a636cb0aebe1f3f to your computer and use it in GitHub Desktop.
A fast and dirty parser for turning a kismet XML file into a more organized KML file.
source "https://rubygems.org"
gem 'nokogiri'
gem 'ruby_kml'
GEM
remote: https://rubygems.org/
specs:
builder (3.2.2)
mini_portile (0.6.1)
nokogiri (1.6.4)
mini_portile (~> 0.6.0)
ruby_kml (0.1.7)
builder
nokogiri
PLATFORMS
ruby
DEPENDENCIES
nokogiri
ruby_kml
#!/usr/bin/env ruby
# Copyright (c) 2014 Sam Stelfox
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
require 'nokogiri'
require 'optparse'
require 'ruby_kml'
options = {
input: nil,
output: 'organized_scan.kml'
}
cli_parser = OptionParser.new(nil, 32, ' ')
cli_parser.on('-i', '--input FILE', 'Path to input XML file from Kismet output') do |f|
options[:input] = f
end
cli_parser.on('-o', '--output FILE', 'Path to store output KML file') do |f|
options[:output] = f
end
cli_parser.on('-h', '--help', 'Show this message') do |f|
puts cli_parser.help
exit
end
cli_parser.parse!(ARGV)
if options[:input].nil?
puts "An input file needs to be provided\n\n"
puts cli_parser.help
exit
end
xml = Nokogiri::XML(File.open(options[:input]), 'r')
nodes = xml.xpath('//wireless-network[@type="infrastructure"]')
ap_list = {}
nodes.each do |n|
bssid = n.xpath('BSSID')[0].text.downcase
channel = n.xpath('channel').text.to_i
next if bssid == '00:00:00:00:00:00' || channel == 0
lat = ((n.xpath('gps-info/min-lat').text.to_f + n.xpath('gps-info/max-lat').text.to_f) / 2)
lon = ((n.xpath('gps-info/min-lon').text.to_f + n.xpath('gps-info/max-lon').text.to_f) / 2)
clients = n.xpath('wireless-client').map do |c|
{
mac: c.xpath('client-mac').text.downcase,
manufacturer: c.xpath('client-manuf').text
}
end
ap_list[bssid] = {
bssid: bssid,
cloaked: (n.xpath('SSID/essid').attribute('cloaked').value == 'true'),
ssid: n.xpath('SSID/essid').text,
encryption: n.xpath('SSID/encryption').map(&:text),
channel: channel,
latitude: lat,
longitude: lon,
clients: clients
}
end
def ap_to_description(ap)
output = "<h4>Access Point Info</h4><hr/>BSSID: #{ap[:bssid]}<br/>"
output += "Cloaked: #{ap[:cloaked]}<br/>"
output += "Encryption: #{ap[:encryption].join(", ")}<br/>"
output += "Channel: #{ap[:channel]}<br/>"
output += "<h4>Clients (#{ap[:clients].count})</h4><hr/>"
output += "<table><thead><tr><td>Mac</td><td>Manufacturer</td></thead><tbody>"
ap[:clients].each do |c|
output += "<tr><td>#{c[:mac]}</td><td>#{c[:manufacturer]}</td></tr>"
end
output += "</tbody></table>"
output
end
kml_file = KMLFile.new
document = KML::Document.new(:name => 'Wireless Scan Report', :open => true)
folders = {}
ap_list.map { |_, ap| ap[:encryption] }.flatten.uniq.sort.each do |enc|
folders[enc] = KML::Folder.new(name: enc, open: false)
end
ap_list.each do |_, ap|
ap_placemark = KML::Placemark.new(
name: "#{ap[:ssid]}",
description: ap_to_description(ap),
geometry: KML::Point.new(coordinates: [ap[:longitude], ap[:latitude]]),
visibility: false
)
ap[:encryption].each { |e| folders[e].features << ap_placemark }
end
folders.each { |_, f| document.features << f }
kml_file.features << document
File.write(options[:output], kml_file.render)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment