mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Add iec-identify script
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE] iec-identify probes for the IEC 60870-5-104 SCADA protocol.
|
||||||
|
[Aleksandr Timorin, Daniel Miller]
|
||||||
|
|
||||||
o [GH#910] added libssh2 support, ssh-brute, ssh-run, ssh-auth-methods,
|
o [GH#910] added libssh2 support, ssh-brute, ssh-run, ssh-auth-methods,
|
||||||
ssh-publickey-acceptance [Evangelos Deirmentzoglou]
|
ssh-publickey-acceptance [Evangelos Deirmentzoglou]
|
||||||
|
|
||||||
|
|||||||
161
scripts/iec-identify.nse
Normal file
161
scripts/iec-identify.nse
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
local shortport = require "shortport"
|
||||||
|
local comm = require "comm"
|
||||||
|
local stdnse = require "stdnse"
|
||||||
|
local string = require "string"
|
||||||
|
local match = require "match"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
Attempts to identify IEC 60870-5-104 ICS protocol.
|
||||||
|
|
||||||
|
After probing with a TESTFR (test frame) message, a STARTDT (start data
|
||||||
|
transfer) message is sent and general interrogation is used to gather the list
|
||||||
|
of information object addresses stored.
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @output
|
||||||
|
-- | iec-identify:
|
||||||
|
-- | ASDU address: 105
|
||||||
|
-- |_ Information objects: 30
|
||||||
|
--
|
||||||
|
|
||||||
|
author = {"Aleksandr Timorin", "Daniel Miller"}
|
||||||
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"discovery", "intrusive"}
|
||||||
|
|
||||||
|
portrule = shortport.port_or_service(2404, "iec-104", "tcp")
|
||||||
|
|
||||||
|
local function get_asdu(socket)
|
||||||
|
local status, data = socket:receive_buf(match.numbytes(2), true)
|
||||||
|
if not status then
|
||||||
|
return nil, data
|
||||||
|
end
|
||||||
|
if data:byte(1) ~= 0x68 then
|
||||||
|
return nil, "Not IEC-104"
|
||||||
|
end
|
||||||
|
local len = data:byte(2)
|
||||||
|
status, data = socket:receive_buf(match.numbytes(len), true)
|
||||||
|
if not status then
|
||||||
|
return nil, data
|
||||||
|
end
|
||||||
|
local apcitype = data:byte(1)
|
||||||
|
return apcitype, data
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function(host, port)
|
||||||
|
|
||||||
|
local output = stdnse.output_table()
|
||||||
|
local socket, err = comm.opencon(host, port)
|
||||||
|
if not socket then
|
||||||
|
stdnse.debug1("Connect error: %s", err)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- send TESTFR ACT command
|
||||||
|
-- Test frame, like "ping"
|
||||||
|
local TESTFR = "\x68\x04\x43\0\0\0"
|
||||||
|
local status, err = socket:send( TESTFR )
|
||||||
|
if not status then
|
||||||
|
stdnse.debug1("Failed to send: %s", err)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- receive TESTFR answer
|
||||||
|
local apcitype, recv = get_asdu(socket)
|
||||||
|
if not apcitype then
|
||||||
|
stdnse.debug1("protocol error: %s", recv)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if apcitype ~= 0x83 then
|
||||||
|
stdnse.print_debug(1, "Not IEC-104. TESTFR response: %#x", apcitype)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- send STARTDT ACT command
|
||||||
|
local STARTDT = "\x68\x04\x07\0\0\0"
|
||||||
|
status, err = socket:send( STARTDT )
|
||||||
|
if not status then
|
||||||
|
stdnse.debug1("Failed to send: %s", err)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- receive STARTDT answer
|
||||||
|
apcitype, recv = get_asdu(socket)
|
||||||
|
if not apcitype then
|
||||||
|
stdnse.debug1("protocol error: %s", recv)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if apcitype ~= 0x0b then
|
||||||
|
stdnse.debug1("STARTDT ACT did not receive STARTDT CON: %#x", apcitype)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- May also receive ME_EI_NA_1 (End of initialization), so check for that in the buffer after sending the next part
|
||||||
|
|
||||||
|
-- send C_IC_NA_1 command
|
||||||
|
-- type: 0x64, C_IC_NA_1,
|
||||||
|
-- numix: 1
|
||||||
|
-- TNCause: 6, Act
|
||||||
|
-- Originator address; 0
|
||||||
|
-- ASDU address: 0xffff
|
||||||
|
-- Information object address: 0
|
||||||
|
-- QOI: 0x14 (20), Station interrogation (global)
|
||||||
|
local C_IC_NA_1_broadcast = "\x68\x0e\0\0\0\0\x64\x01\x06\0\xff\xff\0\0\0\x14"
|
||||||
|
status, err = socket:send( C_IC_NA_1_broadcast )
|
||||||
|
if not status then
|
||||||
|
stdnse.debug1("Failed to send: %s", err)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local asdu_address
|
||||||
|
local ioas = 0
|
||||||
|
-- Have to draw the line somewhere.
|
||||||
|
local limit = 10
|
||||||
|
while limit > 0 do
|
||||||
|
limit = limit - 1
|
||||||
|
apcitype, recv = get_asdu(socket)
|
||||||
|
if not apcitype then
|
||||||
|
stdnse.debug1("Error in C_IC_NA_1: %s", recv)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if apcitype & 0x01 == 0 then -- Type I, numbered information transfer
|
||||||
|
-- skip 2 bytes Tx, 2 bytes Rx
|
||||||
|
local typeid = recv:byte(5)
|
||||||
|
if typeid == 70 then
|
||||||
|
-- ME_EI_NA_1, End of Initialization. Skip.
|
||||||
|
else
|
||||||
|
local numix = recv:byte(6) & 0x7f
|
||||||
|
local cause = recv:byte(7) & 0x3f
|
||||||
|
asdu_address = string.unpack("<I2", recv, 9)
|
||||||
|
stdnse.debug2("Got asdu=%d, type %d, cause %d, numix %d.", asdu_address, typeid, cause, numix)
|
||||||
|
if typeid == 100 then
|
||||||
|
-- C_IC_NA_1
|
||||||
|
if cause == 7 then
|
||||||
|
-- ActCon. Skip.
|
||||||
|
elseif cause == 10 then
|
||||||
|
-- ActTerm. The end!
|
||||||
|
break
|
||||||
|
else
|
||||||
|
-- TODO: do something!
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if cause >= 20 and cause <= 36 then
|
||||||
|
-- Inrogen, response to general interrogation
|
||||||
|
ioas = ioas + numix
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
socket:close()
|
||||||
|
|
||||||
|
if asdu_address then
|
||||||
|
output["ASDU address"] = asdu_address
|
||||||
|
output["Information objects"] = ioas
|
||||||
|
else
|
||||||
|
output = "IEC-104 endpoint did not respond to C_IC_NA_1 request"
|
||||||
|
end
|
||||||
|
|
||||||
|
return output
|
||||||
|
end
|
||||||
@@ -278,6 +278,7 @@ Entry { filename = "http-xssed.nse", categories = { "discovery", "external", "sa
|
|||||||
Entry { filename = "iax2-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "iax2-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "iax2-version.nse", categories = { "version", } }
|
Entry { filename = "iax2-version.nse", categories = { "version", } }
|
||||||
Entry { filename = "icap-info.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "icap-info.nse", categories = { "discovery", "safe", } }
|
||||||
|
Entry { filename = "iec-identify.nse", categories = { "discovery", "intrusive", } }
|
||||||
Entry { filename = "ike-version.nse", categories = { "default", "discovery", "safe", "version", } }
|
Entry { filename = "ike-version.nse", categories = { "default", "discovery", "safe", "version", } }
|
||||||
Entry { filename = "imap-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "imap-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "imap-capabilities.nse", categories = { "default", "safe", } }
|
Entry { filename = "imap-capabilities.nse", categories = { "default", "safe", } }
|
||||||
@@ -394,6 +395,7 @@ Entry { filename = "omp2-enum-targets.nse", categories = { "discovery", "safe",
|
|||||||
Entry { filename = "omron-info.nse", categories = { "discovery", "version", } }
|
Entry { filename = "omron-info.nse", categories = { "discovery", "version", } }
|
||||||
Entry { filename = "openlookup-info.nse", categories = { "default", "discovery", "safe", "version", } }
|
Entry { filename = "openlookup-info.nse", categories = { "default", "discovery", "safe", "version", } }
|
||||||
Entry { filename = "openvas-otp-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "openvas-otp-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
|
Entry { filename = "openwebnet-discovery.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "oracle-brute-stealth.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "oracle-brute-stealth.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "oracle-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "oracle-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "oracle-enum-users.nse", categories = { "auth", "intrusive", } }
|
Entry { filename = "oracle-enum-users.nse", categories = { "auth", "intrusive", } }
|
||||||
@@ -499,7 +501,11 @@ Entry { filename = "snmp-win32-users.nse", categories = { "auth", "default", "sa
|
|||||||
Entry { filename = "socks-auth-info.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "socks-auth-info.nse", categories = { "default", "discovery", "safe", } }
|
||||||
Entry { filename = "socks-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "socks-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "socks-open-proxy.nse", categories = { "default", "discovery", "external", "safe", } }
|
Entry { filename = "socks-open-proxy.nse", categories = { "default", "discovery", "external", "safe", } }
|
||||||
|
Entry { filename = "ssh-auth-methods.nse", categories = { } }
|
||||||
|
Entry { filename = "ssh-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "ssh-hostkey.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "ssh-hostkey.nse", categories = { "default", "discovery", "safe", } }
|
||||||
|
Entry { filename = "ssh-publickey-acceptance.nse", categories = { } }
|
||||||
|
Entry { filename = "ssh-run.nse", categories = { "intrusive", } }
|
||||||
Entry { filename = "ssh2-enum-algos.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "ssh2-enum-algos.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "sshv1.nse", categories = { "default", "safe", } }
|
Entry { filename = "sshv1.nse", categories = { "default", "safe", } }
|
||||||
Entry { filename = "ssl-ccs-injection.nse", categories = { "safe", "vuln", } }
|
Entry { filename = "ssl-ccs-injection.nse", categories = { "safe", "vuln", } }
|
||||||
|
|||||||
Reference in New Issue
Block a user