mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Add script argument to force specific MAC address. See #1838
This commit is contained in:
@@ -36,6 +36,9 @@ o [Windows] Add support for the new loopback behavior in Npcap 0.9983. This
|
||||
Adapter to be installed, which was a source of problems for some users.
|
||||
[Daniel Miller]
|
||||
|
||||
o [NSE][GH#1838] Scripts dhcp-discover and broadcast-dhcp-discover now support
|
||||
new argument "mac" to force a specific client MAC address [nnposter]
|
||||
|
||||
o [NSE] Code improvements in RPC Dump, benefitting NFS-related scripts
|
||||
[nnposter]
|
||||
|
||||
|
||||
@@ -49,11 +49,18 @@ The script needs to be run as a privileged user, typically root.
|
||||
-- <elem key="Domain Name Server">192.168.1.1</elem>
|
||||
-- <elem key="Domain Name">localdomain</elem>
|
||||
--
|
||||
-- @args broadcast-dhcp-discover.mac Set to <code>random</code> or a specific
|
||||
-- client MAC address in the DHCP request. "DE:AD:C0:DE:CA:FE"
|
||||
-- is used by default. Setting it to <code>random</code> will
|
||||
-- possibly cause the DHCP server to reserve a new IP address
|
||||
-- each time.
|
||||
-- @args broadcast-dhcp-discover.timeout time in seconds to wait for a response
|
||||
-- (default: 10s)
|
||||
--
|
||||
|
||||
-- Version 0.1
|
||||
-- Created 01/14/2020 - v0.2 - updated by nnposter
|
||||
-- o Implemented script argument "mac" to force a specific MAC address
|
||||
--
|
||||
-- Created 07/14/2011 - v0.1 - created by Patrik Karlsson
|
||||
|
||||
author = "Patrik Karlsson"
|
||||
@@ -148,10 +155,16 @@ action = function()
|
||||
local timeout = stdnse.parse_timespec(stdnse.get_script_args("broadcast-dhcp-discover.timeout"))
|
||||
timeout = (timeout or 10) * 1000
|
||||
|
||||
-- randomizing the MAC could exhaust dhcp servers with small scopes
|
||||
-- if ran multiple times, so we should probably refrain from doing
|
||||
-- this?
|
||||
local mac = "\xDE\xAD\xC0\xDE\xCA\xFE"
|
||||
local macaddr = (stdnse.get_script_args(SCRIPT_NAME .. ".mac") or "DE:AD:C0:DE:CA:FE"):lower()
|
||||
if macaddr:find("^ra?nd") then
|
||||
macaddr = rand.random_string(6)
|
||||
else
|
||||
macaddr = macaddr:gsub(":", "")
|
||||
if not (#macaddr == 12 and macaddr:find("^%x+$")) then
|
||||
return stdnse.format_output(false, "Invalid MAC address")
|
||||
end
|
||||
macaddr = stdnse.fromhex(macaddr)
|
||||
end
|
||||
|
||||
local interfaces
|
||||
|
||||
@@ -174,7 +187,7 @@ action = function()
|
||||
|
||||
-- we need to set the flags to broadcast
|
||||
local request_options, overrides, lease_time = nil, { flags = 0x8000 }, nil
|
||||
local status, packet = dhcp.dhcp_build(request_type, ip_address, mac, nil, request_options, overrides, lease_time, transaction_id)
|
||||
local status, packet = dhcp.dhcp_build(request_type, ip_address, macaddr, nil, request_options, overrides, lease_time, transaction_id)
|
||||
if (not(status)) then return fail("Failed to build packet") end
|
||||
|
||||
local threads = {}
|
||||
|
||||
@@ -5,6 +5,7 @@ local shortport = require "shortport"
|
||||
local stdnse = require "stdnse"
|
||||
local string = require "string"
|
||||
local table = require "table"
|
||||
local ipOps = require "ipOps"
|
||||
|
||||
description = [[
|
||||
Sends a DHCPINFORM request to a host on UDP port 67 to obtain all the local configuration parameters
|
||||
@@ -33,14 +34,18 @@ Some of the more useful fields:
|
||||
-- @see broadcast-dhcp6-discover.nse
|
||||
-- @see broadcast-dhcp-discover.nse
|
||||
--
|
||||
-- @args dhcptype The type of DHCP request to make. By default, DHCPINFORM is sent, but this
|
||||
-- argument can change it to DHCPOFFER, DHCPREQUEST, DHCPDECLINE, DHCPACK, DHCPNAK,
|
||||
-- DHCPRELEASE or DHCPINFORM. Not all types will evoke a response from all servers,
|
||||
-- and many require different fields to contain specific values.
|
||||
-- @args randomize_mac Set to <code>true</code> or <code>1</code> to send a random MAC address with
|
||||
-- the request (keep in mind that you may not see the response). This should
|
||||
-- cause the router to reserve a new IP address each time.
|
||||
-- @args requests Set to an integer to make up to that many requests (and display the results).
|
||||
-- @args dhcp-discover.dhcptype The type of DHCP request to make. By default,
|
||||
-- DHCPINFORM is sent, but this argument can change it to DHCPOFFER,
|
||||
-- DHCPREQUEST, DHCPDECLINE, DHCPACK, DHCPNAK, DHCPRELEASE or
|
||||
-- DHCPINFORM. Not all types will evoke a response from all servers,
|
||||
-- and many require different fields to contain specific values.
|
||||
-- @args dhcp-discover.mac Set to <code>native</code> (default) or
|
||||
-- <code>random</code> or a specific client MAC address in the DHCP
|
||||
-- request. Keep in mind that you may not see the response if
|
||||
-- a non-native address is used. Setting it to <code>random</code> will
|
||||
-- possibly cause the DHCP server to reserve a new IP address each time.
|
||||
-- @args dhcp-discover.requests Set to an integer to make up to that many
|
||||
-- requests (and display the results).
|
||||
--
|
||||
-- @usage
|
||||
-- nmap -sU -p 67 --script=dhcp-discover <target>
|
||||
@@ -68,6 +73,10 @@ Some of the more useful fields:
|
||||
-- </table>
|
||||
--
|
||||
|
||||
--
|
||||
-- 2020-01-14 - Revised by nnposter
|
||||
-- o Added script argument "mac" to prescribe a specific MAC address
|
||||
-- o Deprecated argument "randomize_mac" in favor of "mac=random"
|
||||
--
|
||||
-- 2011-12-28 - Revised by Patrik Karlsson <patrik@cqure.net>
|
||||
-- o Removed DoS code and placed script into discovery and safe categories
|
||||
@@ -94,43 +103,6 @@ function portrule(host, port)
|
||||
return shortport.portnumber(67, "udp")(host, port)
|
||||
end
|
||||
|
||||
local function go(host, port)
|
||||
|
||||
-- Build and send a DHCP request using the specified request type, or DHCPINFORM
|
||||
local requests = tonumber(nmap.registry.args.requests or 1)
|
||||
local results = {}
|
||||
for i = 1, requests, 1 do
|
||||
-- Decide which type of request to make
|
||||
local request_type = dhcp.request_types[nmap.registry.args.dhcptype or "DHCPINFORM"]
|
||||
if(request_type == nil) then
|
||||
return false, "Valid request types: " .. table.concat(dhcp.request_types_str, ", ")
|
||||
end
|
||||
|
||||
-- Generate the MAC address, if it's random
|
||||
local mac_addr = host.mac_addr_src
|
||||
if(nmap.registry.args.randomize_mac == 'true' or nmap.registry.args.randomize_mac == '1') then
|
||||
stdnse.debug2("Generating a random MAC address")
|
||||
mac_addr = rand.random_string(6)
|
||||
end
|
||||
|
||||
local iface, err = nmap.get_interface_info(host.interface)
|
||||
if ( not(iface) or not(iface.address) ) then
|
||||
return false, "Couldn't determine local ip for interface: " .. host.interface
|
||||
end
|
||||
|
||||
local status, result = dhcp.make_request(host.ip, request_type, iface.address, mac_addr)
|
||||
if( not(status) ) then
|
||||
stdnse.debug1("Couldn't send DHCP request: %s", result)
|
||||
return false, result
|
||||
end
|
||||
|
||||
table.insert(results, result)
|
||||
end
|
||||
|
||||
-- Done!
|
||||
return true, results
|
||||
end
|
||||
|
||||
local commasep = {
|
||||
__tostring = function (t)
|
||||
return table.concat(t, ", ")
|
||||
@@ -138,21 +110,69 @@ local commasep = {
|
||||
}
|
||||
|
||||
action = function(host, port)
|
||||
local status, results = go(host, port)
|
||||
|
||||
|
||||
if(not(status)) then
|
||||
return stdnse.format_output(false, results)
|
||||
local dhcptype = (stdnse.get_script_args(SCRIPT_NAME .. ".dhcptype") or "DHCPINFORM"):upper()
|
||||
local dhcptypeid = dhcp.request_types[dhcptype]
|
||||
if not dhcptypeid then
|
||||
return stdnse.format_output(false, "Invalid request type (use "
|
||||
.. table.concat(dhcp.request_types_str, " / ")
|
||||
.. ")")
|
||||
end
|
||||
|
||||
if(not(results)) then
|
||||
local reqcount = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".requests") or 1)
|
||||
if not reqcount then
|
||||
return stdnse.format_output(false, "Invalid request count")
|
||||
end
|
||||
|
||||
local iface, err = nmap.get_interface_info(host.interface)
|
||||
if not (iface and iface.address) then
|
||||
return stdnse.format_output(false, "Couldn't determine local IP for interface: " .. host.interface)
|
||||
end
|
||||
|
||||
local overrides = {}
|
||||
|
||||
local macaddr = (stdnse.get_script_args(SCRIPT_NAME .. ".mac") or "native"):lower()
|
||||
-- Support for legacy argument "randomize_mac"
|
||||
local randomize = (stdnse.get_script_args(SCRIPT_NAME .. ".randomize_mac") or "false"):lower()
|
||||
if randomize == "true" or randomize == "1" then
|
||||
stdnse.debug1("Use %s.mac=random instead of %s.randomize_mac=%s", SCRIPT_NAME, SCRIPT_NAME, randomize)
|
||||
macaddr = "random"
|
||||
end
|
||||
if macaddr ~= "native" then
|
||||
-- Set the scanner as a relay agent
|
||||
overrides.giaddr = string.unpack("<I4", ipOps.ip_to_str(iface.address))
|
||||
end
|
||||
local macaddr_iter
|
||||
if macaddr:find("^ra?nd") then
|
||||
macaddr_iter = function () return rand.random_string(6) end
|
||||
else
|
||||
if macaddr == "native" then
|
||||
macaddr = host.mac_addr_src
|
||||
else
|
||||
macaddr = macaddr:gsub(":", "")
|
||||
if not (#macaddr == 12 and macaddr:find("^%x+$")) then
|
||||
return stdnse.format_output(false, "Invalid MAC address")
|
||||
end
|
||||
macaddr = stdnse.fromhex(macaddr)
|
||||
end
|
||||
macaddr_iter = function () return macaddr end
|
||||
end
|
||||
|
||||
local results = {}
|
||||
for i = 1, reqcount do
|
||||
local macaddr = macaddr_iter()
|
||||
stdnse.debug1("Client MAC address: %s", stdnse.tohex(macaddr, {separator = ":"}))
|
||||
local status, result = dhcp.make_request(host.ip, dhcptypeid, iface.address, macaddr, nil, nil, overrides)
|
||||
if not status then
|
||||
return stdnse.format_output(false, "Couldn't send DHCP request: " .. result)
|
||||
end
|
||||
table.insert(results, result)
|
||||
end
|
||||
|
||||
if #results == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Set the port state to open
|
||||
if(host) then
|
||||
nmap.set_port_state(host, port, "open")
|
||||
end
|
||||
nmap.set_port_state(host, port, "open")
|
||||
|
||||
local response = stdnse.output_table()
|
||||
|
||||
@@ -160,12 +180,11 @@ action = function(host, port)
|
||||
for i, result in ipairs(results) do
|
||||
local result_table = stdnse.output_table()
|
||||
|
||||
if ( nmap.registry.args.dhcptype and
|
||||
"DHCPINFORM" ~= nmap.registry.args.dhcptype ) then
|
||||
if dhcptype ~= "DHCPINFORM" then
|
||||
result_table["IP Offered"] = result.yiaddr_str
|
||||
end
|
||||
for _, v in ipairs(result.options) do
|
||||
if(type(v.value) == 'table') then
|
||||
if type(v.value) == 'table' then
|
||||
setmetatable(v.value, commasep)
|
||||
end
|
||||
result_table[ v.name ] = v.value
|
||||
|
||||
Reference in New Issue
Block a user