Microsoft might have taken a few years to get IIS right, but IIS 6.0 can be a solid and secure Web server. More than half the 2005 Fortune 1000 companies use IIS 6.0 to host their main Web sites, according to a study done by Port80 Software. And since its release in March 2003, IIS 6.0 has had only three vulnerability advisories versus Apache 2.0's 24 advisories, as reported by the Secunia IT security services company. This evidence suggests that Microsoft has delivered on the promise of better Web server security.

Nevertheless, being charged with hardening a Microsoft IIS server that will be connected to the Internet can be intimidating. It helps to start with Windows Server 2003 and IIS 6.0—they're secure out of the box. But in the real world, you must install and configure Web sites and applications. Attaching any Web server to the Internet invites a multitude of hackers and malicious scanning bots to scour your site looking for any opportunity to exploit a misconfiguration. With that in mind, I installed Windows Server 2003, hardened it against attack, and then downloaded and followed Microsoft's IIS 6.0 installation and deployment security guides. Here's a summary of the steps I took.

Install Windows 2003
The first step was to install Windows 2003 and fully patch it without connecting it to the Internet. I wanted the underlying Windows 2003 system to be a secure base system before I installed IIS. The very first step was to make sure all the hardware and BIOS had up-to-date firmware. I wouldn't want to be hacked due to an outdated SCSI driver.

I enforced booting from only the C drive to help prevent local attacks that use boot-around OSs such as Knoppix or NTFSDOS. Preventing unauthorized booting from the CD-ROM or floppy drive can help stop many password-resetting or -cracking programs and make copying the local SAM to removable media more challenging. I also disabled unused COM, LPT1, IDE, and USB ports in the BIOS, then protected the BIOS by using a complex password. I set up a router and firewall in front of the server computer and blocked all the router's TCP ports except for one RDP port to use for remote installation and configuration. When the site went live, I would also open TCP port 80.

Next, I installed Windows 2003, Standard Edition and used the default settings for a server in standalone-workgroup mode (a domain isn't needed for a standalone public-facing Internet server). I created two local drives, C and D, on the server's hard drive, which was RAID protected. Microsoft recommends installing the OS on one volume and the IIS Web site on another to prevent many directory-transversal attacks.

I renamed the Administrator and Guest accounts to some random-sounding user names and gave both complex passwords longer than 10 characters to decrease the chances of a brute-force password-guessing attack. Although an attacker can discover the Administrator account through SID enumeration, anonymous SID enumeration is turned off by default on systems that aren't domain controllers (DCs) in Windows 2003 and Windows XP.

I enabled Remote Desktop as the only way to remotely administer the server. I chose Remote Desktop because it's installed (although not enabled) by default, performs well, allows remote drive mapping so that I could install software, and has default RC4 encryption. I changed the related RDP port to something other than the default TCP port 3389 following the instructions in the Microsoft article "How to Change Terminal Server's Listening Port" (http://support.microsoft.com/?kbid=187623). The port was changed to slow down any hacker attempts to discover the Remote Desktop service and the brute-force logon-guessing attacks a discovered RDP port might invite.

I toyed with the idea of requiring IPsec to access the Remote Desktop connection but decided against this extra precaution until after I knew the server was stable. IPsec can prevent man-in-the-middle attacks against Remote Desktop, but I didn't want to troubleshoot Remote Desktop and IPsec at the same time during the initial configuration. The renamed Administrator and Guest accounts and their complex passwords would make remote password guessing unlikely to succeed against the server.

In addition, I made the following changes to the Remote Desktop setup by using Group Policy:

  • Specifically denied the anonymous user access to Remote Desktop
  • Set encryption to High
  • Disabled the use of remote control on Remote Assistance connections
  • Forced a user to close a session after disconnecting
  • Prevented a program from starting at logon so that the desktop was always shown immediately after a successful Remote Desktop connection
  • Disabled all mappings except clipboard

On the server's Remote Desktop settings, I enabled:

  • Delete temporary folders on exit
  • Use temporary folders per session
  • Active Desktop is disabled
  • Permission capability: full security
  • Restrict each user to 1 session: yes

I copied Windows 2003 Service Pack 1 (SP1) to the server, installed it, and rebooted the server. Then I ran Microsoft Baseline Security Analyzer (MBSA) to see whether anymore patches were needed, which was more difficult than it sounds. I needed to run it without accessing the Internet and exposing the possibly unpatched server to maliciousness. In order to do that, I downloaded MBSA's XML database, called mssecure.xml, to my local machine, then copied it to the server. I then ran MBSA, which revealed no missing patches or noted vulnerabilities. (I ran MBSA again after installing IIS because MBSA doesn't scan for IIS patches or vulnerabilities until IIS is installed and running.)

