local dns = require "dns" local nmap = require "nmap" local packet = require "packet" local stdnse = require "stdnse" local string = require "string" local ipOps = require "ipOps" description = [[ Detects whether the remote device has ip forwarding or "Internet connection sharing" enabled, by sending an ICMP echo request to a given target using the scanned host as default gateway. The given target can be a routed or a LAN host and needs to be able to respond to ICMP requests (ping) in order for the test to be successful. In addition, if the given target is a routed host, the scanned host needs to have the proper routing to reach it. In order to use the scanned host as default gateway Nmap needs to discover the MAC address. This requires Nmap to be run in privileged mode and the host to be on the LAN. ]] --- -- @usage -- sudo nmap -sn --script ip-forwarding --script-args='target=www.example.com' -- -- @output -- | ip-forwarding: -- |_ The host has ip forwarding enabled, tried ping against (www.example.com) -- -- @param ip-forwarding.target a LAN or routed target responding to ICMP echo -- requests (ping). -- author = "Patrik Karlsson" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"safe", "discovery"} local arg_target = stdnse.get_script_args(SCRIPT_NAME .. ".target") hostrule = function(host) if ( not(host.mac_addr) ) then stdnse.print_debug( "%s: Failed to determine hosts remote MAC address", SCRIPT_NAME ) end return (arg_target ~= nil and host.mac_addr ~= nil) end local function format_mac(mac) local octets octets = {} for _, v in ipairs({ string.byte(mac, 1, #mac) }) do octets[#octets + 1] = string.format("%02x", v) end return stdnse.strjoin(":", octets) end icmpEchoRequest = function(ifname, host, addr) local iface = nmap.get_interface_info(ifname) local dnet, pcap = nmap.new_dnet(), nmap.new_socket() pcap:set_timeout(5000) pcap:pcap_open(iface.device, 128, false, ("ether src %s and icmp and ( icmp[0] = 0 or icmp[0] = 5 ) and dst %s"):format(format_mac(host.mac_addr), iface.address)) dnet:ethernet_open(iface.device) local probe = packet.Frame:new() probe.mac_src = iface.mac probe.mac_dst = host.mac_addr probe.ip_bin_src = packet.iptobin(iface.address) probe.ip_bin_dst = packet.iptobin(addr) probe.echo_id = 0x1234 probe.echo_seq = 6 probe.echo_data = "Nmap host discovery." probe:build_icmp_echo_request() probe:build_icmp_header() probe:build_ip_packet() probe:build_ether_frame() dnet:ethernet_send(probe.frame_buf) local status = pcap:pcap_receive() dnet:ethernet_close() return status end local function fail(err) return ("\n ERROR: %s"):format(err or "") end action = function(host) local ifname = nmap.get_interface() or host.interface if ( not(ifname) ) then return fail("Failed to determine the network interface name") end local target = ipOps.ip_to_bin(arg_target) if ( not(target) ) then local status status, target = dns.query(arg_target, { dtype='A' }) if ( not(status) ) then return fail(("Failed to lookup hostname: %s"):format(arg_target)) end else target = arg_target end if ( target == host.ip ) then return ("\n ERROR: Target can not be the same as the scanned host") end if (icmpEchoRequest(ifname, host, target)) then return ("\n The host has ip forwarding enabled, tried ping against (%s)"):format(arg_target) end end