nmunch 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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