Note: A default installation of Windows 2003 SP1 is simpler than the steps I just described of patching the machine prior to attaching the server to the Internet. SP1 prevents all access to the server until after patching has been accomplished, so the risk of malicious exploit prior to all patches being applied is minimized. However, physically disconnecting all Internet access and patching manually is always more secure.

Next, I ran the Windows 2003 SP1 Security Configuration Wizard (SCW), choosing the server's role of a standalone IIS box and disabling all other unnecessary functions and services. Microsoft's cool new wizard did most of the work and guided me along, but it didn't disable enough services to satisfy me, so I had to disable a few services manually. Here's a recap of my SCW experience:

  1. On the Server Roles wizard screen, I chose only the Web Server role; I deselected Application Server, File Server, and Middle-tier Application Server (COM+/DTC).
  2. On the Client Features wizard screen, I deselected all features.
  3. On the Installed Options wizard screen, I selected: Backup (NT or 3rd Party), Backup to local hardware, Local application installation, Remote desktop administration, Remote SCW configuration and analysis, Remote Windows administration, Windows Firewall, and Windows user mode driver framework. I cleared the Time Synchronization and WPAD options.
  4. I disabled Upload Manager.
  5. I configured Windows Firewall to include the necessary RDP port.
  6. I configured the LAN Manager (LM), NTLM, and NTLMv2 authentication protocols to be disabled.
  7. I configured auditing to include all successes and failures.

I then manually disabled even more services in the Services console:

  • Application Experience Lookup Service
  • Automatic Updates
  • BITS
  • Computer Browser
  • DHCP Client
  • Error Reporting Service
  • Help and Support
  • Network Location Awareness
  • Print Spooler
  • Remote Registry
  • Secondary Logon
  • Server
  • Smartcard
  • TCP/IP NetBIOS Helper
  • Workstation
  • Windows Audio
  • Windows Time
  • Wireless Configuration

I opened the server's Local Computer Policy (gpedit.msc) and made the following changes/selections:

  1. Set minimum password size equal to 12.
  2. Enabled Password Complexity requirements.
  3. Set Account Lockout threshold to five bad passwords in 1 minute—results in a 1-minute lockout.
  4. Enabled Success/Failure auditing for all audit categories except Directory Service Access and Process Tracking.
  5. Removed Everyone group from Access this computer from the network user right.
  6. Under User Rights Assignment, removed Power Users and Backup Operators as members of the Access this computer from the network user right.
  7. Changed Unsigned Driver behavior from Warn to Don't Allow
  8. Enabled Message Text for Interactive Logon (just to defeat any brute-force logon-guessing tools). Didn't select the normal Unauthorized access not allowed setting.
  9. Disabled Logon caching (which should have no effect on the server).
  10. Enabled the Do not allow the anonymous access of SAM accounts and shares option.
  11. Enabled the Do not allow the storage of credentials or Passports for network authentication option.
  12. Enabled the Do not store Lan Man hash value on next password change option.
  13. Changed LM Authentication Level to NTLMv2—refuse LM and NTLM.
  14. Enabled the Clear virtual memory page file option.
  15. Removed Posix as an optional Windows subsystem.
  16. Enabled the Do not allow Windows Messenger to be run option.
  17. Enabled the Do not allow Windows DRM to be run option.
  18. Enabled the Do not allow Windows Movie Maker to be run option.
  19. Disabled Automatic Updates.
  20. Turned off Slow Link Detection for GPOs.
  21. Enabled WFP Scanning during startup.
  22. Restricted CD-ROM and floppy drive use to local logged-on users only.
  23. Denied Log On Locally right to IIS anonymous users.
  24. Enabled the Interactive Logon: Do not display user info option.
  25. Removed DFS$ and COMCFG from file shares that allow anonymous logon.
  26. Disabled Active Desktop.

I also disabled File and Printer Sharing in the Network Configuration dialog box and hardened the TCP stack with the registry edits recommended at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod109.asp. I then rebooted the server to make sure all the changes took effect and to make sure the server was responding normally. Now, it was time to install the Web server software.

