diff --git a/CHANGELOG b/CHANGELOG index 4a5e40756..0bbcf55a4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Fixed authentication problems in the TNS library that would prevent + authentication from working against Oracle 11.2.0.2.0 XE [Chris Woodbury] + o Removed some restrictions on probe matching that, for example, prevented a RST/ACK reply from being recognized in a NULL scan. This was found and fixed by Matthew Stickney and Joe McEachern. diff --git a/nselib/tns.lua b/nselib/tns.lua index 8470b7df8..f2c8d91b3 100644 --- a/nselib/tns.lua +++ b/nselib/tns.lua @@ -77,7 +77,7 @@ -- @args tns.sid specifies the Oracle instance to connect to -- --- Version 0.6 +-- Version 0.7 -- Created 07/12/2010 - v0.1 - created by Patrik Karlsson -- Revised 07/21/2010 - v0.2 - made minor changes to support 11gR2 on Windows -- Revised 07/23/2010 - v0.3 - corrected incorrect example code in docs @@ -91,19 +91,23 @@ -- - added some more documentation and fixed some -- indentation bugs -- +-- Revised 26/08/2011 - v0.7 - applied patch from Chris Woodbury +-- - -- -- The following versions have been tested and are known to work: --- +--------+---------------+-------+-------------------------------+ --- | OS | DB Version | Arch | Functionality | --- +--------+---------------+-------+-------------------------------| --- | Win | 11.2.0.2.0 | 64bit | Authentication | --- | Win | 11.2.0.1.0 | 64bit | Authentication | --- | Win | 11.1.0.6.0 | 64bit | Authentication | --- | Win | 11.1.0.6.0 | 32bit | Authentication, Queries | --- | Win | 11.2.0.1.0 | 32bit | Authentication, Queries | --- | Linux | 10.2.0.1.0 | 32bit | Authentication | --- | Linux | 11.2.0.1.0 | 64bit | Authentication | --- +--------+---------------+-------+-------------------------------+ +-- +--------+---------------+---------+-------+-------------------------------+ +-- | OS | DB Version | Edition | Arch | Functionality | +-- +--------+---------------+---------+-------+-------------------------------| +-- | Win | 10.2.0.1.0 | EE | 32bit | Authentication | +-- | Linux | 10.2.0.1.0 | EE | 32bit | Authentication | +-- | Win | 11.1.0.6.0 | EE | 64bit | Authentication | +-- | Win | 11.1.0.6.0 | EE | 32bit | Authentication, Queries | +-- | Win | 11.2.0.1.0 | EE | 64bit | Authentication | +-- | Win | 11.2.0.1.0 | XE | 32bit | Authentication, Queries | +-- | Win | 11.2.0.2.0 | EE | 64bit | Authentication | +-- | Win | 11.2.0.2.0 | XE | 32bit | Authentication, Queries | +-- | Linux | 11.2.0.1.0 | EE | 64bit | Authentication | +-- +--------+---------------+---------+-------+-------------------------------+ -- require 'bin' @@ -452,15 +456,6 @@ Packet.PreAuth = { self.__index = self return o end, - - --- Converts a parameter to a string representation - -- - -- @param name string containing the parameter name - -- @param value string containing the parameter value - -- @return string containing the parameter key and value - paramToString = function( self, param_name, param_value ) - return bin.pack(">CIACIAI", #param_name, #param_name, param_name, #param_value, #param_value, param_value, 0 ) - end, --- Converts the DATA packet to string -- @@ -479,9 +474,10 @@ Packet.PreAuth = { data = data .. bin.pack("CA", #self.auth_user, self.auth_user ) for _, v in ipairs( Packet.PreAuth.param_order ) do for k, v2 in pairs(v) do - data = data .. self:paramToString( k, self.auth_options[v2] ) + data = data .. Marshaller.marshalKvp( k, self.auth_options[v2] ) end end + return data end, @@ -492,26 +488,22 @@ Packet.PreAuth = { -- @return table containing the keys and values returned by the server parseResponse = function( self, tns ) - local len, len2, key, val, _ - local pos = 6 + local kvp_count, key, val, kvp_flags local kvps = {} - - while( true ) do - pos, len, len2 = bin.unpack("CIAII", #param_name, #param_name, param_name, #param_value, 0 ) - else - return bin.pack(">CIACIAI", #param_name, #param_name, param_name, #param_value, #param_value, param_value, 0 ) - end - end, - --- Converts the DATA packet to string -- -- @return string containing the packet @@ -586,11 +565,11 @@ Packet.Auth = { for k, v in ipairs( self.param_order ) do if ( v['def'] ) then - data = data .. self:paramToString( v['key'], v['def']) + data = data .. Marshaller.marshalKvp( v['key'], v['def'] ) elseif ( self.auth_options[ v['var'] ] ) then - data = data .. self:paramToString( v['key'], self.auth_options[ v['var'] ] ) + data = data .. Marshaller.marshalKvp( v['key'], self.auth_options[ v['var'] ] ) elseif ( self[ v['var'] ] ) then - data = data .. self:paramToString( v['key'], self[ v['var'] ] ) + data = data .. Marshaller.marshalKvp( v['key'], self[ v['var'] ] ) end end return data @@ -601,27 +580,20 @@ Packet.Auth = { -- @param tns Packet.TNS containing the TNS packet recieved from the server -- @return table containing the key pair values from the Auth packet parseResponse = function( self, tns ) - local pos = 6 - local len, name, val, _ - local data = tns.data - local response + local kvp_count, key, val, kvp_flags + local kvps = {} - repeat - pos, len, _ = bin.unpack("CI", data, pos) - if ( len == 0 ) then break end - pos, name = bin.unpack("A" .. len, data, pos) - pos, len, _ = bin.unpack("CI", data, pos) - if ( len > 0 ) then - pos, val = bin.unpack("A" .. len, data, pos) - pos = pos + 4 - else - pos = pos + 3 - end - response = response or {} - response[name] = val - until( name == "AUTH_SVR_RESPONSE" ) + local pos = 4 + pos, kvp_count = bin.unpack( "C", tns.data, pos ) + pos = 6 + + for kvp_itr=1, kvp_count do + pos, key, val, kvp_flags = Marshaller.unmarshalKvp( tns.data, pos ) + -- we don't actually do anything with the flags currently, but they're there + kvps[key] = val + end - return true, response + return true, kvps end, } @@ -1201,6 +1173,126 @@ Packet.QueryResponseAck = { } +Marshaller = { + --- Marshals a TNS key-value pair data structure + -- + -- @param key The key + -- @param value The value + -- @param flags The flags + -- @return A binary packed string representing the KVP structure + marshalKvp = function( key, value, flags ) + flags = flags or 0 + + local result = "" + result = result .. Marshaller.marshalKvpComponent( key ) + result = result .. Marshaller.marshalKvpComponent( value ) + result = result .. bin.pack( " 0 ) then + -- 64 bytes seems to be the maximum length before Oracle starts + -- chunking strings + local MAX_CHUNK_LENGTH = 64 + local split_into_chunks = ( #value > MAX_CHUNK_LENGTH ) + + if ( not( split_into_chunks ) ) then + -- It's pretty easy if we don't have to split up the string + result = result .. bin.pack( "p", value ) + else + -- Otherwise, it's a bit more involved: + -- First, write the multiple-chunk indicator + result = result .. bin.pack( "C", 0xFE ) + + -- Loop through the string, chunk by chunk + while ( #value > 0 ) do + -- Figure out how much we're writing in this chunk, the + -- remainder of the string, or the maximum, whichever is less + local write_length = MAX_CHUNK_LENGTH + if (#value < MAX_CHUNK_LENGTH) then + write_length = #value + end + + -- get a substring of what we're going to write... + local write_value = value:sub( 1, write_length ) + -- ...and remove that piece from the remaining string + value = value:sub( write_length + 1 ) + + result = result .. bin.pack( "p", write_value ) + end + + -- put a null byte at the end + result = result .. bin.pack( "C", 0 ) + end + end + + return result + end, + + --- Parses a key or value element from a TNS key-value pair data structure. + -- + -- @param data Packed string to parse + -- @param pos Position in the string at which the element begins + -- @return table containing the last position read and the value parsed + unmarshalKvpComponent = function( data, pos ) + local value_len, chunk_len + local value, chunk = "", "" + local has_multiple_chunks = false + + -- read the 32-bit total length of the value + pos, value_len = bin.unpack("