Lucene search

K
nmapMarek MajkowskiNMAP:SNIFFER-DETECT.NSE
HistoryNov 06, 2008 - 2:52 a.m.

sniffer-detect NSE Script

2008-11-0602:52:59
Marek Majkowski
nmap.org
449

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

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&gt;.

Example Usage

nmap -sV --script=sniffer-detect &lt;target&gt;

Script Output

Host script results:
|_ sniffer-detect: Likely in promiscuous mode (tests: "11111111")

Requires


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

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.973 High

EPSS

Percentile

99.8%

Related for NMAP:SNIFFER-DETECT.NSE