mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 05:01:29 +00:00
If you ran the (fortunately non-default) http-domino-enum-passwords script with the (fortunately also non-default) domino-enum-passwords.idpath parameter against a malicious server, it could cause an arbitrarily named file to to be written to the client system. Thanks to Trustwave researcher Piotr Duszynski for discovering and reporting the problem. We've fixed that script, and also updated several other scripts to use a new stdnse.filename_escape function for extra safety. This breaks our record of never having a vulnerability in the 16 years that Nmap has existed, but that's still a fairly good run. [David, Fyodor]
118 lines
3.3 KiB
Lua
118 lines
3.3 KiB
Lua
local io = require "io"
|
|
local msrpc = require "msrpc"
|
|
local smb = require "smb"
|
|
local stdnse = require "stdnse"
|
|
local string = require "string"
|
|
|
|
-- -*- mode: lua -*-
|
|
-- vim: set filetype=lua :
|
|
|
|
description = [[
|
|
Detects whether a host is infected with the Stuxnet worm (http://en.wikipedia.org/wiki/Stuxnet).
|
|
|
|
An executable version of the Stuxnet infection will be downloaded if a format
|
|
for the filename is given on the command line.
|
|
]]
|
|
|
|
---
|
|
-- @usage
|
|
-- nmap --script stuxnet-detect -p 445 <host>
|
|
--
|
|
-- @args stuxnet-detect.save Path to save Stuxnet executable under, with
|
|
-- <code>%h</code> replaced by the host's IP address, and <code>%v</code>
|
|
-- replaced by the version of Stuxnet.
|
|
--
|
|
-- @output
|
|
-- PORT STATE SERVICE REASON
|
|
-- 445/tcp open microsoft-ds syn-ack
|
|
--
|
|
-- Host script results:
|
|
-- |_stuxnet-detect: INFECTED (version 4c:04:00:00:01:00:00:00)
|
|
|
|
author = "Mak Kolybabi"
|
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|
categories = {"discovery", "intrusive"}
|
|
|
|
|
|
local STUXNET_PATHS = {"\\\\browser", "\\\\ntsvcs", "\\\\pipe\\browser", "\\\\pipe\\ntsvcs"}
|
|
local STUXNET_UUID = string.char(0xe1, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
|
|
local STUXNET_VERSION = 0x01
|
|
|
|
local RPC_GET_VERSION = 0x00
|
|
local RPC_GET_EXECUTABLE = 0x04
|
|
|
|
local function check_infected(host, path, save)
|
|
local file, result, session, status, version
|
|
|
|
-- Create an SMB session.
|
|
status, session = msrpc.start_smb(host, path)
|
|
if not status then
|
|
stdnse.print_debug(1, "Failed to establish session on %s.", path)
|
|
return false, nil
|
|
end
|
|
|
|
-- Bind to the Stuxnet service.
|
|
status, result = msrpc.bind(session, STUXNET_UUID, STUXNET_VERSION, nil)
|
|
if not status or result["ack_result"] ~= 0 then
|
|
stdnse.print_debug(1, "Failed to bind to Stuxnet service.")
|
|
msrpc.stop_smb(session)
|
|
return false, nil
|
|
end
|
|
|
|
-- Request version of Stuxnet infection.
|
|
status, result = msrpc.call_function(session, RPC_GET_VERSION, "")
|
|
if not status then
|
|
stdnse.print_debug(1, "Failed to retrieve Stuxnet version: %s", result)
|
|
msrpc.stop_smb(session)
|
|
return false, nil
|
|
end
|
|
version = stdnse.tohex(result.arguments, {separator = ":"})
|
|
|
|
-- Request executable of Stuxnet infection.
|
|
if save then
|
|
local file, fmt
|
|
|
|
status, result = msrpc.call_function(session, RPC_GET_EXECUTABLE, "")
|
|
if not status then
|
|
stdnse.print_debug(1, "Failed to retrieve Stuxnet executable: %s", result)
|
|
msrpc.stop_smb(session)
|
|
return true, version
|
|
end
|
|
|
|
fmt = save:gsub("%%h", host.ip)
|
|
fmt = fmt:gsub("%%v", version)
|
|
file = io.open(stdnse.filename_escape(fmt), "w")
|
|
if file then
|
|
stdnse.print_debug(1, "Wrote %d bytes to file %s.", #result.arguments, fmt)
|
|
file:write(result.arguments)
|
|
file:close()
|
|
else
|
|
stdnse.print_debug(1, "Failed to open file: %s", fmt)
|
|
end
|
|
end
|
|
|
|
-- Destroy the SMB session
|
|
msrpc.stop_smb(session)
|
|
|
|
return true, version
|
|
end
|
|
|
|
hostrule = function(host)
|
|
return (smb.get_port(host) ~= nil)
|
|
end
|
|
|
|
action = function(host, port)
|
|
local _, path, result, save, status
|
|
|
|
-- Get script arguments.
|
|
save = stdnse.get_script_args("stuxnet-detect.save")
|
|
|
|
-- Try to find Stuxnet on this host.
|
|
for _, path in pairs(STUXNET_PATHS) do
|
|
status, result = check_infected(host, path, save)
|
|
if status then
|
|
return "INFECTED (version " .. result .. ")"
|
|
end
|
|
end
|
|
end
|