mirror of
https://github.com/nmap/nmap.git
synced 2026-08-27 11:55:27 +00:00
Fix: Handle ZMTP 2.0, CURVE/PLAIN, and identity padding in detection
- Add 's' flag to service probe regex (dot must match 0x0A in signature padding when identity length == 10) - Remove '$' anchor from NULL probe ZMTP match to catch 2.0 responses longer than 10 bytes (revision + socket-type + identity frame) - Handle partial greetings from CURVE/PLAIN servers (only 10-byte signature before mechanism mismatch closure) - Tested against 19 servers: 7 NULL socket types, 2 NULL+identity, 2 CURVE, 2 PLAIN, 6 raw ZMTP 2.0 (with/without identity)
This commit is contained in:
parent
8703877d7d
commit
fd325c06a6
2 changed files with 42 additions and 23 deletions
|
|
@ -5277,8 +5277,11 @@ match zeo-monitor m|^ZEO monitor server version ([\w._-]+)\n.*\n\nStorage: \d+\n
|
|||
match zos-commserver m|^EZY1315E \d\d/\d\d/\d\d \d\d:\d\d:\d\d INVALID TRANID=\r\n\r\n PARTNER INET ADDR=[\d.]+ PORT= \d+ | p|IBM z/OS Communications Server| o|z/OS| cpe:/o:ibm:z%2fos/
|
||||
|
||||
# http://rfc.zeromq.org/spec:15
|
||||
# This is a backwards-compatible handshake
|
||||
match zmtp m|^\xff\0\0\0\0\0\0\0\x01\x7f$| p/ZeroMQ ZMTP 2.0/
|
||||
# ZMTP signature: 0xFF + 8 padding bytes + 0x7F. Padding may contain identity
|
||||
# length for backward compat (can be 0x0A = \n, so 's' flag is required).
|
||||
# Original match required exactly 10 bytes ($), but 2.0 servers send more
|
||||
# (revision + socket-type + identity frame). Use 's' flag for \n in padding.
|
||||
match zmtp m|^\xff.{8}\x7f|s p/ZeroMQ ZMTP/
|
||||
|
||||
##############################NEXT PROBE##############################
|
||||
# ZMTP 3.x (ZeroMQ Message Transport Protocol)
|
||||
|
|
@ -5291,7 +5294,8 @@ ports 41459,50051,56441,30000-65535
|
|||
|
||||
# ZMTP response: 64-byte greeting starting with signature 0xFF...0x7F
|
||||
# Catches all ZMTP versions (2.0, 3.0, 3.1+). NSE script handles detailed parsing.
|
||||
match zmtp m|^\xff.{8}\x7f| p/ZeroMQ ZMTP/
|
||||
# 's' flag: padding bytes may contain 0x0A (\n) when identity length == 10.
|
||||
match zmtp m|^\xff.{8}\x7f|s p/ZeroMQ ZMTP/
|
||||
|
||||
# http://www.space-walrus.com/games/Minebuilder
|
||||
# Very general, so leaving it here at the end
|
||||
|
|
|
|||
|
|
@ -296,12 +296,13 @@ action = function(host, port)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- Receive at least the 10-byte signature.
|
||||
-- For ZMTP 3.x we typically get 64+ bytes, for 2.0 we get ~14 bytes.
|
||||
-- Receive response. We ask for at least 10 bytes (the signature).
|
||||
-- ZMTP 3.x servers typically send 64+ bytes, 2.0 servers send ~14 bytes.
|
||||
-- CURVE/PLAIN servers may send only 10 bytes initially (partial greeting).
|
||||
local response
|
||||
status, response = socket:receive_bytes(10)
|
||||
|
||||
if not status or #response < 11 then
|
||||
if not status or #response < 10 then
|
||||
socket:close()
|
||||
stdnse.debug1("No valid response received")
|
||||
return nil
|
||||
|
|
@ -317,27 +318,41 @@ action = function(host, port)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- If we only got the 10-byte signature (partial greeting from CURVE/PLAIN
|
||||
-- servers), try to receive more bytes for version info.
|
||||
if #response == 10 then
|
||||
stdnse.debug1("Got only signature (10 bytes), waiting for version...")
|
||||
local s, more = socket:receive_bytes(1)
|
||||
if s and more then
|
||||
response = response .. more
|
||||
end
|
||||
end
|
||||
|
||||
local output = stdnse.output_table()
|
||||
output.protocol = "ZMTP"
|
||||
|
||||
local major = string.byte(response, 11)
|
||||
|
||||
if major >= 3 then
|
||||
-- ZMTP 3.x: ensure we have the full 64-byte greeting
|
||||
if #response < 64 then
|
||||
local s, more = socket:receive_bytes(64 - #response)
|
||||
if s and more then
|
||||
response = response .. more
|
||||
end
|
||||
end
|
||||
parse_zmtp3(response, socket, output)
|
||||
elseif major == 1 or major == 2 then
|
||||
-- ZMTP 2.0 (revision byte 0x01) or ZMTP 2.1 (0x02)
|
||||
parse_zmtp2(response, output)
|
||||
if #response < 11 then
|
||||
-- Only got the signature, no version byte. Report as ZMTP detected.
|
||||
stdnse.debug1("ZMTP signature confirmed but no version received (%d bytes)", #response)
|
||||
else
|
||||
-- Unknown version, report what we know
|
||||
output.version = string.format("%d.0", major)
|
||||
stdnse.debug1("Unknown ZMTP major version: %d", major)
|
||||
local major = string.byte(response, 11)
|
||||
|
||||
if major >= 3 then
|
||||
-- ZMTP 3.x: try to get the full 64-byte greeting
|
||||
if #response < 64 then
|
||||
local s, more = socket:receive_bytes(1)
|
||||
if s and more then
|
||||
response = response .. more
|
||||
end
|
||||
end
|
||||
parse_zmtp3(response, socket, output)
|
||||
elseif major == 1 or major == 2 then
|
||||
-- ZMTP 2.0 (revision byte 0x01) or ZMTP 2.1 (0x02)
|
||||
parse_zmtp2(response, output)
|
||||
else
|
||||
output.version = string.format("%d.0", major)
|
||||
stdnse.debug1("Unknown ZMTP major version: %d", major)
|
||||
end
|
||||
end
|
||||
|
||||
socket:close()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue