diff options
Diffstat (limited to '')
-rw-r--r-- | scripts/sniffer-detect.nse | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/scripts/sniffer-detect.nse b/scripts/sniffer-detect.nse new file mode 100644 index 0000000..0621f74 --- /dev/null +++ b/scripts/sniffer-detect.nse @@ -0,0 +1,144 @@ +local nmap = require "nmap" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" + +description = [[ +Checks if a target on a local Ethernet has its network card in promiscuous mode. + +The techniques used are described at +http://www.securityfriday.com/promiscuous_detection_01.pdf. +]] + +--- +-- @output +-- Host script results: +-- |_ sniffer-detect: Likely in promiscuous mode (tests: "11111111") + + +author = "Marek Majkowski" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" + +categories = {"discovery", "intrusive"} + +-- okay, we're interested only in hosts that are on our ethernet lan +hostrule = function(host) + if nmap.address_family() ~= 'inet' then + stdnse.debug1("is IPv4 compatible only.") + return false + end + if host.directly_connected == true and + host.mac_addr ~= nil and + host.mac_addr_src ~= nil and + host.interface ~= nil then + local iface = nmap.get_interface_info(host.interface) + if iface and iface.link == 'ethernet' then + return true + end + end + return false +end + +local function check (layer2) + return string.sub(layer2, 0, 12) +end + + +do_test = function(dnet, pcap, host, test) + local status, length, layer2, layer3 + local i = 0 + + -- ARP requests are send with timeouts: 10ms, 40ms, 90ms + -- before each try, we wait at least 100ms + -- in summary, this test takes at least 100ms and at most 440ms + for i=1,3 do + -- flush buffers :), wait quite long. + repeat + pcap:set_timeout(100) + local test = host.mac_addr_src .. host.mac_addr + status, length, layer2, layer3 = pcap:pcap_receive() + while status and test ~= check(layer2) do + status, length, layer2, layer3 = pcap:pcap_receive() + end + until status ~= true + pcap:set_timeout(10 * i*i) + + dnet:ethernet_send(test) + + local test = host.mac_addr_src .. host.mac_addr + status, length, layer2, layer3 = pcap:pcap_receive() + while status and test ~= check(layer2) do + status, length, layer2, layer3 = pcap:pcap_receive() + end + if status == true then + -- the basic idea, was to inform user about time, when we got packet + -- so that 1 would mean (0-10ms), 2=(10-40ms) and 3=(40ms-90ms) + -- but when we're running this tests on macs, first test is always 2. + -- which means that the first answer is dropped. + -- for now, just return 1 if test was successful, it's easier + -- return(i) + return(1) + end + end + return('_') +end + +action = function(host) + local dnet = nmap.new_dnet() + local pcap = nmap.new_socket() + local _ + local status + local results = { + ['1_____1_'] = false, -- MacOSX(Tiger.Panther)/Linux/ ?Win98/ WinXP sp2(no pcap) + ['1_______'] = false, -- Old Apple/SunOS/3Com + ['1___1_1_'] = false, -- MacOSX(Tiger) + ['11111111'] = true, -- BSD/Linux/OSX/ (or not promiscuous openwrt ) + ['1_1___1_'] = false, -- WinXP sp2 + pcap|| win98 sniff || win2k sniff (see below) + ['111___1_'] = true, -- WinXP sp2 promisc + --['1111__1_'] = true, -- ?Win98 promisc + ??win98 no promisc *not confirmed* + } + dnet:ethernet_open(host.interface) + + pcap:pcap_open(host.interface, 64, false, "arp") + + local test_static = host.mac_addr_src .. + "\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01" .. + host.mac_addr_src .. + host.bin_ip_src .. + "\x00\x00\x00\x00\x00\x00" .. + host.bin_ip + local t = { + "\xff\xff\xff\xff\xff\xff", -- B32 no meaning? + "\xff\xff\xff\xff\xff\xfe", -- B31 + "\xff\xff\x00\x00\x00\x00", -- B16 + "\xff\x00\x00\x00\x00\x00", -- B8 + "\x01\x00\x00\x00\x00\x00", -- G + "\x01\x00\x5e\x00\x00\x00", -- M0 + "\x01\x00\x5e\x00\x00\x01", -- M1 no meaning? + "\x01\x00\x5e\x00\x00\x03", -- M3 + } + local v + local out = {} + for _, v in ipairs(t) do + out[#out+1] = do_test(dnet, pcap, host, v .. test_static) + end + out = table.concat(out) + + dnet:ethernet_close() + pcap:pcap_close() + + if out == '1_1___1_' then + return 'Windows with libpcap installed; may or may not be sniffing (tests: "' .. out .. '")' + end + if results[out] == false then + -- probably not sniffing + return + end + if results[out] == true then + -- rather sniffer. + return 'Likely in promiscuous mode (tests: "' .. out .. '")' + end + + -- results[out] == nil + return 'Unknown (tests: "' .. out .. '")' +end |