Install and Configure IIS 6.0
IIS was installed with its normal defaults, which disable all Web extensions and Internet Server API (ISAPI) filters, among other things. Here are the other steps I took (most are recommended in the Microsoft IIS 6.0 resources listed in the Learning Path box):

  1. Changed the IP address of the Web site in the IIS Manager console to be a static private address instead of All Unassigned.
  2. Renamed the Default Web site in the IIS Manager console.
  3. On the renamed Web site, I required the host header to match the appropriate URL name. This action prevents many automated hacking tools and worms, which typically use only IP addresses. When users access Web sites, they almost always use the Web site name rather than the IP address (see http://www.iisanswers.com/hinders_rant.htm for more details).
  4. Set Execute Permissions of the Web site to None in the IIS Manager console.
  5. Disabled the IWAM and default IIS anonymous accounts in the User Manager tool.
  6. Created a new IIS anonymous account. This is an optional step but allowed me to better control what access the IIS anonymous user has to the Web server.
  7. Created an Anonymous Web Users group, added the new IIS anonymous user account to the group, and removed the original IIS anonymous account from it.
  8. Using Windows Explorer, I set Full Control permission to Deny on the Windows and System32 folders for the Anonymous Web Users group.
  9. Created a new IIS Web server directory on the E drive.
  10. In the IIS Manager console, changed the Web server directory from C:\Inetpub to the new directory on the E drive. Moving the Web site off the boot volume disables many directory transversal attacks.
  11. Gave the new Anonymous Web Users group read-only permission to the new Web site folder to prevent anonymous users from writing to or creating files on the Web site.
  12. Installed URLScan 2.5. URLScan loads as an ISAPI program. After it was successfully installed, I made the following changes:
  • Set UseAllowExtensions to 1.
  • Set MaxURL to 50.
  • Set MaxAllowContent Length to 1000.
  • Set MaxQueryString to 0.
  • Set AllowVerbs to GET and HEAD.
  • Added a period (.) to AllowExtension.

These URLScan settings—in particular, the short URL length and zero length for queries—make the site resistant to known and future buffer overflow attacks via the URL. Although these values aren't realistic for all e-commerce sites, any site will see significant improvements in security by rejecting overly long queries and URLs.

Note: IIS 6.0 is installed with much of URLScan's functionality built in, but I chose to install the standalone version of URLScan. It adds even more functionality and allows more configuration control versus having to accept IIS 6.0's hard-wired URLScan settings.

  • Added Everyone Deny permissions on Windows\Temporary Compressed Files.
  • Deleted all files in the iisadmpwd folder.
  • Deleted the \wutemp folder left over by patching.
  • Disabled Idle Timeout for Default App Pool.
  • In the IIS Manager console, disabled Session State on the new Web site.
  • Disabled Cache ISAPI extensions.
  • Changed Default App Pool identity from NetworkService to LocalService because the Web site doesn't need to access additional network resources.
  • Changed memory recycling pressure to 700MB for both settings.
  • Disabled rapid fail protection.
  • Changed Shutdown Time Limit from 90 seconds to 10 seconds.
  • I then stopped and restarted IIS to let new changes take effect. I reran MBSA to check for missing patches, and it reported no missing patches.

    Configure Log Files
    Originally, I considered using Microsoft's Network Monitor application or a third-party Intrusion Detection System (IDS) to document hacking activity, but I later decided to use server monitoring tools and log files that would typically be associated with a default install of IIS. Here's a summary of the logging setup steps:

    1. Made C:\IISLogfiles the central location for storing all log files.
    2. Enabled hourly IIS log files, enabled all fields, and configured log files to be saved in C:\IISLogfiles.
    3. Configured URLScan to save its log files to C:\IISLogfiles. Note that IIS 6.0's built-in http.sys security functionality creates a log file called HTTPERR (for more information, see "Error logging in HTTP API" at http://support.microsoft.com/?id=820729). I wasn't sure how to move this log file, so I just placed a shortcut to it in C:\IISLogfiles.
    4. Configured Windows Firewall to monitor all successful and dropped packets and save the log file to C:\IISLogfiles. I learned that the maximum Windows Firewall log size is 32MB (woefully inadequate) and that you must stop Windows Firewall to copy the log files. When I wanted to copy the firewall logs to an external computer for analysis, I used IPsec to protect the server.
    5. Created an IPsec policy between the Web server and the remote management computer that would be using RDP to connect.
    6. Enabled success and failure auditing for all audit events. Note that a high-volume Web site would probably experience a significant performance hit over time with all auditing enabled. After you've troubleshot any resulting error messages, you can enable the auditing categories recommended in the IIS 6.0 Resource Kit.

    Last, I emptied the Recycle Bin to make sure no old files were hanging around. The server was rebooted and the router and firewall opened to allow TCP port 80 traffic.

    Results?
    My heavily-trafficked Web site has been up for several months without a successful exploit. Does that mean that IIS 6.0 is unhackable? No, all software is hackable, and all Web servers have vulnerabilities, known and unknown. Often, Web servers are exploited because of faulty applications running on them. By minimizing the potential application problems, I minimized the overall vulnerability risk.

    What my Web site shows is that Windows 2003 and IIS 6.0 properly secured can provide a high level of security. Most of the hardening steps listed above are taken right from Microsoft's IIS hardening guides. You can follow them and have a secure Web site.

    Project Snapshot: How to
    PROBLEM: Set up a secure IIS 6.0 server.
    WHAT YOU NEED: Windows Server 2003, supporting network infrastructure, router, MBSA, URLScan 2.5
    DIFFICULTY: 3 out of 5
    PROJECT STEPS:
    1. Install Windows 2003 and fully patch it without connecting the server to the Internet.
    2. Install and configure IIS 6.0.
    3. Configure log files to record hacking activity.