1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-19 20:59:01 +00:00

o [NSE] Added a new library for ASN.1 parsing and adapted the SNMP library to

make use of it. Added 5 scripts that use the new libraries:
  - snmp-netstat shows listening and connected sockets
  - snmp-processes shows process information including name, pid, path and 
    parameters
  - snmp-win32-services shows the names of running Windows services
  - snmp-win32-shares shows the names and path of Windows shares
  - snmp-win32-software shows a list of installed Windows software
  - snmp-win32-users shows a list of local Windows users
This commit is contained in:
patrik
2010-02-16 09:15:38 +00:00
parent 3f36981440
commit d2e54f0bf2
9 changed files with 1456 additions and 301 deletions

View File

@@ -2,6 +2,17 @@
[NOT YET RELEASED]
o [NSE] Added a new library for ASN.1 parsing and adapted the SNMP library to
make use of it. Added 5 scripts that use the new libraries:
- snmp-netstat shows listening and connected sockets
- snmp-processes shows process information including name, pid, path and
parameters
- snmp-win32-services shows the names of running Windows services
- snmp-win32-shares shows the names and path of Windows shares
- snmp-win32-software shows a list of installed Windows software
- snmp-win32-users shows a list of local Windows users
[Patrik]
o Qualified an assertion to allow zero-byte sends in Nsock. Without
this, an NSE script could cause this assertion failure by doing
socket:send(""):
@@ -9,7 +20,7 @@ o Qualified an assertion to allow zero-byte sends in Nsock. Without
[David]
o Added a service probe for Logitech SqueezeCenter command line interface
[Patrik]
[Patrik]
o Improved PostgreSQL match lines by matching the line of the error to a
specific version [Patrik].

459
nselib/asn1.lua Normal file
View File

