Routing and Remote Access Blog

VPN articles - straight from Windows development team

How to secure the server running RRAS role after doing upgrade or fresh install of Windows server 2008

How to secure the server running RRAS role after doing upgrade or fresh install of Windows server 2008

  • Comments 2
  • Likes

Hello,

 

As you know in Windows server 2008 (WS08) we have removed “Basic Firewall” functionality in RRAS which exist in Windows Server 2003 (WS03). 

 

This leads to following security implications which you should be carefully consider when configuring RRAS on WS08:

 

1)      If you were running WS03 enabled for RRAS as a VPN server with inbound/outbound filters and you upgrade to WS08, after update:

a.       You don’t need to do anything extra in terms of RRAS inbound/outbound filter configuration (i.e. all your RRAS inbound/outbound filter settings will get migrated from WS03 to WS08)

b.      WS08 will be turned on with Windows firewall. Now you have two packet filtering engines that are enabled (RRAS inbound/outbound filters AND Windows Firewall). Read [1] to understand the differences between the two and in which scenario to use which one.

 

2)      If you were running WS03 enabled for RRAS as a NAT router with “Basic Firewall” and you upgrade to WS08, after upgrade:

a.       Manually turn on Windows Firewall (Note: This happens because in WS03, Windows firewall will be turned off as RRAS was enabled with Basic Firewall; and Basic firewall is removed in WS08). Open Windows Firewall clicking on Start->Control Panel->Windows Firewall->Change Settings. Click on “On”

 

b.      Validate all the “exemptions” that are added inside Windows firewall.  As Windows firewall settings are global to the machine, all the ports that are opened as exemptions will be visible from pubic as well as private NICs of RRAS. 

 

In case of RRAS, following ports are opened to allow traffic from remote access users using different forms of VPN tunnels:

                TCP Port 1723: PPTP control traffic

                IP Protocol 47: PPTP data (GRE) traffic

                UDP Port 1701: L2TP traffic

                UDP Port 500 and 4500: L2TP/IPSec IKE traffic

IP Protocol 50: L2TP/IPSec data (ESP) traffic

                TCP Port 443: SSTP control and data traffic

 

Additionally, following ports are opened to allow remote manageability of VPN servers

                TCP Port 135: RPC Endpoint mapper service

                Dynamic RPC port: Dynamic ports opened by RPC service  for DCOM traffic

 

c.       If you will like to block ports from the public side (let us say the remote manageability ports), you can do so in “Windows Firewall with advanced security”. 

1)      Click on Start->Administrative Tools->Windows Firewall with Advanced security.

2)      Go under Inbound rules. Search for the two rules with names starting with “Routing and remote access remote management”. View the properties of the rules.

3)      Add two new rules by clicking on “New Rule” under Action tab. Give all the properties of this rule same as  “Routing and remote access management” rules,  but add it with specific “Local Address” equal to public NIC IP address AND action as “Block the connections” (i.e. block remote manageability to RRAS public NIC’s address).

 

OR alternate way is to disable both the rules with names starting “Routing and remote access remote management” and create new rules with properties similar to the disabled rules and in addition set the local address to the IP address of the private NIC and set remote address to specific subnet from which to accept remote manageability requests.

4)      Repeat steps 2 and 3 for Outbound rules

 

3)      If you do a fresh install of WS08, install RRAS role via server manager and configures the RRAS role.

a.       If you have configured RRAS wizard with inbound/outbound filters that drops all traffic except VPN traffic -  you don’t need to do anything extra (because RRAS opens only VPN traffic on the public interface which anyways is required as a VPN server role)

b.      If you have configured RRAS without inbound/outbound filters (let us say enabled for NAT scenario and inbound/outbound filters don’t co-exist with NAT), you need to follow steps 2b) and 2c) as given above.

 

For any queries, feel free to write to us at the email address given above

 

References:

[1] RRAS Server in Windows server 2008: Which one to use - Windows firewall or RRAS filters

[2] Ports affecting the VPN connectivity

[3] RRAS static packet filters - do's and don'ts

[4] Which ports to unblock for VPN traffic to pass-through

 

Cheers,

Samir Jain
Senior Program Manager
Windows Enterprise Networking

 

