nmunch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ results.html
3
+ pkg
4
+ html
5
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nmunch.gemspec
4
+ gemspec
@@ -0,0 +1,33 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nmunch (1.0.0)
5
+ methadone (~> 1.2.3)
6
+ paint
7
+ pcap
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ diff-lcs (1.1.3)
13
+ methadone (1.2.3)
14
+ bundler
15
+ paint (0.8.5)
16
+ pcap (0.7.7)
17
+ rake (0.9.5)
18
+ rspec (2.12.0)
19
+ rspec-core (~> 2.12.0)
20
+ rspec-expectations (~> 2.12.0)
21
+ rspec-mocks (~> 2.12.0)
22
+ rspec-core (2.12.1)
23
+ rspec-expectations (2.12.0)
24
+ diff-lcs (~> 1.1.3)
25
+ rspec-mocks (2.12.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ nmunch!
32
+ rake (~> 0.9.2)
33
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Michael Henriksen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,103 @@
1
+ # Nmunch
2
+
3
+ ![OM NOM NOM NOM](https://dl.dropbox.com/u/70881769/omnomnomnom.jpg)
4
+
5
+ Nmunch is a simple passive network discovery tool to find live nodes just by
6
+ listening to [ARP][arp] and broadcast packets on a network interface.
7
+
8
+ The main reason why I built this tool was mostly to have an excuse to play around
9
+ with the [ruby-pcap gem][ruby-pcap], but it turned out to be quite useful and the
10
+ architecture is flexible enough to extend the tool to do pretty much anything
11
+ with a discovered node.
12
+
13
+ ## Requirements
14
+
15
+ - Ruby 1.9
16
+ - libpcap (<http://www.tcpdump.org/>)
17
+
18
+ ## Installation
19
+
20
+ gem install nmunch
21
+
22
+ ## Usage
23
+
24
+ ![Nmunch munching](https://dl.dropbox.com/u/70881769/nmunch.png "Nmunch munching packets on a network")
25
+
26
+ Nmunch is pretty straight-forward and supports two different methods:
27
+
28
+ ### Listen on a network device
29
+
30
+ nmunch -i <device name>
31
+
32
+ To find the names of your network devices, use `ifconfig` in a terminal. Usually,
33
+ they are called `eth0`, `en1`, etc.
34
+
35
+ To stop listening, simply press `Ctrl`+`C` to interrupt. It might take a couple of
36
+ seconds before it reacts.
37
+
38
+
39
+ ### Analyze a PCAP capture file
40
+
41
+ Nmunch can also find nodes from a `pcap` capture file:
42
+
43
+ nmunch -f <path/to/pcap/file.pcap>
44
+
45
+ ### See all options
46
+
47
+ To see all options for Nmunch, type:
48
+
49
+ nmunch --help
50
+
51
+ ## Extending Nmunch
52
+
53
+ I have tried to keep the architecture pretty flexible with a simple *publish/subscribe* pattern for handling the discovered nodes. So if you want all nodes to be pwned by your secret 0day spl0itz, you can write a new node subscriber to do that for you. Have a look at `Nmunch::Subscriber::Stdout` for an example of how to write a node subscriber
54
+
55
+ ### *Y U NO capture [insert protocol name] to find more nodes!?!1*
56
+
57
+ The current version of Nmunch only looks for [ARP][arp] and broadcast IP packets which captures quite a lot of nodes, but if you have more ideas, you can easily make a new packet dissector to handle it. see `Nmunch::Dissectors::Arp` for an example of how to write a packet dissector.
58
+
59
+ ## Roadmap
60
+
61
+ This is what I have on the roadmap for Nmunch:
62
+
63
+ ### ▢ More tests
64
+ ### ▢ Improve documentation
65
+ ### ▢ Export results in formats compatible with other tools
66
+ ### ▢ Easier way to register custom node subscribers
67
+ ### ▢ Extract more interesting information apart from live nodes
68
+ ### ▢ Make a [Metasploit] Auxiliary module version of Nmunch
69
+
70
+ ## Contributing
71
+
72
+ Feel free to file an issue, even if you don't have time to submit a patch.
73
+
74
+ Please try to include tests for any patch you submit. If you don't include tests, I'll have to write one, and it'll take longer to get your code in.
75
+
76
+ ## License
77
+
78
+ Copyright (c) 2012 Michael Henriksen
79
+
80
+ MIT License
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining
83
+ a copy of this software and associated documentation files (the
84
+ "Software"), to deal in the Software without restriction, including
85
+ without limitation the rights to use, copy, modify, merge, publish,
86
+ distribute, sublicense, and/or sell copies of the Software, and to
87
+ permit persons to whom the Software is furnished to do so, subject to
88
+ the following conditions:
89
+
90
+ The above copyright notice and this permission notice shall be
91
+ included in all copies or substantial portions of the Software.
92
+
93
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
94
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
95
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
96
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
97
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
98
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
99
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
100
+
101
+ [arp]: http://en.wikipedia.org/wiki/Address_Resolution_Protocol "Address Resolution Protocol"
102
+ [ruby-pcap]: https://github.com/ahobson/ruby-pcap
103
+ [metasploit]: http://www.metasploit.com/ "Metasploit penetration testing framework"
@@ -0,0 +1,44 @@
1
+ def dump_load_path
2
+ puts $LOAD_PATH.join("\n")
3
+ found = nil
4
+ $LOAD_PATH.each do |path|
5
+ if File.exists?(File.join(path,"rspec"))
6
+ puts "Found rspec in #{path}"
7
+ if File.exists?(File.join(path,"rspec","core"))
8
+ puts "Found core"
9
+ if File.exists?(File.join(path,"rspec","core","rake_task"))
10
+ puts "Found rake_task"
11
+ found = path
12
+ else
13
+ puts "!! no rake_task"
14
+ end
15
+ else
16
+ puts "!!! no core"
17
+ end
18
+ end
19
+ end
20
+ if found.nil?
21
+ puts "Didn't find rspec/core/rake_task anywhere"
22
+ else
23
+ puts "Found in #{path}"
24
+ end
25
+ end
26
+ require 'bundler'
27
+ require 'rake/clean'
28
+
29
+ begin
30
+ require 'rspec/core/rake_task'
31
+ rescue LoadError
32
+ dump_load_path
33
+ raise
34
+ end
35
+
36
+ include Rake::DSL
37
+
38
+ Bundler::GemHelper.install_tasks
39
+
40
+ RSpec::Core::RakeTask.new do |t|
41
+ # Put spec opts in a file named .rspec in root
42
+ end
43
+
44
+ task :default => [:spec]
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'methadone'
5
+ require 'pcap'
6
+ require 'paint'
7
+ require 'ipaddr'
8
+ require 'nmunch'
9
+
10
+ class App
11
+ include Methadone::Main
12
+ include Methadone::CLILogging
13
+
14
+ main do
15
+ begin
16
+ if !options[:interface] && !options[:file]
17
+ help_now!("You must specify an interface or a PCAP file.")
18
+ end
19
+
20
+ logger.debug("Command-line options: #{options.inspect}")
21
+
22
+ logger.debug("Setting up report")
23
+ report = Nmunch::Report.new(options)
24
+
25
+ logger.debug("Registering STDOUT node subscriber")
26
+ report.register_subscriber(Nmunch::Subscribers::Stdout.new(options))
27
+
28
+ # Disable output coloring if specified in options
29
+ if options.include?('no-color')
30
+ logger.debug("Disabling output coloring")
31
+ Paint.mode = 0
32
+ end
33
+
34
+ if !options.include?('no-banner')
35
+ puts Paint[Nmunch.banner, :blue]
36
+ puts Paint[" Munching on packets om nom nom nom...\n", :blue]
37
+ end
38
+
39
+ # Start munching packets and find live nodes...
40
+ logger.debug("Munching packets now...")
41
+ Nmunch.munch!(options) do |node|
42
+ logger.debug("Found node: #{node.ip_address} (#{node.mac_address})")
43
+ report.publish_node(node)
44
+ end
45
+
46
+ logger.debug("Done, printing summary")
47
+ puts "\n#{report.summary}"
48
+
49
+ rescue Exception => e
50
+ if !e.is_a?(Interrupt)
51
+ logger.debug("Caught exception!")
52
+ logger.debug(e.inspect)
53
+ puts Paint[" Warp Core Breach!", :red]
54
+ puts Paint[" [#{e.class}] #{e.message}", :red]
55
+ else
56
+ logger.debug("Caught interrupt")
57
+ puts "\n#{report.summary}"
58
+ exit!
59
+ end
60
+ end
61
+ end
62
+
63
+ on("-i INTERFACE", "--interface", "Interface to munch packets on")
64
+ on("-f FILE", "--file", "Path to PCAP file to analyze")
65
+ on("--no-prefix-lookup", "Disable MAC prefix lookups")
66
+ on("--no-banner", "Don't display awesome Nmunch banner")
67
+ on("--no-color", "Don't colorize output")
68
+
69
+ description "A passive network discovery tool."
70
+ version Nmunch::VERSION
71
+
72
+ use_log_level_option
73
+
74
+ go!
75
+ end
@@ -0,0 +1,60 @@
1
+ require "nmunch/version"
2
+ require "nmunch/dissectors/base"
3
+ require "nmunch/dissectors/ip"
4
+ require "nmunch/dissectors/arp"
5
+ require "nmunch/subscribers/base"
6
+ require "nmunch/subscribers/stdout"
7
+ require "nmunch/node"
8
+ require "nmunch/report"
9
+ require "nmunch/mac_oui_lookup"
10
+
11
+ # Public: Main Nmunch module
12
+ #
13
+ # Acts as a facade in front of the ruby-pcap gem and abstracts away the packet analysis.
14
+ module Nmunch
15
+
16
+ # Internal: PCAP filter expression to only get ARP and broadcast packets
17
+ CAPTURE_FILTER = 'arp or broadcast'
18
+
19
+ # Public: Start munching on packets on interface or from PCAP file
20
+ #
21
+ # options - Hash of command line options
22
+ #
23
+ # Yields an Nmunch::Node with IP and MAC address information
24
+ def self.munch!(options)
25
+ create_capture_object(options).each_packet do |packet|
26
+ dissector = Nmunch::Dissectors::Base.factory(packet)
27
+ yield Nmunch::Node.create_from_dissector(dissector)
28
+ end
29
+ end
30
+
31
+ # Internal: Get the awesome Nmunch ASCII banner
32
+ #
33
+ # Returns ASCII banner
34
+ def self.banner
35
+ banner = <<EOB
36
+
37
+ 88b 88 8b d8 88 88 88b 88 dP""b8 88 88
38
+ 88Yb88 88b d88 88 88 88Yb88 dP `" 88 88
39
+ 88 Y88 88YbdP88 Y8 8P 88 Y88 Yb 888888
40
+ 88 Y8 88 YY 88 `YbodP' 88 Y8 YboodP 88 88
41
+ EOB
42
+ end
43
+
44
+ private
45
+
46
+ # Internal: Create a capture object from options
47
+ #
48
+ # options - Hash of command line options
49
+ #
50
+ # Returns a Pcap::Capture object on interface or a PCAP file
51
+ def self.create_capture_object(options)
52
+ if options[:interface]
53
+ capture = Pcap::Capture.open_live(options[:interface])
54
+ else
55
+ capture = Pcap::Capture.open_offline(options[:file])
56
+ end
57
+ capture.setfilter(CAPTURE_FILTER)
58
+ capture
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ module Nmunch
2
+ module Dissectors
3
+
4
+ # Public: Address Resolution Protocol dissector
5
+ #
6
+ # Extracts IP and MAC address from an ARP packet
7
+ #
8
+ # See http://en.wikipedia.org/wiki/Address_Resolution_Protocol for protocol details
9
+ class Arp < Nmunch::Dissectors::Base
10
+
11
+ # Public: Get sender IP address from ARP packet
12
+ #
13
+ # Returns IP address
14
+ def ip_address
15
+ @ip_address ||= IPAddr.new(raw_data[28..31].join.hex, Socket::AF_INET).to_s
16
+ end
17
+
18
+ # Public: Get sender MAC address from ARP packet
19
+ #
20
+ # Returns MAC address
21
+ def mac_address
22
+ @mac_address ||= raw_data[22..27].join(':')
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+ module Nmunch
2
+ module Dissectors
3
+
4
+ # Public: Base dissector class
5
+ class Base
6
+ attr_reader :pcap_packet, :raw_data
7
+
8
+ # Public: Initializer
9
+ #
10
+ # pcap_packet - An instance of Pcap::Packet
11
+ #
12
+ # Stores the packet and extracts to raw packet data in a way that makes
13
+ # it easy to dissect
14
+ #
15
+ # Returns nothing
16
+ def initialize(pcap_packet)
17
+ @pcap_packet = pcap_packet
18
+ extract_raw_packet_data
19
+ end
20
+
21
+ # Public: Dissector factory
22
+ #
23
+ # pcap_packet - An instance of Pcap::Packet
24
+ #
25
+ # Returns an instance of a dissector
26
+ def self.factory(pcap_packet)
27
+ if pcap_packet.ip?
28
+ Nmunch::Dissectors::Ip.new(pcap_packet)
29
+ else
30
+ Nmunch::Dissectors::Arp.new(pcap_packet)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # Internal: Extract raw packet data and store it in @raw_data
37
+ #
38
+ # Unpacks data to HEX and splits it into an array of bytes
39
+ #
40
+ # Returns nothing
41
+ def extract_raw_packet_data
42
+ @raw_data = pcap_packet.raw_data.unpack('H*').first.scan(/.{2}/)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,26 @@
1
+ module Nmunch
2
+ module Dissectors
3
+
4
+ # Public: Internet Protocol dissector
5
+ #
6
+ # Extracts IP and MAC address from IP packet
7
+ #
8
+ # See http://en.wikipedia.org/wiki/Internet_Protocol for protocol details
9
+ class Ip < Nmunch::Dissectors::Base
10
+
11
+ # Public: Get sender IP address from IP packet
12
+ #
13
+ # Returns IP address
14
+ def ip_address
15
+ @ip_address ||= pcap_packet.ip_src.to_s
16
+ end
17
+
18
+ # Public: Get sender MAC address from IP packet
19
+ #
20
+ # Returns MAC address
21
+ def mac_address
22
+ @mac_address ||= raw_data[6..11].join(':')
23
+ end
24
+ end
25
+ end
26
+ end