mirror of
https://github.com/nmap/nmap.git
synced 2025-12-14 19:59:02 +00:00
Add AllSeeingEye (a protocol for querying status of certain games) script and service probe
This commit is contained in:
232
scripts/allseeingeye-info.nse
Normal file
232
scripts/allseeingeye-info.nse
Normal file
@@ -0,0 +1,232 @@
|
||||
local comm = require "comm"
|
||||
local nmap = require "nmap"
|
||||
local shortport = require "shortport"
|
||||
local string = require "string"
|
||||
local bit = require "bit"
|
||||
local stdnse = require "stdnse"
|
||||
|
||||
description = [[
|
||||
Detects the All-Seeing Eye service. Provided by some game servers for
|
||||
querying the server's status.
|
||||
|
||||
The All-Seeing Eye service can listen on a UDP port separate from the
|
||||
main game server port (usually game port + 123). On receiving a packet
|
||||
with the payload "s", it replies with various game server status info.
|
||||
|
||||
When run as a version detection script (<code>-sV</code>), the script
|
||||
will report on the game name, version, actual port, and whether it has a
|
||||
password. When run explicitly (<code>--script ase-info</code>), the
|
||||
script will additionally report on the server name, game type, map name,
|
||||
current number of players, maximum number of players, player
|
||||
information, and various other information.
|
||||
|
||||
For more info on the protocol see:
|
||||
http://int64.org/docs/gamestat-protocols/ase.html
|
||||
http://aluigi.altervista.org/papers.htm#ase
|
||||
http://sourceforge.net/projects/gameq/
|
||||
(relevant files: games.ini, packets.ini, ase.php)
|
||||
]]
|
||||
|
||||
-- @usage
|
||||
-- nmap -sV <target>
|
||||
-- @usage
|
||||
-- nmap -Pn -sU -sV --script allseeingeye-info -p <port> <target>
|
||||
--
|
||||
-- @output
|
||||
-- PORT STATE SERVICE REASON VERSION
|
||||
-- 27138/udp open allseeingeye udp-response All-Seeing Eye (game: chrome 1.2.0.0ww; port: 27015; no password)
|
||||
-- | ase-info:
|
||||
-- | game: chrome
|
||||
-- | port: 27015
|
||||
-- | server name: ChromeNet Server
|
||||
-- | game type: Team Death Match
|
||||
-- | map: Data/LevelsNet/Narrow/Narrow.map
|
||||
-- | version: 1.2.0.0ww
|
||||
-- | passworded: 0
|
||||
-- | num players: 2
|
||||
-- | max players: 16
|
||||
-- | settings:
|
||||
-- | Dedicated: No
|
||||
-- | Password Required: No
|
||||
-- | Time Limit: 30
|
||||
-- | Points Limit: 200 min.
|
||||
-- | Respawns Limit: unlimited
|
||||
-- | Respawn Delay: 10 sec.
|
||||
-- | Enemies Visible On Map: No
|
||||
-- | Available Inventory Room: Yes
|
||||
-- | Identify Enemy Players: No
|
||||
-- | Available Vehicles: Yes
|
||||
-- | Vehicle Respaws Limit: unlimited
|
||||
-- | Vehicle Respawn Delay: 30 sec.
|
||||
-- | Vehicle Auto Return Time: 90 sec.
|
||||
-- | Vehicles Visible On Map: Yes
|
||||
-- | Team Balance: Off
|
||||
-- | Friendly Fire: On
|
||||
-- | Friends Visible On Map: Yes
|
||||
-- | players:
|
||||
-- | player 0:
|
||||
-- | name: NoVoDondo
|
||||
-- | team: BLUE
|
||||
-- | skin:
|
||||
-- | score: 71
|
||||
-- | ping: 0
|
||||
-- | time:
|
||||
-- | player 1:
|
||||
-- | name: HeroX
|
||||
-- | team: RED
|
||||
-- | skin:
|
||||
-- | score: 0
|
||||
-- | ping: 11
|
||||
-- |_ time:
|
||||
--
|
||||
-- @xmloutput
|
||||
-- <elem key="game">chrome</elem>
|
||||
-- <elem key="port">27015</elem>
|
||||
-- <elem key="server name">ChromeNet Server</elem>
|
||||
-- <elem key="game type">Team Death Match</elem>
|
||||
-- <elem key="map">Data/LevelsNet/Narrow/Narrow.map</elem>
|
||||
-- <elem key="version">1.2.0.0ww</elem>
|
||||
-- <elem key="passworded">0</elem>
|
||||
-- <elem key="num players">2</elem>
|
||||
-- <elem key="max players">16</elem>
|
||||
-- <table key="settings">
|
||||
-- <elem key="Dedicated">No</elem>
|
||||
-- <elem key="Password Required">No</elem>
|
||||
-- <elem key="Time Limit">30</elem>
|
||||
-- <elem key="Points Limit">200 min.</elem>
|
||||
-- <elem key="Respawns Limit">unlimited</elem>
|
||||
-- <elem key="Respawn Delay">10 sec.</elem>
|
||||
-- <elem key="Enemies Visible On Map">No</elem>
|
||||
-- <elem key="Available Inventory Room">Yes</elem>
|
||||
-- <elem key="Identify Enemy Players">No</elem>
|
||||
-- <elem key="Available Vehicles">Yes</elem>
|
||||
-- <elem key="Vehicle Respaws Limit">unlimited</elem>
|
||||
-- <elem key="Vehicle Respawn Delay">30 sec.</elem>
|
||||
-- <elem key="Vehicle Auto Return Time">90 sec.</elem>
|
||||
-- <elem key="Vehicles Visible On Map">Yes</elem>
|
||||
-- <elem key="Team Balance">Off</elem>
|
||||
-- <elem key="Friendly Fire">On</elem>
|
||||
-- <elem key="Friends Visible On Map">Yes</elem>
|
||||
-- </table>
|
||||
-- <table key="players">
|
||||
-- <table key="player 0">
|
||||
-- <elem key="name">NoVoDondo</elem>
|
||||
-- <elem key="team">BLUE</elem>
|
||||
-- <elem key="skin"></elem>
|
||||
-- <elem key="score">71</elem>
|
||||
-- <elem key="ping">0</elem>
|
||||
-- <elem key="time"></elem>
|
||||
-- </table>
|
||||
-- <table key="player 1">
|
||||
-- <elem key="name">HeroX</elem>
|
||||
-- <elem key="team">RED</elem>
|
||||
-- <elem key="skin"></elem>
|
||||
-- <elem key="score">0</elem>
|
||||
-- <elem key="ping">11</elem>
|
||||
-- <elem key="time"></elem>
|
||||
-- </table>
|
||||
-- </table>
|
||||
|
||||
author = "Marin Maržić"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = { "discovery", "safe", "version" }
|
||||
|
||||
-- Unpacks a string preceded by a 1-byte integer length
|
||||
-- (+1 for the length byte) from another string, starting
|
||||
-- at the given position.
|
||||
-- @param str the string from which to unpack
|
||||
-- @param pos the position in the string from which to start unpacking (position of the length byte)
|
||||
-- @return ret_pos the position after the last unpacked byte
|
||||
-- @return string the unpacked string
|
||||
local unpack_str = function(str, pos)
|
||||
local ret_pos = pos + str:byte(pos)
|
||||
return ret_pos, string.sub(str, pos + 1, ret_pos - 1)
|
||||
end
|
||||
|
||||
portrule = shortport.version_port_or_service({1258,2126,3123,12444,13200,23196,26000,27138,27244,27777,28138}, "allseeingeye", "udp")
|
||||
|
||||
action = function(host, port)
|
||||
local status, data = comm.exchange(host, port.number, "s", { proto = "udp", timeout = 3000 })
|
||||
if not status then
|
||||
return
|
||||
end
|
||||
|
||||
-- UDP port is open
|
||||
nmap.set_port_state(host, port, "open")
|
||||
|
||||
if not string.match(data, "^EYE1") then
|
||||
return
|
||||
end
|
||||
|
||||
-- Detected; extract fields
|
||||
local o = stdnse.output_table()
|
||||
local pos = 5
|
||||
|
||||
pos, o["game"] = unpack_str(data, pos)
|
||||
pos, o["port"] = unpack_str(data, pos)
|
||||
pos, o["server name"] = unpack_str(data, pos)
|
||||
pos, o["game type"] = unpack_str(data, pos)
|
||||
pos, o["map"] = unpack_str(data, pos)
|
||||
pos, o["version"] = unpack_str(data, pos)
|
||||
pos, o["passworded"] = unpack_str(data, pos)
|
||||
pos, o["num players"] = unpack_str(data, pos)
|
||||
pos, o["max players"] = unpack_str(data, pos)
|
||||
|
||||
-- extract the key-value pairs
|
||||
local kv = stdnse.output_table()
|
||||
o["settings"] = kv
|
||||
while data:byte(pos) ~= 1 do
|
||||
local key, value
|
||||
pos, key = unpack_str(data, pos)
|
||||
pos, value = unpack_str(data, pos)
|
||||
kv[key] = value
|
||||
end
|
||||
pos = pos + 1
|
||||
|
||||
-- extract player info
|
||||
local players = stdnse.output_table()
|
||||
o["players"] = players
|
||||
local playernum = 0
|
||||
while pos <= #data do
|
||||
local flags = data:byte(pos)
|
||||
pos = pos + 1
|
||||
|
||||
local player = stdnse.output_table()
|
||||
if bit.band(flags, 1) ~= 0 then
|
||||
pos, player.name = unpack_str(data, pos)
|
||||
end
|
||||
if bit.band(flags, 2) ~= 0 then
|
||||
pos, player.team = unpack_str(data, pos)
|
||||
end
|
||||
if bit.band(flags, 4) ~= 0 then
|
||||
pos, player.skin = unpack_str(data, pos)
|
||||
end
|
||||
if bit.band(flags, 8) ~= 0 then
|
||||
pos, player.score = unpack_str(data, pos)
|
||||
end
|
||||
if bit.band(flags, 16) ~= 0 then
|
||||
pos, player.ping = unpack_str(data, pos)
|
||||
end
|
||||
if bit.band(flags, 32) ~= 0 then
|
||||
pos, player.time = unpack_str(data, pos)
|
||||
end
|
||||
|
||||
players["player " .. playernum] = player
|
||||
playernum = playernum + 1
|
||||
end
|
||||
|
||||
port.version.name = "ase"
|
||||
port.version.name_confidence = 10
|
||||
port.version.product = "All-Seeing Eye"
|
||||
local passworded_string
|
||||
if o["passworded"] == "0" then
|
||||
passworded_string = "; no password"
|
||||
else
|
||||
passworded_string = "; has password"
|
||||
end
|
||||
port.version.extrainfo = "game: " .. o["game"] .. " " .. o["version"] .. "; port: " .. o["port"] .. passworded_string
|
||||
|
||||
nmap.set_port_version(host, port, "hardmatched")
|
||||
|
||||
return o
|
||||
end
|
||||
@@ -10,6 +10,7 @@ Entry { filename = "ajp-brute.nse", categories = { "brute", "intrusive", } }
|
||||
Entry { filename = "ajp-headers.nse", categories = { "discovery", "safe", } }
|
||||
Entry { filename = "ajp-methods.nse", categories = { "default", "safe", } }
|
||||
Entry { filename = "ajp-request.nse", categories = { "discovery", "safe", } }
|
||||
Entry { filename = "allseeingeye-info.nse", categories = { "discovery", "safe", "version", } }
|
||||
Entry { filename = "amqp-info.nse", categories = { "default", "discovery", "safe", "version", } }
|
||||
Entry { filename = "asn-query.nse", categories = { "discovery", "external", "safe", } }
|
||||
Entry { filename = "auth-owners.nse", categories = { "default", "safe", } }
|
||||
|
||||
Reference in New Issue
Block a user