From c4ecf225dd25b0ad3fa2a59c5fd27f1855678bd5 Mon Sep 17 00:00:00 2001 From: nnposter Date: Wed, 15 Jan 2020 01:20:36 +0000 Subject: [PATCH] Add script argument to force specific MAC address. See #1838 --- CHANGELOG | 3 + scripts/broadcast-dhcp-discover.nse | 25 ++++-- scripts/dhcp-discover.nse | 135 ++++++++++++++++------------ 3 files changed, 99 insertions(+), 64 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9429786d0..84ac822f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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] diff --git a/scripts/broadcast-dhcp-discover.nse b/scripts/broadcast-dhcp-discover.nse index bb36e9621..977f27cfa 100644 --- a/scripts/broadcast-dhcp-discover.nse +++ b/scripts/broadcast-dhcp-discover.nse @@ -49,11 +49,18 @@ The script needs to be run as a privileged user, typically root. -- 192.168.1.1 -- localdomain -- +-- @args broadcast-dhcp-discover.mac Set to random or a specific +-- client MAC address in the DHCP request. "DE:AD:C0:DE:CA:FE" +-- is used by default. Setting it to random 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 = {} diff --git a/scripts/dhcp-discover.nse b/scripts/dhcp-discover.nse index ac825d519..65e6cff22 100644 --- a/scripts/dhcp-discover.nse +++ b/scripts/dhcp-discover.nse @@ -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 true or 1 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 native (default) or +-- random 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 random 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 @@ -68,6 +73,10 @@ Some of the more useful fields: -- -- +-- +-- 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 -- 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("