@@ -0,0 +1,459 @@
--- ASN1 functions.
--
-- Large chunks of this code have been ripped right out from snmp.lua
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
--
-- @author Patrik Karlsson
--
-- Version 0.3
-- Created 01/12/2010 - v0.1 - Created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/28/2010 - v0.2 - Adapted to create a framework for SNMP, LDAP and future protocols
-- Revised 02/02/2010 - v0.3 - Changes: o Re-designed so that ASN1Encoder and ASN1Decoder are separate classes
-- o Each script or library should now create it's own Encoder and Decoder instance
--
module(... or "asn1",package.seeall)
require("bit")
BERCLASS = {
Universal = 0,
Application = 64,
ContextSpecific = 128,
Private = 192
}
--- The decoder class
--
ASN1Decoder = {
new = function(self,o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end,
--- Registers the base simple type decoders
--
registerBaseDecoders = function(self)
self.decoder = {}
-- Boolean
self.decoder["01"] = function( self, encStr, elen, pos )
local val = bin.unpack("H", encStr, pos)
if val ~= "FF" then
return pos, true
else
return pos, false
end
end
-- Integer
self.decoder["02"] = function( self, encStr, elen, pos )
return self.decodeInt(encStr, elen, pos)
end
-- Octet String
self.decoder["04"] = function( self, encStr, elen, pos )
return bin.unpack("A" .. elen, encStr, pos)
end
-- Null
self.decoder["05"] = function( self, encStr, elen, pos )
return pos, false
end
-- Object Identifier
self.decoder["06"] = function( self, encStr, elen, pos )
return self:decodeOID( encStr, elen, pos )
end
-- Context specific tags
--
self.decoder["30"] = function( self, encStr, elen, pos )
return self:decodeSeq(encStr, elen, pos)
end
end,
--- Allows for registration of additional tag decoders
--
-- @param table containing decoding functions @see tagDecoders
registerTagDecoders = function(self, tagDecoders)
self:registerBaseDecoders()
for k, v in pairs(tagDecoders) do
self.decoder[k] = v
end
end,
--- Decodes the ASN.1's built-in simple types
--
-- @param encStr Encoded string.
-- @param pos Current position in the string.
-- @return The position after decoding
-- @return The decoded value(s).
decode = function(self, encStr, pos)
local etype, elen
local newpos = pos
newpos, etype = bin.unpack("H1", encStr, newpos)
newpos, elen = self.decodeLength(encStr, newpos)
if self.decoder[etype] then
return self.decoder[etype]( self, encStr, elen, newpos )
else
stdnse.print_debug("no decoder for etype: " .. etype)
return newpos, nil
end
end,
---
-- Decodes length part of encoded value according to ASN.1 basic encoding
-- rules.
-- @param encStr Encoded string.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The length of the following value.
decodeLength = function(encStr, pos)
local elen
pos, elen = bin.unpack('C', encStr, pos)
if (elen > 128) then
elen = elen - 128
local elenCalc = 0
local elenNext
for i = 1, elen do
elenCalc = elenCalc * 256
pos, elenNext = bin.unpack("C", encStr, pos)
elenCalc = elenCalc + elenNext
end
elen = elenCalc
end
return pos, elen
end,
---
-- Decodes a sequence according to ASN.1 basic encoding rules.
-- @param encStr Encoded string.
-- @param len Length of sequence in bytes.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded sequence as a table.
decodeSeq = function(self, encStr, len, pos)
local seq = {}
local sPos = 1
local sStr
pos, sStr = bin.unpack("A" .. len, encStr, pos)
while (sPos < len) do
local newSeq
sPos, newSeq = self:decode(sStr, sPos)
table.insert(seq, newSeq)
end
return pos, seq
end,
-- Decode one component of an OID from a byte string. 7 bits of the component
-- are stored in each octet, most significant first, with the eigth bit set in
-- all octets but the last. These encoding rules come from
-- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
-- IDENTIFIER.
decode_oid_component = function(encStr, pos)
local octet
local n = 0
repeat
pos, octet = bin.unpack("C", encStr, pos)
n = n * 128 + bit.band(0x7F, octet)
until octet < 128
return pos, n
end,
--- Decodes an OID from a sequence of bytes.
--
-- @param encStr Encoded string.
-- @param len Length of sequence in bytes.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The OID as an array.
decodeOID = function(self, encStr, len, pos)
local last
local oid = {}
local octet
last = pos + len - 1
if pos <= last then
oid._snmp = '06'
pos, octet = bin.unpack("C", encStr, pos)
oid[2] = math.mod(octet, 40)
octet = octet - oid[2]
oid[1] = octet/40
end
while pos <= last do
local c
pos, c = self.decode_oid_component(encStr, pos)
oid[#oid + 1] = c
end
return pos, oid
end,
---
-- Decodes length part of encoded value according to ASN.1 basic encoding
-- rules.
-- @param encStr Encoded string.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The length of the following value.
decodeLength = function(encStr, pos)
local elen
pos, elen = bin.unpack('C', encStr, pos)
if (elen > 128) then
elen = elen - 128
local elenCalc = 0
local elenNext
for i = 1, elen do
elenCalc = elenCalc * 256
pos, elenNext = bin.unpack("C", encStr, pos)
elenCalc = elenCalc + elenNext
end
elen = elenCalc
end
return pos, elen
end,
---
-- Decodes an Integer according to ASN.1 basic encoding rules.
-- @param encStr Encoded string.
-- @param len Length of integer in bytes.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded integer.
decodeInt = function(encStr, len, pos)
local hexStr
pos, hexStr = bin.unpack("H" .. len, encStr, pos)
local value = tonumber(hexStr, 16)
if (value >= math.pow(256, len)/2) then
value = value - math.pow(256, len)
end
return pos, value
end,
---
-- Decodes an SNMP packet or a part of it according to ASN.1 basic encoding
-- rules.
-- @param encStr Encoded string.
-- @param pos Current position in the string.
-- @return The decoded value(s).
dec = function(self, encStr, pos)
local result
local _
_, result = self:decode(encStr, pos)
return result
end,
}
--- The encoder class
--
ASN1Encoder = {
new = function(self,o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end,
---
-- Encodes an ASN1 sequence
encodeSeq = function(self, seqData)
return bin.pack('HAA' , '30', self.encodeLength(string.len(seqData)), seqData)
end,
---
-- Encodes a given value according to ASN.1 basic encoding rules for SNMP
-- packet creation.
-- @param val Value to be encoded.
-- @return Encoded value.
encode = function(self, val)
local vtype = type(val)
if self.encoder[vtype] then
return self.encoder[vtype](self,val)
else
return nil
end
return ''
end,
--- Allows for registration of additional tag encoders
--
-- @param table containing encoding functions @see tagEncoders
registerTagEncoders = function(self, tagEncoders)
self:registerBaseEncoders()
for k, v in pairs(tagEncoders) do
self.encoder[k] = v
end
end,
-- ASN.1 Simple types encoders
registerBaseEncoders = function(self)
self.encoder = {}
-- Bolean encoder
self.encoder['boolean'] = function( self, val )
if val then
return bin.pack('H','01 01 FF')
else
return bin.pack('H', '01 01 00')
end
end
-- Integer encoder
self.encoder['number'] = function( self, val )
local ival = self.encodeInt(val)
local len = self.encodeLength(string.len(ival))
return bin.pack('HAA', '02', len, ival)
end
-- Octet String encoder
self.encoder['string'] = function( self, val )
local len = self.encodeLength(string.len(val))
return bin.pack('HAA', '04', len, val)
end
-- Null encoder
self.encoder['nil'] = function( self, val )
return bin.pack('H', '05 00')
end
end,
-- Encode one component of an OID as a byte string. 7 bits of the component are
-- stored in each octet, most significant first, with the eigth bit set in all
-- octets but the last. These encoding rules come from
-- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
-- IDENTIFIER.
encode_oid_component = function(n)
local parts = {}
parts[1] = string.char(bit.mod(n, 128))
while n >= 128 do
n = bit.rshift(n, 7)
parts[#parts + 1] = string.char(bit.mod(n, 128) + 0x80)
end
return string.reverse(table.concat(parts))
end,
---
-- Encodes an Integer according to ASN.1 basic encoding rules.
-- @param val Value to be encoded.
-- @return Encoded integer.
encodeInt = function(val)
local lsb = 0
if val > 0 then
local valStr = ""
while (val > 0) do
lsb = math.mod(val, 256)
valStr = valStr .. bin.pack("C", lsb)
val = math.floor(val/256)
end
if lsb > 127 then -- two's complement collision
valStr = valStr .. bin.pack("H", "00")
end
return string.reverse(valStr)
elseif val < 0 then
local i = 1
local tcval = val + 256 -- two's complement
while tcval <= 127 do
tcval = tcval + (math.pow(256, i) * 255)
i = i+1
end
local valStr = ""
while (tcval > 0) do
lsb = math.mod(tcval, 256)
valStr = valStr .. bin.pack("C", lsb)
tcval = math.floor(tcval/256)
end
return string.reverse(valStr)
else -- val == 0
return bin.pack("x")
end
end,
---
-- Encodes the length part of a ASN.1 encoding triplet using the "primitive,
-- definite-length" method.
-- @param val Value to be encoded.
-- @return Encoded length value.
encodeLength = function(len)
if len < 128 then
return string.char(len)
else
local parts = {}
while len > 0 do
parts[#parts + 1] = string.char(bit.mod(len, 256))
len = bit.rshift(len, 8)
end
assert(#parts < 128)
return string.char(#parts + 0x80) .. string.reverse(table.concat(parts))
end
end
}
---
-- Converts a BER encoded type to a numeric value
-- This allows it to be used in the encoding function
--
-- @param class number - see <code>BERCLASS<code>
-- @param constructed boolean (true if constructed, false if primitive)
-- @param number numeric
-- @return number to be used with <code>encode</code>
function BERtoInt(class, constructed, number)
local asn1_type = class + number
if constructed == true then
asn1_type = asn1_type + 32
end
return asn1_type
end
---
-- Converts an integer to a BER encoded type table
--
-- @param i number containing the value to decode
-- @return table with the following entries <code>class</code>, <code>constructed</code>,
-- <code>primitive</code> and <code>number</code>
function intToBER( i )
local ber = {}
if bit.band( i, BERCLASS.Application ) == BERCLASS.Application then
ber.class = BERCLASS.Application
elseif bit.band( i, BERCLASS.ContextSpecific ) == BERCLASS.ContextSpecific then
ber.class = BERCLASS.ContextSpecific
elseif bit.band( i, BERCLASS.Private ) == BERCLASS.Private then
ber.class = BERCLASS.Private
else
ber.class = BERCLASS.Universal
end
if bit.band( i, 32 ) == 32 then
ber.constructed = true
ber.number = i - ber.class - 32
else
ber.primitive = true
ber.number = i - ber.class
end
return ber
end

View File

@@ -3,254 +3,158 @@
-- @args snmpcommunity The community string to use. If not given, it is
-- <code>"public"</code>, or whatever is passed to <code>buildPacket</code>.
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
--
--
--
module(... or "snmp",package.seeall)
require("bit")
require("asn1")
---
-- Encodes an Integer according to ASN.1 basic encoding rules.
-- @param val Value to be encoded.
-- @return Encoded integer.
local function encodeInt(val)
local lsb = 0
if val > 0 then
local valStr = ""
while (val > 0) do
lsb = math.mod(val, 256)
valStr = valStr .. bin.pack("C", lsb)
val = math.floor(val/256)
end
if lsb > 127 then -- two's complement collision
valStr = valStr .. bin.pack("H", "00")
end
-- SNMP ASN.1 Encoders
local tagEncoder = {}
return string.reverse(valStr)
elseif val < 0 then
local i = 1
local tcval = val + 256 -- two's complement
while tcval <= 127 do
tcval = tcval + (math.pow(256, i) * 255)
i = i+1
end
local valStr = ""
while (tcval > 0) do
lsb = math.mod(tcval, 256)
valStr = valStr .. bin.pack("C", lsb)
tcval = math.floor(tcval/256)
end
return string.reverse(valStr)
else -- val == 0
return bin.pack("x")
end
-- Override the boolean encoder
tagEncoder['boolean'] = function(self, val)
return bin.pack('H', '05 00')
end
-- Complex tag encoders
tagEncoder['table'] = function(self, val)
if val._snmp == '06' then -- OID
local oidStr = string.char(val[1]*40 + val[2])
for i = 3, #val do
oidStr = oidStr .. self.encode_oid_component(val[i])
end
return bin.pack("HAA", '06', self.encodeLength(#oidStr), oidStr)
---
-- Encodes the length part of a ASN.1 encoding triplet using the "primitive,
-- definite-length" method.
-- @param val Value to be encoded.
-- @return Encoded length value.
local function encodeLength(len)
if len < 128 then
return string.char(len)
else
local parts = {}
elseif (val._snmp == '40') then -- ipAddress
return bin.pack("HC4", '40 04', unpack(val))
-- counter or gauge or timeticks or opaque
elseif (val._snmp == '41' or val._snmp == '42' or val._snmp == '43' or val._snmp == '44') then
local val = self:encodeInt(val[1])
return bin.pack("HAA", val._snmp, self.encodeLength(string.len(val)), val)
end
local encVal = ""
for _, v in ipairs(val) do
encVal = encVal .. self:encode(v) -- todo: buffer?
end
while len > 0 do
parts[#parts + 1] = string.char(bit.mod(len, 256))
len = bit.rshift(len, 8)
end
assert(#parts < 128)
return string.char(#parts + 0x80) .. string.reverse(table.concat(parts))
end
local tableType = bin.pack("H", "30")
if (val["_snmp"]) then
tableType = bin.pack("H", val["_snmp"])
end
return bin.pack('AAA', tableType, self.encodeLength(string.len(encVal)), encVal)
end
-- Encode one component of an OID as a byte string. 7 bits of the component are
-- stored in each octet, most significant first, with the eigth bit set in all
-- octets but the last. These encoding rules come from
-- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
-- IDENTIFIER.
local function encode_oid_component(n)
local parts = {}
parts[1] = string.char(bit.mod(n, 128))
while n >= 128 do
n = bit.rshift(n, 7)
parts[#parts + 1] = string.char(bit.mod(n, 128) + 0x80)
end
return string.reverse(table.concat(parts))
end
---
-- Encodes a given value according to ASN.1 basic encoding rules for SNMP
-- packet creation.
-- @param val Value to be encoded.
-- @return Encoded value.
function encode(val)
local vtype = type(val)
if (vtype == 'number') then
local ival = encodeInt(val)
local len = encodeLength(string.len(ival))
return bin.pack('HAA', '02', len, ival)
end
if (vtype == 'string') then
local len = encodeLength(string.len(val))
return bin.pack('HAA', '04', len, val)
end
if (vtype == 'nil' or vtype == 'boolean') then
return bin.pack('H', '05 00')
end
if (vtype == 'table') then -- complex data types
if val._snmp == '06' then -- OID
local oidStr = string.char(val[1]*40 + val[2])
for i = 3, #val do
oidStr = oidStr .. encode_oid_component(val[i])
end
return bin.pack("HAA", '06', encodeLength(#oidStr), oidStr)
elseif (val._snmp == '40') then -- ipAddress
return bin.pack("HC4", '40 04', unpack(val))
elseif (val._snmp == '41') then -- counter
local cnt = encodeInt(val[1])
return bin.pack("HAA", val._snmp, encodeLength(string.len(cnt)), cnt)
elseif (val._snmp == '42') then -- gauge
local gauge = encodeInt(val[1])
return bin.pack("HAA", val._snmp, encodeLength(string.len(gauge)), gauge)
elseif (val._snmp == '43') then -- timeticks
local ticks = encodeInt(val[1])
return bin.pack("HAA", val._snmp, encodeLength(string.len(ticks)), ticks)
elseif (val._snmp == '44') then -- opaque
return bin.pack("HAA", val._snmp, encodeLength(string.len(val[1])), val[1])
end
local encVal = ""
for _, v in ipairs(val) do
encVal = encVal .. encode(v) -- todo: buffer?
end
local tableType = bin.pack("H", "30")
if (val["_snmp"]) then
tableType = bin.pack("H", val["_snmp"])
end
return bin.pack('AAA', tableType, encodeLength(string.len(encVal)), encVal)
end
return ''
local vtype = type(val)
local encoder = asn1.ASN1Encoder:new()
encoder:registerTagEncoders( tagEncoder )
local encVal = encoder:encode(val)
if encVal then
return encVal
end
return ''
end
-- SNMP ASN.1 Decoders
local tagDecoder = {}
---
-- Decodes length part of encoded value according to ASN.1 basic encoding
-- rules.
-- @param encStr Encoded string.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The length of the following value.
local function decodeLength(encStr, pos)
local elen
pos, elen = bin.unpack('C', encStr, pos)
if (elen > 128) then
elen = elen - 128
local elenCalc = 0
local elenNext
for i = 1, elen do
elenCalc = elenCalc * 256
pos, elenNext = bin.unpack("C", encStr, pos)
elenCalc = elenCalc + elenNext
end
elen = elenCalc
end
return pos, elen
end
---
-- Decodes an Integer according to ASN.1 basic encoding rules.
-- @param encStr Encoded string.
-- @param len Length of integer in bytes.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded integer.
local function decodeInt(encStr, len, pos)
local hexStr
pos, hexStr = bin.unpack("H" .. len, encStr, pos)
local value = tonumber(hexStr, 16)
if (value >= math.pow(256, len)/2) then
value = value - math.pow(256, len)
end
return pos, value
end
-- Decode one component of an OID from a byte string. 7 bits of the component
-- are stored in each octet, most significant first, with the eigth bit set in
-- all octets but the last. These encoding rules come from
-- http://luca.ntop.org/Teaching/Appunti/asn1.html, section 5.9 OBJECT
-- IDENTIFIER.
local function decode_oid_component(encStr, pos)
local octet
local n = 0
repeat
pos, octet = bin.unpack("C", encStr, pos)
n = n * 128 + bit.band(0x7F, octet)
until octet < 128
return pos, n
end
--- Decodes an OID from a sequence of bytes.
-- Application specific tags
--
-- @param encStr Encoded string.
-- @param len Length of sequence in bytes.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The OID as an array.
local function decodeOID(encStr, len, pos)
local last
local oid = {}
local octet
-- IP Address
last = pos + len - 1
if pos <= last then
oid._snmp = '06'
pos, octet = bin.unpack("C", encStr, pos)
oid[2] = math.mod(octet, 40)
octet = octet - oid[2]
oid[1] = octet/40
end
while pos <= last do
local c
pos, c = decode_oid_component(encStr, pos)
oid[#oid + 1] = c
end
return pos, oid
tagDecoder["40"] = function( self, encStr, elen, pos )
local ip = {}
pos, ip[1], ip[2], ip[3], ip[4] = bin.unpack("C4", encStr, pos)
ip._snmp = '40'
return pos, ip
end
---
-- Decodes a sequence according to ASN.1 basic encoding rules.
-- @param encStr Encoded string.
-- @param len Length of sequence in bytes.
-- @param pos Current position in the string.
-- @return The position after decoding.
-- @return The decoded sequence as a table.
local function decodeSeq(encStr, len, pos)
local seq = {}
local sPos = 1
local i = 1
local sStr
pos, sStr = bin.unpack("A" .. len, encStr, pos)
while (sPos < len) do
local newSeq
sPos, newSeq = decode(sStr, sPos)
table.insert(seq, newSeq)
i = i + 1
end
return pos, seq
-- Counter
tagDecoder["41"] = function( self, encStr, elen, pos )
local tbl = {}
pos, tbl[1] = self.decodeInt(encStr, elen, pos)
tbl._snmp = '41'
return pos, tbl
end
-- Gauge
tagDecoder["42"] = function( self, encStr, elen, pos )
local tbl = {}
pos, tbl[1] = self.decodeInt(encStr, elen, pos)
tbl._snmp = '41'
return pos, tbl
end
-- TimeTicks
tagDecoder["43"] = function( self, encStr, elen, pos )
local tbl = {}
pos, tbl[1] = self.decodeInt(encStr, elen, pos)
tbl._snmp = '41'
return pos, tbl
end
-- Opaque
tagDecoder["44"] = function( self, encStr, elen, pos )
local tbl = {}
pos, tbl[1] = self.decodeInt(encStr, elen, pos)
tbl._snmp = '41'
return pos, tbl
end
-- Context specific tags
--
tagDecoder["A0"] = function( self, encStr, elen, pos )
local seq
pos, seq = self:decodeSeq(encStr, elen, pos)
seq._snmp = "A0"
return pos, seq
end
tagDecoder["A1"] = function( self, encStr, elen, pos )
local seq
pos, seq = self:decodeSeq(encStr, elen, pos)
seq._snmp = "A1"
return pos, seq
end
tagDecoder["A2"] = function( self, encStr, elen, pos )
local seq
pos, seq = self:decodeSeq(encStr, elen, pos)
seq._snmp = "A2"
return pos, seq
end
tagDecoder["A3"] = function( self, encStr, elen, pos )
local seq
pos, seq = self:decodeSeq(encStr, elen, pos)
seq._snmp = "A3"
return pos, seq
end
tagDecoder["A4"] = function( self, encStr, elen, pos )
local seq
pos, seq = self:decodeSeq(encStr, elen, pos)
seq._snmp = "A4"
return pos, seq
end
---
-- Decodes an SNMP packet or a part of it according to ASN.1 basic encoding
-- rules.
@@ -259,81 +163,10 @@ end
-- @return The position after decoding
-- @return The decoded value(s).
function decode(encStr, pos)
local etype, elen
pos, etype = bin.unpack("H1", encStr, pos)
pos, elen = decodeLength(encStr, pos)
if (etype == "02") then -- INTEGER
return decodeInt(encStr, elen, pos)
elseif (etype == "04") then -- STRING
return bin.unpack("A" .. elen, encStr, pos)
elseif (etype == "05") then -- NULL
return pos, false
local decoder = asn1.ASN1Decoder:new()
decoder:registerTagDecoders( tagDecoder )
elseif (etype == "06") then -- OID
return decodeOID( encStr, elen, pos )
elseif (etype == "30") then -- sequence
local seq
pos, seq = decodeSeq(encStr, elen, pos)
return pos, seq
elseif (etype == "A0") then -- getReq
local seq
pos, seq = decodeSeq(encStr, elen, pos)
seq._snmp = etype
return pos, seq
elseif (etype == "A1") then -- getNextReq
local seq
pos, seq = decodeSeq(encStr, elen, pos)
seq._snmp = etype
return pos, seq
elseif (etype == "A2") then -- getResponse
local seq
pos, seq = decodeSeq(encStr, elen, pos)
seq._snmp = etype
return pos, seq
elseif (etype == "A3") then -- setReq
local seq
pos, seq = decodeSeq(encStr, elen, pos)
seq._snmp = etype
return pos, seq
elseif (etype == "A4") then -- Trap
local seq
pos, seq = decodeSeq(encStr, elen, pos)
seq._snmp = etype
return pos, seq
elseif (etype == '40') then -- App: IP-Address
local ip = {}
pos, ip[1], ip[2], ip[3], ip[4] = bin.unpack("C4", encStr, pos)
ip._snmp = '40'
return pos, ip
elseif (etype == '41') then -- App: counter
local cnt = {}
pos, cnt[1] = decodeInt(encStr, elen, pos)
cnt._snmp = '41'
return pos, cnt
elseif (etype == '42') then -- App: gauge
local gauge = {}
pos, gauge[1] = decodeInt(encStr, elen, pos)
gauge._snmp = '42'
return pos, gauge
elseif (etype == '43') then -- App: TimeTicks
local ticks = {}
pos, ticks[1] = decodeInt(encStr, elen, pos)
ticks._snmp = '43'
return pos, ticks
elseif (etype == '44') then -- App: opaque
local opaque = {}
pos, opaque[1] = bin.unpack("A" .. elen, encStr, pos)
opaque._snmp = '44'
return pos, opaque
end
return pos, nil
return decoder:decode( encStr, pos )
end
---
@@ -416,7 +249,7 @@ end
function buildGetNextRequest(options, ...)
if not options then options = {} end
if not options.reqId then options.reqId = math.mod(nmap.clock_ms(), 65000) end
if not options.reqId then options.reqId = math.mod(nmap.clock_ms(), 65000) end
if not options.err then options.err = 0 end
if not options.errIdx then options.errIdx = 0 end
@@ -431,7 +264,7 @@ function buildGetNextRequest(options, ...)
payload[i] = {}
payload[i][1] = select(i, ...)
if type(payload[i][1]) == "string" then
payload[i][1] = str2oid(payload[i][1])
payload[i][1] = str2oid(payload[i][1])
end
payload[i][2] = false
end
@@ -648,8 +481,11 @@ end
-- @param response SNMP Response (will be decoded if necessary).
-- @return First decoded value of the response.
function fetchFirst(response)
local result = fetchResponseValues(response)
if type(result) == "table" and result[1] and result[1][1] then return result[1][1]
else return nil
end
local result = fetchResponseValues(response)
if type(result) == "table" and result[1] and result[1][1] then
return result[1][1]
else
return nil
end
end

145
scripts/snmp-netstat.nse Normal file
View File

@@ -0,0 +1,145 @@
description = [[
Attempts to query SNMP for a netstat like output
]]
---
-- @output
-- | snmp-netstat:
-- | TCP 0.0.0.0:21 0.0.0.0:2256
-- | TCP 0.0.0.0:80 0.0.0.0:8218
-- | TCP 0.0.0.0:135 0.0.0.0:53285
-- | TCP 0.0.0.0:389 0.0.0.0:38990
-- | TCP 0.0.0.0:445 0.0.0.0:49158
-- | TCP 127.0.0.1:389 127.0.0.1:1045
-- | TCP 127.0.0.1:389 127.0.0.1:1048
-- | UDP 192.168.56.3:137 *:*
-- | UDP 192.168.56.3:138 *:*
-- | UDP 192.168.56.3:389 *:*
-- |_ UDP 192.168.56.3:464 *:*
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
dependencies = {"snmp-brute"}
-- Version 0.1
-- Created 01/19/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
require "shortport"
require "snmp"
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
--- Walks the MIB Tree
--
-- @param socket socket already connected to the server
-- @base_oid string containing the base object ID to walk
-- @return table containing <code>oid</code> and <code>value</code>
function snmp_walk( socket, base_oid )
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmp_table = {}
local oid = base_oid
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
options.reqId = 28428 -- unnecessary?
payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) )
try(socket:send(payload))
response = try( socket:receive_bytes(1) )
snmpdata = snmp.fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
local lip = oid:match( "^" .. base_oid .. "%.(%d+%.%d+%.%d+%.%d+)") or ""
local lport = oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.(%d+)")
local fip = oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+%.%d+%.%d+%.%d+)") or "*:*"
local fport = oid:match( "^" .. base_oid .. "%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.%d+%.(%d+)")
if lport and lport ~= "0" then
lip = lip .. ":" .. lport
end
if fport and fport ~= "0" then
fip = fip .. ":" .. fport
end
value = string.format("%-20s %s", lip, fip )
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
snmp_table.baseoid = base_oid
return snmp_table
end
--- Processes the table and creates the script output
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl, prefix )
local new_tab = {}
for _, v in ipairs( tbl ) do
table.insert( new_tab, string.format( "%-4s %s", prefix, v.value ) )
end
return new_tab
end
function table_merge( t1, t2 )
for _, v in ipairs(t2) do
table.insert(t1, v)
end
return t1
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local tcp_oid = "1.3.6.1.2.1.6.13.1.1"
local udp_oid = "1.3.6.1.2.1.7.5.1.1"
local netstat = {}
socket:set_timeout(5000)
try(socket:connect(host.ip, port.number, "udp"))
local tcp = snmp_walk( socket, tcp_oid )
local udp = snmp_walk( socket, udp_oid )
if ( tcp == nil ) or ( #tcp == 0 ) or ( udp==nil ) or ( #udp == 0 ) then
return
end
tcp = process_answer(tcp, "TCP")
udp = process_answer(udp, "UDP")
netstat = table_merge( tcp, udp )
nmap.set_port_state(host, port, "open")
socket:close()
return stdnse.format_output( true, netstat )
end

176
scripts/snmp-processes.nse Normal file
View File

@@ -0,0 +1,176 @@
description = [[
Attempts to enumerate running processes through SNMP
]]
---
-- @output
-- | snmp-processes:
-- | System Idle Process
-- | PID: 1
-- | System
-- | PID: 4
-- | smss.exe
-- | Path: \SystemRoot\System32\
-- | PID: 256
-- | csrss.exe
-- | Path: C:\WINDOWS\system32\
-- | Params: ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserS
-- | PID: 308
-- | winlogon.exe
-- | PID: 332
-- | services.exe
-- | Path: C:\WINDOWS\system32\
-- | PID: 380
-- | lsass.exe
-- | Path: C:\WINDOWS\system32\
-- |_ PID: 392
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
dependencies = {"snmp-brute"}
-- Version 0.3
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist
-- Revised 01/19/2010 - v0.2 - removed debugging output and renamed file
require "shortport"
require "snmp"
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
--- Walks the MIB Tree
--
-- @param socket socket already connected to the server
-- @base_oid string containing the base object ID to walk
-- @return table containing <code>oid</code> and <code>value</code>
function snmp_walk( socket, base_oid )
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmp_table = {}
local oid = base_oid
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
options.reqId = 28428 -- unnecessary?
payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) )
try(socket:send(payload))
response = try( socket:receive_bytes(1) )
snmpdata = snmp.fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
socket:close()
snmp_table.baseoid = base_oid
return snmp_table
end
--- Gets a value for the specified oid
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @param oid string containing the object id for which the value should be extracted
-- @return value of relevant type or nil if oid was not found
function get_value_from_table( tbl, oid )
for _, v in ipairs( tbl ) do
if v.oid == oid then
return v.value
end
end
return nil
end
--- Processes the table and creates the script output
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl )
local swrun_name = "1.3.6.1.2.1.25.4.2.1.2"
local swrun_pid = "1.3.6.1.2.1.25.4.2.1.1"
local swrun_path = "1.3.6.1.2.1.25.4.2.1.4"
local swrun_params = "1.3.6.1.2.1.25.4.2.1.5"
local new_tbl = {}
for _, v in ipairs( tbl ) do
if ( v.oid:match("^" .. swrun_name) ) then
local item = {}
local objid = v.oid:gsub( "^" .. swrun_name, swrun_path)
local value = get_value_from_table( tbl, objid )
if value and value:len() > 0 then
table.insert( item, ("Path: %s"):format( value ) )
end
objid = v.oid:gsub( "^" .. swrun_name, swrun_params)
value = get_value_from_table( tbl, objid )
if value and value:len() > 0 then
table.insert( item, ("Params: %s"):format( value ) )
end
objid = v.oid:gsub( "^" .. swrun_name, swrun_pid)
value = get_value_from_table( tbl, objid )
if value then
table.insert( item, ("PID: %s"):format( value ) )
end
item.name = v.value
table.insert( item, value )
table.insert( new_tbl, item )
end
end
return new_tbl
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local data, snmpoid = nil, "1.3.6.1.2.1.25.4.2"
local shares = {}
socket:set_timeout(5000)
try(socket:connect(host.ip, port.number, "udp"))
shares = snmp_walk( socket, snmpoid )
if ( shares == nil ) or ( #shares == 0 ) then
return
end
shares = process_answer( shares )
nmap.set_port_state(host, port, "open")
return stdnse.format_output( true, shares )
end

View File

@@ -0,0 +1,121 @@
description = [[
Attempts to enumerate Windows Services through SNMP
]]
---
-- @output
-- | snmp-win32-services:
-- | Apache Tomcat
-- | Application Experience Lookup Service
-- | Application Layer Gateway Service
-- | Automatic Updates
-- | COM+ Event System
-- | COM+ System Application
-- | Computer Browser
-- | Cryptographic Services
-- | DB2 - DB2COPY1 - DB2
-- | DB2 Management Service (DB2COPY1)
-- | DB2 Remote Command Server (DB2COPY1)
-- | DB2DAS - DB2DAS00
-- |_ DCOM Server Process Launcher
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
dependencies = {"snmp-brute"}
-- Version 0.2
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist
require "shortport"
require "snmp"
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
--- Walks the MIB Tree
--
-- @param socket socket already connected to the server
-- @base_oid string containing the base object ID to walk
-- @return table containing <code>oid</code> and <code>value</code>
function snmp_walk( socket, base_oid )
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmp_table = {}
local oid = base_oid
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
options.reqId = 28428 -- unnecessary?
payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) )
try(socket:send(payload))
response = try( socket:receive_bytes(1) )
snmpdata = snmp.fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
socket:close()
snmp_table.baseoid = base_oid
return snmp_table
end
--- Processes the table and creates the script output
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl )
local new_tab = {}
for _, v in ipairs( tbl ) do
table.insert( new_tab, v.value )
end
table.sort( new_tab )
return new_tab
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmpoid = "1.3.6.1.4.1.77.1.2.3.1.1"
local services = {}
socket:set_timeout(5000)
try(socket:connect(host.ip, port.number, "udp"))
services = snmp_walk( socket, snmpoid )
if ( services == nil ) or ( #services == 0 ) then
return
end
services = process_answer(services)
nmap.set_port_state(host, port, "open")
return stdnse.format_output( true, services )
end

View File

@@ -0,0 +1,142 @@
description = [[
Attempts to enumerate Windows Shares through SNMP
]]
---
-- @output
-- | snmp-win32-shares:
-- | SYSVOL
-- | C:\WINDOWS\sysvol\sysvol
-- | NETLOGON
-- | C:\WINDOWS\sysvol\sysvol\inspectit-labb.local\SCRIPTS
-- | Webapps
-- |_ C:\Program Files\Apache Software Foundation\Tomcat 5.5\webapps\ROOT
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
dependencies = {"snmp-brute"}
-- Version 0.2
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist
require "shortport"
require "snmp"
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
--- Walks the MIB Tree
--
-- @param socket socket already connected to the server
-- @base_oid string containing the base object ID to walk
-- @return table containing <code>oid</code> and <code>value</code>
function snmp_walk( socket, base_oid )
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmp_table = {}
local oid = base_oid
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
options.reqId = 28428 -- unnecessary?
payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) )
try(socket:send(payload))
response = try( socket:receive_bytes(1) )
snmpdata = snmp.fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
socket:close()
snmp_table.baseoid = base_oid
return snmp_table
end
--- Gets a value for the specified oid
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @param oid string containing the object id for which the value should be extracted
-- @return value of relevant type or nil if oid was not found
function get_value_from_table( tbl, oid )
for _, v in ipairs( tbl ) do
if v.oid == oid then
return v.value
end
end
return nil
end
--- Processes the table and creates the script output
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl )
local share_name = "1.3.6.1.4.1.77.1.2.27.1.1"
local share_path = "1.3.6.1.4.1.77.1.2.27.1.2"
local new_tbl = {}
for _, v in ipairs( tbl ) do
if ( v.oid:match("^" .. share_name) ) then
local item = {}
local objid = v.oid:gsub( "^" .. share_name, share_path)
local path = get_value_from_table( tbl, objid )
item.name = v.value
table.insert( item, path )
table.insert( new_tbl, item )
end
end
return new_tbl
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local data, snmpoid = nil, "1.3.6.1.4.1.77.1.2.27"
local shares = {}
socket:set_timeout(5000)
try(socket:connect(host.ip, port.number, "udp"))
shares = snmp_walk( socket, snmpoid )
if ( shares == nil ) or ( #shares == 0 ) then
return
end
shares = process_answer( shares )
nmap.set_port_state(host, port, "open")
return stdnse.format_output( true, shares )
end

View File

@@ -0,0 +1,147 @@
description = [[
Attempts to enumerate installed software through SNMP
]]
---
-- @output
-- | snmp-win32-software:
-- | Apache Tomcat 5.5 (remove only); 2007-09-15 15:13:18
-- | Microsoft Internationalized Domain Names Mitigation APIs; 2007-09-15 15:13:18
-- | Security Update for Windows Media Player (KB911564); 2007-09-15 15:13:18
-- | Security Update for Windows Server 2003 (KB924667-v2); 2007-09-15 15:13:18
-- | Security Update for Windows Media Player 6.4 (KB925398); 2007-09-15 15:13:18
-- | Security Update for Windows Server 2003 (KB925902); 2007-09-15 15:13:18
-- |_ Windows Internet Explorer 7; 2007-09-15 15:13:18
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
dependencies = {"snmp-brute"}
-- Version 0.2
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist
require "shortport"
require "snmp"
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
--- Walks the MIB Tree
--
-- @param socket socket already connected to the server
-- @base_oid string containing the base object ID to walk
-- @return table containing <code>oid</code> and <code>value</code>
function snmp_walk( socket, base_oid )
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmp_table = {}
local oid = base_oid
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
options.reqId = 28428 -- unnecessary?
payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) )
try(socket:send(payload))
response = try( socket:receive_bytes(1) )
snmpdata = snmp.fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
socket:close()
snmp_table.baseoid = base_oid
return snmp_table
end
--- Gets a value for the specified oid
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @param oid string containing the object id for which the value should be extracted
-- @return value of relevant type or nil if oid was not found
function get_value_from_table( tbl, oid )
for _, v in ipairs( tbl ) do
if v.oid == oid then
return v.value
end
end
return nil
end
--- Processes the table and creates the script output
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl )
local sw_name = "1.3.6.1.2.1.25.6.3.1.2"
local sw_date = "1.3.6.1.2.1.25.6.3.1.5"
local new_tbl = {}
for _, v in ipairs( tbl ) do
if ( v.oid:match("^" .. sw_name) ) then
local objid = v.oid:gsub( "^" .. sw_name, sw_date)
local install_date = get_value_from_table( tbl, objid )
local sw_item
local _, year, month, day, hour, min, sec = bin.unpack( ">SCCCCC", install_date )
install_date = ("%02d-%02d-%02d %02d:%02d:%02d"):format( year, month, day, hour, min, sec )
sw_item = ("%s; %s"):format(v.value ,install_date)
table.insert( new_tbl, sw_item )
end
end
table.sort( new_tbl )
return new_tbl
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local data, snmpoid = nil, "1.3.6.1.2.1.25.6.3.1"
local sw = {}
socket:set_timeout(5000)
try(socket:connect(host.ip, port.number, "udp"))
sw = snmp_walk( socket, snmpoid )
if ( sw == nil ) or ( #sw == 0 ) then
return
end
sw = process_answer( sw )
nmap.set_port_state(host, port, "open")
return stdnse.format_output( true, sw )
end

View File

@@ -0,0 +1,118 @@
description = [[
Attempts to enumerate User Accounts through SNMP
]]
---
-- @output
-- | snmp-win32-users:
-- | Administrator
-- | Guest
-- | IUSR_EDUSRV011
-- | IWAM_EDUSRV011
-- | SUPPORT_388945a0
-- | Tomcat
-- | db2admin
-- | ldaptest
-- |_ patrik
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
dependencies = {"snmp-brute"}
-- Version 0.2
-- Created 01/15/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 01/19/2010 - v0.2 - fixed loop that would occure if a mib did not exist
require "shortport"
require "snmp"
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
--- Walks the MIB Tree
--
-- @param socket socket already connected to the server
-- @base_oid string containing the base object ID to walk
-- @return table containing <code>oid</code> and <code>value</code>
function snmp_walk( socket, base_oid )
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmp_table = {}
local oid = base_oid
while ( true ) do
local value, response, snmpdata, options, item = nil, nil, nil, {}, {}
options.reqId = 28428 -- unnecessary?
payload = snmp.encode( snmp.buildPacket( snmp.buildGetNextRequest(options, oid) ) )
try(socket:send(payload))
response = try( socket:receive_bytes(1) )
snmpdata = snmp.fetchResponseValues( response )
value = snmpdata[1][1]
oid = snmpdata[1][2]
if not oid:match( base_oid ) or base_oid == oid then
break
end
item.oid = oid
item.value = value
table.insert( snmp_table, item )
end
socket:close()
snmp_table.baseoid = base_oid
return snmp_table
end
--- Processes the table and creates the script output
--
-- @param tbl table containing <code>oid</code> and <code>value</code>
-- @return table suitable for <code>stdnse.format_output</code>
function process_answer( tbl )
local new_tab = {}
for _, v in ipairs( tbl ) do
table.insert( new_tab, v.value )
end
table.sort( new_tab )
return new_tab
end
action = function(host, port)
local socket = nmap.new_socket()
local catch = function() socket:close() end
local try = nmap.new_try(catch)
local snmpoid = "1.3.6.1.4.1.77.1.2.25"
local users = {}
socket:set_timeout(5000)
try(socket:connect(host.ip, port.number, "udp"))
users = snmp_walk( socket, snmpoid )
users = process_answer( users )
if ( users == nil ) or ( #users == 0 ) then
return
end
nmap.set_port_state(host, port, "open")
return stdnse.format_output( true, users )
end