-- -*- 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"}
require("msrpc")
require("smb")
require("stdnse")
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(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
Copyright 2K16 - 2K18 Indonesian Hacker Rulez