id = "PCAP example" description = "" author = "Marek Majkowski " license = "See nmaps COPYING for licence" --[[ Sends udp packet to dns port, using raw sockets. with the request: A? www.google.pl ]]-- categories = {"discovery"} require "packet" require "shortport" portrule = shortport.service("domain") portrule = function(host, port) if (port.number == 53 or port.service == "domain") and port.protocol == "udp" then if not host.mac_addr or not host.mac_addr_src then io.write("Please use the --send-eth option and scan local network or use send_ip() patch\n") return false else return true end end return false end send_ethernet = function(host, dnet, ip_datagram) -- much better whould be to use sendip() patch, but it's not included in current nmap -- TODO: test if ethernet packet is smaller than 1500 bytes (MTU) local data = host.mac_addr .. host.mac_addr_src .. packet.hextobin("0800") .. ip_datagram .. packet.hextobin("00000000") -- packet.set_u16(data, string.len(data) - 2, packet.in_cksum(data) ) dnet:ethernet_send(data ) end -- the key is source host .. destinationport .. sourceport pcap_callback = function(packetsz, layer2, layer3) local pac = packet.Packet:new(layer3, packetsz-string.len(layer2)) if pac.udp then return "prefix" .. pac.ip_bin_src .. " " .. pac.udp_sport .. " " .. pac.udp_dport end return layer2 .. layer3 -- ignore end dns_udp_packet = packet.hextobin( -- "4500 003b" .. "d5a7 0000" .. "4011 0000" .. "0000 0000" .. "0000 0000" .. "0000 0000" .. "0027 0000" .. "c074 0100 0001 0000 0000 0000 0377 7777 0667 6f6f 676c 6502 706c 0000 0100 01" ) null_udp_packet = packet.hextobin( -- "4500 001e" .. -- version ihl, tos| total length (0x14ip + 0x08udp + payload0x2= 0x1e) "0001 0000" .. -- identification | flags, fragment offset "2a11 0000" .. -- ttl, protocol(0x11=udp) | header checksum "0000 0000" .. -- source ip address "0000 0000" .. -- dest ip address "0000 0000" .. -- udp sport | udp dport "000A 0000" .. -- udp length(0x8-only header + 2) | udp checksum "1013" ) action = function(host, port) local pcap = nmap.new_socket() local dnet = nmap.new_dnet() local conn = nmap.new_socket() dnet:ethernet_open(host.interface) local _, layer2, layer3, status, i, packetsz pcap:pcap_open(host.interface, 1024, 0, pcap_callback, "udp and src port " .. port.number ) -- this is not very good. inserting port.number into bpf leads to many opened pcaps pcap:set_timeout(5000) local udp = packet.Packet:new(dns_udp_packet, dns_udp_packet:len()) udp:ip_set_p(17) -- udp udp:ip_set_bin_src(host.bin_ip_src) udp:ip_set_bin_dst(host.bin_ip) udp:ip_set_ttl(math.random(37,63)) local localport = math.random(1025, 65535) udp:udp_set_sport(localport) udp:udp_set_dport(port.number) -- recount checksum on udp udp:udp_count_checksum() -- recount checksum on ip udp:ip_count_checksum() for i=1,3 do pcap:pcap_register("prefix" .. host.bin_ip .. " " .. port.number .. " " .. localport) send_ethernet(host, dnet, udp.buf) status , packetsz, layer2, layer3 = pcap:pcap_receive() if status == true then local pac = packet.Packet:new(layer3, packetsz-string.len(layer2)) return string.format('got packet: %s', pac:tostring() ) end end return "packets dropped" end