Nmap Development mailing list archives
Segfault with Nmap 4.85BETA8
From: Lionel Cons <lionel.cons () cern ch>
Date: Fri, 24 Apr 2009 10:44:18 +0200
I'm sometimes getting a segfault while running Nmap 4.85BETA8. Here is a backtrace: Starting Nmap 4.85BETA8 ( http://nmap.org ) at 2009-04-23 16:39 CEST Program received signal SIGSEGV, Segmentation fault. 0x080d7dae in lua_pushnil () (gdb) bt #0 0x080d7dae in lua_pushnil () #1 0x080b257e in ncap_restore_lua () #2 0x080da35b in lua_getinfo () #3 0x080e2b37 in lua_close () #4 0x080d9c58 in lua_getinfo () #5 0x080da850 in lua_resume () #6 0x080e85c6 in luaL_openlibs () #7 0x080e86a8 in luaL_openlibs () #8 0x080da35b in lua_getinfo () #9 0x080e2b37 in lua_close () #10 0x080da66f in lua_getinfo () #11 0x080d85cf in lua_call () #12 0x080d9c58 in lua_getinfo () #13 0x080da936 in lua_yield () #14 0x080d8624 in lua_pcall () #15 0x080af9fb in ScriptResult::set_output () #16 0x080da35b in lua_getinfo () #17 0x080da634 in lua_getinfo () #18 0x080d86c8 in lua_pcall () #19 0x080d9c58 in lua_getinfo () #20 0x080da936 in lua_yield () #21 0x080d870d in lua_cpcall () #22 0x080af411 in script_scan () #23 0x08061ec7 in nmap_main () #24 0x0805d518 in main () The bug seems to be triggered by an NSE script of mine (see attached). The script may be buggy but IMHO it should not make Nmap segfault. Also, this script worked fine in previous versions of Nmap, up to SVN revision 12857 at least. Finally, the problem is tricky. I can reproduce it when scanning many ports on some sets of hosts. Changing the ports or the hosts scanned sometimes makes the problem disappear, maybe a timing or race condition problem? Any help to improve the NSE script and/or make Nmap more robust would be welcome. Cheers, Lionel
-- -- This script sends RMCP Ping requests and, if successful, IPMI Get -- Channel Auth Capabilities commands in order to detect RMCP and IPMI -- support. Note that we have to use PCAP to receive the replies to our -- probes since the RMCP support may be at hardware level (BMC) so the -- operating system may send us "Port unreachable" ICMP messages. -- -- In case you wonder: -- * RMCP = Remote Management Control Protocol -- * IPMI = Intelligent Platform Management Interface -- * BMC = Baseboard Management Controller -- -- -- script definition -- id = "RMCP and IPMI Support" description = "Sends probes to detect RMCP and IPMI support." author = "Lionel Cons (http://cern.ch/lionel.cons)" license = "See Nmap's COPYING for license" categories = { "safe", "version" } -- -- used modules -- require('stdnse') require('packet') -- -- we do not use a portrule as the port may appear to be closed -- (we do however check that the RMCP port has been scanned) -- hostrule = function(host) local result -- initialise only once if (not nmap.registry.rmcp_port) then init() end -- run only if the RMCP port was scanned, but regardless of its state result = nmap.get_port_state(host, nmap.registry.rmcp_port, nmap.registry.rmcp_port.protocol) if (not result) then stdnse.print_debug("[RMCP-IPMI] RMCP port not scanned") return false end -- so far so good stdnse.print_debug("[RMCP-IPMI] RMCP port scanned and found to be %s", result.state) return true end -- -- store port information and our probes in the registry -- init = function() stdnse.print_debug("[RMCP-IPMI] initialisation") -- RMCP port in binary format nmap.registry.rmcp_bin_port = string.char(0x02, 0x6f) -- RMCP port information nmap.registry.rmcp_port = { number = 623, protocol = "udp", version = { name = "rmcp", version = "6", confidence = 10, }, } -- IPMI port information nmap.registry.ipmi_port = { number = 623, protocol = "udp", version = { name = "rmcp", version = "6", extrainfo = "ipmi", confidence = 10, }, } -- RMCP probes local tag = math.random(192) nmap.registry.rmcp_probes = { string.char(0x06, 0x00, 0xff, 0x06, 0x00, 0x00, 0x11, 0xbe, 0x80, tag+0, 0x00, 0x00), string.char(0x06, 0x00, 0xff, 0x06, 0x00, 0x00, 0x11, 0xbe, 0x80, tag+1, 0x00, 0x00), string.char(0x06, 0x00, 0xff, 0x06, 0x00, 0x00, 0x11, 0xbe, 0x80, tag+2, 0x00, 0x00), } -- RMCP data nmap.registry.rmcp_data_1 = string.char(0x06, 0x00, 0xff, 0x06, 0x00, 0x00, 0x11, 0xbe, 0x40) nmap.registry.rmcp_data_2 = string.char(0x06, 0x00, 0xff, 0x06, 0xbe, 0x11, 0x00, 0x00, 0x40) -- IPMI probes local seq = (16 + math.random(32)) * 4 nmap.registry.ipmi_probes = { string.char(0x06, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x20, 0x18, 0xc8, 0x81, seq+0, 0x38, 0x0e, 0x02, 311 - (seq+0)), string.char(0x06, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x20, 0x18, 0xc8, 0x81, seq+4, 0x38, 0x0e, 0x02, 311 - (seq+4)), string.char(0x06, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x20, 0x18, 0xc8, 0x81, seq+8, 0x38, 0x0e, 0x02, 311 - (seq+8)), } -- IPMI data nmap.registry.ipmi_data_1 = string.char(0x06, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x81, 0x1c, 0x63, 0x20) nmap.registry.ipmi_data_2 = string.char(0x38, 0x00) end -- -- send the probes one by one and stop if we receive a reply -- function send_probes(host, socket, pcap, probes) local status, result, layer2, layer3, i, nprobes, hash hash = host.bin_ip .. host.bin_ip_src .. nmap.registry.rmcp_bin_port nprobes = table.getn(probes) for i = 1, nprobes do stdnse.print_debug("[RMCP-IPMI] send probe: %d/%d", i, nprobes) -- register the hash pcap:pcap_register(hash) -- (re)connect the socket status, result = socket:connect(host.ip, nmap.registry.rmcp_port.number, nmap.registry.rmcp_port.protocol) if (not status) then stdnse.print_debug("[RMCP-IPMI] socket:connect failed: %s", result) return false, result end -- send one probe status, result = socket:send(probes[i]) if (not status) then stdnse.print_debug("[RMCP-IPMI] socket:send failed: %s", result) return false, result end -- check for a reply packet status, result, layer2, layer3 = pcap:pcap_receive() if (status) then -- we found one so we do not send any more probes stdnse.print_debug("[RMCP-IPMI] packet has %d bytes", result) result = string.sub(layer3, 29) stdnse.print_debug("[RMCP-IPMI] packet is %s", packet.bintohex(result)) -- check the reply length if (string.len(result) < 12 or string.len(result) > 32) then -- packet is too small or too big return false, result end -- so far so good return true, result else stdnse.print_debug("[RMCP-IPMI] pcap:pcap_receive failed: %s", result) if (result == "TIMEOUT" and i < nprobes) then -- try once more else return false, result end end end -- so far so bad but this should not be reached! stdnse.print_debug("[RMCP-IPMI] ooops!") return false, "" end -- -- check for RMCP support -- function check_rmcp(host, socket, pcap) local status, result -- send the RMCP probes status, result = send_probes(host, socket, pcap, nmap.registry.rmcp_probes) if (not status) then stdnse.print_debug("[RMCP-IPMI] RMCP probes failed") return false end -- we did receive something from this port so it must be open nmap.set_port_state(host, nmap.registry.rmcp_port, "open") -- check the reply if (string.sub(result, 1, 9) == nmap.registry.rmcp_data_1 or string.sub(result, 1, 9) == nmap.registry.rmcp_data_2) then -- the reply looks like a "Presence Pong" packet -- so the host must support RMCP stdnse.print_debug("[RMCP-IPMI] packet looks like a 'Presence Pong' reply") nmap.set_port_version(host, nmap.registry.rmcp_port, "hardmatched") return true end -- so far so bad return false end -- -- check for IPMI support -- function check_ipmi(host, socket, pcap) local status, result -- send the IPMI probes status, result = send_probes(host, socket, pcap, nmap.registry.ipmi_probes) if (not status) then stdnse.print_debug("[RMCP-IPMI] IPMI probes failed") return false end -- check the reply if (string.sub(result, 1, 18) == nmap.registry.ipmi_data_1 and string.sub(result, 20, 21) == nmap.registry.ipmi_data_2) then -- the reply looks like a "Get Channel Auth Capabilities" response packet -- so the host must support IPMI stdnse.print_debug("[RMCP-IPMI] packet looks like a 'Get Channel Auth Capabilities' reply") nmap.set_port_version(host, nmap.registry.ipmi_port, "hardmatched") return true end -- so far so bad return false end -- -- callback function for PCAP returning the pair of addresses and source port -- (this assumes that the IP header does not contain any options) -- pcap_callback = function(packetsz, layer2, layer3) return string.sub(layer3, 13, 22) end -- -- action -- action = function(host) local socket, pcap, result -- create the needed sockets socket = nmap.new_socket() pcap = nmap.new_socket() -- configure PCAP to only see reply packets matching our probes result = string.format("%s and src port %d", nmap.registry.rmcp_port.protocol, nmap.registry.rmcp_port.number) pcap:pcap_open(host.interface, 96, 0, pcap_callback, result) -- set the PCAP reception timeout to one second pcap:set_timeout(1000) -- check for RMCP support result = check_rmcp(host, socket, pcap) -- then check for IPMI support if we have detected RMCP support if (result) then result = check_ipmi(host, socket, pcap) end -- cleanup and return nothing (no script output) socket:close() pcap:close() return end
_______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- Segfault with Nmap 4.85BETA8 Lionel Cons (Apr 24)
- Re: Segfault with Nmap 4.85BETA8 Patrick Donnelly (Apr 24)
- Re: Segfault with Nmap 4.85BETA8 Patrick Donnelly (Apr 25)
- Re: Segfault with Nmap 4.85BETA8 Lionel Cons (Apr 27)
- Re: Segfault with Nmap 4.85BETA8 Patrick Donnelly (Apr 25)
- Re: Segfault with Nmap 4.85BETA8 Patrick Donnelly (Apr 24)