[This posting is provided "AS IS" with no warranties, and confers no rights.]

 

Comments
  • Maybe this post should not post in here, but I don't know how to indicate it to correct people.

    Bug in rasapi32.dll

    In dllmain@rasapi32.dll (DLL_PROCESS_ATTACH), it opens a global mutex  which names "RasPbFile" and closes it in dllmain(DLL_PROCESS_DETACH).

    The dll use the mutex to sync the read/write operations of the phone book file.  In function ReadPhonebookFileEx and WritePhonebookFile.

    In both these two functions, the code look like:

    if(WaitforSingleObject(g_hmutexPb,INFINITE)==0)

    {

       Read/Write Phone book file;

       ReleaseMutex(hmutexPb);

       return;

    }

    else

    {

       return;

    }

    But it's wrong, in MSDN, I found the following description:

    If a thread terminates without releasing its ownership of a mutex object, the mutex object is considered to be abandoned. A waiting thread can acquire ownership of an abandoned mutex object, but the wait function will return WAIT_ABANDONED to indicate that the mutex object is abandoned.

    So if one application use rasapi32.dll and terminated for some reason, the mutex maybe abandoned, which would cause the following Read/WritePhonebookFile (in another process) acquire the mutex, and DONOT release. So deadlock...

    The correct code maybe:

    DWORD WaitRet = WaitforSingleObject(g_hmutexPb,INFINITE);

    if(WaitRet==0 || WaitRet == WAIT_ABANDONED)

    {

       Read/Write Phone book file;

       ReleaseMutex(hmutexPb);

       return;

    }

    else

    {

       return;

    }

    I don't know if the bug exist in all windows platform. I only check it in windows 2k8 x64 enterprise edition. But I think it should exist in all windows platform.

    Another question is, from MSDN, the stuct RASDIAL_PARAMS

    defines as following:

    typedef struct _RASDIALPARAMS {

     DWORD     dwSize;

     TCHAR     szEntryName[RAS_MaxEntryName + 1];

     TCHAR     szPhoneNumber[RAS_MaxPhoneNumber + 1];

     TCHAR     szCallbackNumber[RAS_MaxCallbackNumber + 1];

     TCHAR     szUserName[UNLEN + 1];

     TCHAR     szPassword[PWLEN + 1];

     TCHAR     szDomain[DNLEN + 1] ;

    #if (WINVER >= 0x401)

     DWORD     dwSubEntry;

     ULONG_PTR dwCallbackId;

    #endif

    } RASDIALPARAMS;

    the dwCallbackId is ULONG_PTR which means in x64 platform, it's uint64.

    but in RasDialFunc2:

    DWORD CALLBACK RasDialFunc2(

     [in]                 DWORD dwCallbackId,

     [in]                 DWORD dwSubEntry,

     [in]                 HRASCONN hrasconn,

     [in]                 UINT unMsg,

     [in]                 RASCONNSTATE rascs,

     [in]                 DWORD dwError,

     [in]                 DWORD dwExtendedError

    );

    the dwCallbaackId is DWORD which means it's always uint32.

    Why?

  • The attack code looks like:

    #include "stdafx.h"

    #include "windows.h"

    HANDLE gMutex = NULL;

    DWORD WINAPI Worker(void*)

    {

       // deadlock

       DWORD Wait = WaitForSingleObject(gMutex,INFINITE);

       return Wait;

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

       gMutex = OpenMutex(SYNCHRONIZE,FALSE,"RasPbFile");

       if(argc == 2 && stricmp(argv[1],"ABANDONED")==0)

       {

           DWORD Wait = WaitForSingleObject(gMutex,INFINITE);

           CloseHandle(gMutex);

           exit(0); // mutex to be ABANDONED state

       }

       DWORD Wait = WaitForSingleObject(gMutex,INFINITE);

       if(Wait == 0) ReleaseMutex(gMutex); // if Mutex state is ABANDONED, the Wait must be WAIT_ABANDONED so that skip the ReleaseMutex

       HANDLE Thread = CreateThread(NULL,0,Worker,NULL,0,NULL);

       DWORD Wait2 = WaitForSingleObject(Thread,INFINITE);

       CloseHandle(gMutex);

       return 0;

    }

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment