mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
Improve robustness of PostgreSQL v3 response code. Fixes #2009
This commit is contained in:
107
nselib/pgsql.lua
107
nselib/pgsql.lua
@@ -384,33 +384,30 @@ v3 =
|
|||||||
-- @param pos number containing the offset into the data buffer
|
-- @param pos number containing the offset into the data buffer
|
||||||
-- @return data string containing the initial and any additional data
|
-- @return data string containing the initial and any additional data
|
||||||
readPacket = function(socket, data, pos)
|
readPacket = function(socket, data, pos)
|
||||||
|
pos = pos or 1
|
||||||
|
data = data or ""
|
||||||
|
|
||||||
local pos = pos or 1
|
-- Make sure that we have enough data for the header
|
||||||
local data = data or ""
|
local targetlen = pos - 1 + 5 -- header is 5 bytes (structure >BI4)
|
||||||
local status = true
|
while #data < targetlen do
|
||||||
local tmp = ""
|
local status, extra = socket:receive_bytes(targetlen - #data)
|
||||||
local ptype, len
|
|
||||||
local header
|
|
||||||
|
|
||||||
local catch = function() socket:close() stdnse.debug1("processResponse(): failed") end
|
|
||||||
local try = nmap.new_try(catch)
|
|
||||||
|
|
||||||
if ( data:len() - pos < 5 ) then
|
|
||||||
status, tmp = socket:receive_bytes( 5 - ( data:len() - pos ) )
|
|
||||||
end
|
|
||||||
|
|
||||||
if not status then
|
if not status then
|
||||||
return nil, "Failed to read packet"
|
stdnse.debug1("Not enough data for PGSQL response header")
|
||||||
|
return nil, extra
|
||||||
|
end
|
||||||
|
data = data .. extra
|
||||||
end
|
end
|
||||||
|
|
||||||
if tmp:len() ~= 0 then
|
local _, header = v3.decodeHeader(data, pos)
|
||||||
data = data .. tmp
|
|
||||||
|
targetlen = targetlen + header.len - 4 -- header.len is 4 bytes
|
||||||
|
while #data < targetlen do
|
||||||
|
local status, extra = socket:receive_bytes(targetlen - #data)
|
||||||
|
if not status then
|
||||||
|
stdnse.debug1("Not enough data for declared PGSQL response size")
|
||||||
|
return nil, extra
|
||||||
end
|
end
|
||||||
|
data = data .. extra
|
||||||
pos, header = v3.decodeHeader(data,pos)
|
|
||||||
|
|
||||||
while data:len() < header.len do
|
|
||||||
data = data .. try(socket:receive_bytes( ( header.len + 1 ) - data:len() ))
|
|
||||||
end
|
end
|
||||||
return data
|
return data
|
||||||
end,
|
end,
|
||||||
@@ -436,24 +433,27 @@ v3 =
|
|||||||
-- @return response string containing decoded data
|
-- @return response string containing decoded data
|
||||||
-- error message if pos is -1
|
-- error message if pos is -1
|
||||||
processResponse = function(data, pos)
|
processResponse = function(data, pos)
|
||||||
local ptype, len, status, response
|
pos = pos or 1
|
||||||
local pos = pos or 1
|
|
||||||
local header
|
|
||||||
|
|
||||||
pos, header = v3.decodeHeader( data, pos )
|
if not data then
|
||||||
|
return -1, "Not enough response data"
|
||||||
if v3.messageDecoder[header.type] then
|
|
||||||
pos, response = v3.messageDecoder[header.type](data, header.len, pos)
|
|
||||||
|
|
||||||
if pos ~= -1 then
|
|
||||||
response.type = header.type
|
|
||||||
return pos, response
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
|
local header
|
||||||
|
pos, header = v3.decodeHeader( data, pos )
|
||||||
|
if not v3.messageDecoder[header.type] then
|
||||||
stdnse.debug1("Missing decoder for %d", header.type )
|
stdnse.debug1("Missing decoder for %d", header.type )
|
||||||
return -1, ("Missing decoder for %d"):format(header.type)
|
return -1, ("Missing decoder for %d"):format(header.type)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local response
|
||||||
|
pos, response = v3.messageDecoder[header.type](data, header.len, pos)
|
||||||
|
if pos == -1 then
|
||||||
return -1, "Decoding failed"
|
return -1, "Decoding failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
response.type = header.type
|
||||||
|
return pos, response
|
||||||
end,
|
end,
|
||||||
|
|
||||||
--- Attempts to authenticate to the pgsql server
|
--- Attempts to authenticate to the pgsql server
|
||||||
@@ -469,47 +469,44 @@ v3 =
|
|||||||
-- result string containing an error message if login fails
|
-- result string containing an error message if login fails
|
||||||
loginRequest = function ( socket, params, username, password, salt )
|
loginRequest = function ( socket, params, username, password, salt )
|
||||||
|
|
||||||
local catch = function() socket:close() stdnse.debug1("loginRequest(): failed") end
|
local creds
|
||||||
local try = nmap.new_try(catch)
|
if params.authtype == AuthenticationType.MD5 then
|
||||||
local response, header = {}, {}
|
creds = createMD5LoginHash(username, password, salt)
|
||||||
local status, data, len, tmp, _
|
elseif params.authtype == AuthenticationType.Plain then
|
||||||
local pos = 1
|
creds = password
|
||||||
|
elseif params.authtype == AuthenticationType.Success then
|
||||||
if ( params.authtype == AuthenticationType.MD5 ) then
|
|
||||||
local hash = createMD5LoginHash(username, password, salt)
|
|
||||||
data = string.pack( ">BI4z", MessageType.PasswordMessage, 40, hash )
|
|
||||||
try( socket:send( data ) )
|
|
||||||
elseif ( params.authtype == AuthenticationType.Plain ) then
|
|
||||||
local data
|
|
||||||
data = string.pack(">BI4z", MessageType.PasswordMessage, password:len() + 4, password)
|
|
||||||
try( socket:send( data ) )
|
|
||||||
elseif ( params.authtype == AuthenticationType.Success ) then
|
|
||||||
return true, nil
|
return true, nil
|
||||||
|
else
|
||||||
|
return false, "Unexpected authentication type 0x" .. stdnse.tohex(params.authtype)
|
||||||
end
|
end
|
||||||
|
|
||||||
data, response.params = "", {}
|
local status, err = socket:send(string.pack(">BI4z", MessageType.PasswordMessage, #creds + 5, creds))
|
||||||
|
if not status then
|
||||||
|
return false, "Unable to send AuthRequest: " .. err
|
||||||
|
end
|
||||||
|
|
||||||
data = v3.readPacket(socket, data, 1)
|
local data = v3.readPacket(socket)
|
||||||
pos, tmp = v3.processResponse(data, 1)
|
local pos, tmp = v3.processResponse(data, 1)
|
||||||
|
|
||||||
-- this should contain the AuthRequest packet
|
-- this should contain the AuthRequest packet
|
||||||
if tmp.type ~= MessageType.AuthRequest then
|
if tmp.type ~= MessageType.AuthRequest then
|
||||||
return false, "Expected AuthRequest got something else"
|
return false, "Expected AuthRequest; got something else"
|
||||||
end
|
end
|
||||||
|
|
||||||
if not tmp.success then
|
if not tmp.success then
|
||||||
return false, "Login failure"
|
return false, "Login failure"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local params = {}
|
||||||
repeat
|
repeat
|
||||||
data = v3.readPacket(socket, data, pos)
|
data = v3.readPacket(socket, data, pos)
|
||||||
pos, tmp = v3.processResponse(data, pos)
|
pos, tmp = v3.processResponse(data, pos)
|
||||||
if ( tmp.type == MessageType.ParameterStatus ) then
|
if ( tmp.type == MessageType.ParameterStatus ) then
|
||||||
table.insert(response.params, {name=tmp.key, value=tmp.value})
|
table.insert(params, {name=tmp.key, value=tmp.value})
|
||||||
end
|
end
|
||||||
until pos >= data:len() or pos == -1
|
until pos >= data:len() or pos == -1
|
||||||
|
|
||||||
return true, response
|
return true, {params}
|
||||||
end,
|
end,
|
||||||
|
|
||||||
--- Sends a startup message to the server containing the username and database to connect to
|
--- Sends a startup message to the server containing the username and database to connect to
|
||||||
|
|||||||
Reference in New Issue
Block a user