Securing Windows servers is a relatively simple task these days, compared with the effort it required just a few years ago. Microsoft has made notable progress in delivering Windows servers that are reasonably secure as long as you keep the system patched and use a firewall. However, many other companies haven't made the effort to deliver applications in secure default configurations or even offer documentation about how to secure that software. I often see third-party Web, FTP, mail, or messaging server applications that put otherwise secure environments at risk because of poor default configurations.

The most common mistake is that many third-party services run under the context of the built-in System account, although the services rarely need this elevated level of access. If the application were ever compromised, an attacker might use the full system access to wreak havoc. Other common problems are that applications install with lax NTFS permissions or don't make enough effort to protect sensitive data. For example, many third-party applications store their configuration data or even account passwords in the registry or local configuration file but don't adjust permissions to prevent regular users from reading these files. If the software doesn't use strong encryption or other methods to protect sensitive data, that data could end up in the wrong hands.

You might try asking the vendor whether it has any specific hardening recommendations for securing its products. Unfortunately, many companies don't offer such recommendations.We as administrators often must take it upon ourselves to secure these third-party service applications. Doing so is easier than you might think, if you follow the steps I outline.

Keep in mind that these steps won't work for every application, because you might be using the product in a manner that wasn't fully tested by the developer. Furthermore, the amount of tweaking required to get a particular application to work might not be reasonable. Nevertheless, many applications run fine with just a few modifications, and the resulting security benefits can make your work worthwhile. These benefits include a greatly reduced attack surface that significantly limits how an attacker might be able to exploit an application.

Installing the Software
The first step is to install the software as an administrator, using the default configuration. Installing the software as an administrator is important because many applications create configuration files or registry entries the first time they start—a process that's more easily accomplished with the elevated privileges of the System or Administrator account.

When you install the application, carefully consider where you place the application's files within the Program Files directory on your computer. Most applications will have a variety of file types associated with it, such as program executables, support libraries, Help content, configuration files, log files, and user data files. Some applications dump all these files in a single directory, whereas others let you customize the location of each file type. If your application lets you customize settings, take the time to consider the effect of file locations and place each file type in its own directory. For example, log files often contain sensitive information that might be useful to an attacker, so I prefer to put them all in a central location and use scripts to archive them to another system. Sometimes it's best to place user-accessible files (but not the application itself) on an isolated drive partition. Usually, I perform such isolation for publicly accessible servers (e.g., Web servers, FTP servers) that expose a portion of the file system in the application. This isolation prevents hackers from exploiting any future vulnerabilities that might let them access files outside the application's boundaries, such as being able to access system or other sensitive files.

I recently secured a third-party mail server for a client. I installed the software in the server's Program Files directory, but because the software provided Web mail access to mail files, I placed the mailbox files on a separate partition, which also made the files easier to manage. While configuring the program, I noticed that it gave me the option to specify the location of the log files, so I placed them in a central location with the client's other system log files, which makes it easier for my client to manage and archive the logs all in one place.

When you install a software application, you also need to consider which features you should install. If you don't have an immediate need for a particular feature, but you think you might require it in the future, avoid installing it now. You can always install it later when you actually need it. On a production server, you should also avoid installing unnecessary sample or documentation files.

Post-Installation Tasks
Immediately after installing an application, explore the files installed in its Program Files directory. Often, you'll see extra files that aren't necessary for the program's operation: readme files, .doc files, add-ons, installation logs, and temp files. Clutter is an enemy of security, so be sure to delete or relocate as many of these files as you can.

Finally, set application passwords. Many server applications require some kind of user or administrator logon. Often, these applications install accounts with default or blank passwords that can put a server at risk. Set a strong password. If the program lets you customize the username, avoid common and predictable names such as administrator, postmaster, root, and admin. Finally, be sure to remove all default user and demo accounts in the application.

Least Privilege
The most important way to secure any application is to grant it only the privileges necessary to perform its role. You should limit file-system access and registry access, and deny access to certain system rights and privileges, such as the ability to log on over the network. Administrators have full access to any Windows system, so it's essential to configure your service applications to run with non-administrator accounts.

Unfortunately, many software developers don't consider the effect of running their code as a non-administrative user. Many service applications install using the default System account and the developers might not have fully tested running the application with lower privileges. Often, if you configure a service to run under the context of a regular user account, that service will fail to start on the first attempt. But after performing a little research and application monitoring, you'll find that most applications can run just fine without full administrator access.

Software needs certain resources to run. A program might call upon program files, shared Windows resources, registry keys, and system privileges to accomplish its task. If access to any of these items is denied, the application might return an error or simply stop running. The key to preparing an application for least privilege is to figure out what the application needs to access, then create a user account for the service to use (aka a service account) that has those specific rights and privileges—and nothing more.

To create this service account, create a user account on the server or in the domain and give it a strong password. Because this is a password you'll rarely need to type, go with a strong phrase of 30 characters or more. Select the User cannot change password and Password never expires check boxes. Using a password that never expires violates most security policies, but you don't want to take the risk of service downtime occurring because of an expired password. This is one case in which you'll have to manually enforce regular password changes.

Finally, on the Terminal Services Profile tab, select the Deny this user permissions to log on to any Terminal Server check box. If you're running multiple services on the server and you want to create an account for each one, you might also want to create a services group that you can later use to simplify assigning rights and permissions, such as denying all service accounts access to certain parts of the file system.

File Access
The main resource that every application needs is access to the file system, to be able to read and execute files in the application's own program directory. Sometimes the application needs to create or modify its own files. Many programs also place configuration files in shared locations such as the Windows directory. Some applications like to hide certain license-related files in obscure locations in the file system in an attempt to prevent users from bypassing licensing restrictions. You must identify all these files to ensure that the service account has access to what it needs.

To identify the files that the service account requires, you'll need to configure Windows to audit all file accesses. Because you'll be making significant auditing-policy changes that are difficult to reverse, this task is best done on a test system or a virtual machine (VM).

To audit all file access, open Windows Explorer and select the security properties for the first hard disk drive. Click Advanced and select the Auditing tab. Click Add and type in Everyone as the user. Click OK and select the Full Control check boxes on both the successful and failed sides. Doing so will select all check boxes, as you can see in Figure 1. Click OK to save the entry, then select the Replace auditing entries on all objects with entries shown here that apply to child objects check box. Click OK and let the system apply the security setting to the full drive. If necessary, repeat the process on any other drive partitions on the system.

With the audit settings in place, you'll need to configure the security policy to log these audits. From Administrative Tools, open the Microsoft Management Console (MMC) Local Security Policy snap-in. Expand Local Policies and select the Audit Policy folder. Configure the Audit object access and Audit privilege use policies to audit both successful and failed events. Note that log entries resulting from activating these settings will quickly fill up your event logs, so you might need to set them back to the original values after you finish testing.

Registry Access
Most programs make some use of the registry, not only to store configuration information but also to look up systemwide configuration settings stored there. To audit this access, open regedit.exe and right-click the HKEY_LOCAL_MACHINE registry hive. Select Permissions and add an audit entry for Everyone, exactly as you did with the file system.

With these audit settings in place, clear out all your event logs, start the application or service, and run through as many tasks as possible. When you're finished, stop the service or application.

Building Access Lists
Windows will create an event-log entry every time a program accesses a file or registry key that is being audited, which in our case is the entire file system and the entire HKEY_LOCAL_MACHINE registry hive. Because using the Windows registry in this way could result in thousands of event-log entries, I prefer to use Microsoft's free Log Parser tool (see http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&DisplayLang=en) to extract the necessary information .

Use the following command to generate a list of files and registry keys that the application uses:

logparser "SELECT DISTINCT
  EXTRACT_TOKEN(strings,1,'|')
  AS Type, EXTRACT_TOKEN
  (strings,2,'|') AS Name USING
  EXTRACT_TOKEN(strings,7,'|')
  AS Executable FROM Security
  WHERE EventID=560 AND
  Executable LIKE '%<Your
  Application>%' ORDER BY
  Type, Name" -i:evt

where YourApplication is your application or path name.

With this query, Log Parser will produce a list of all file and registry accesses. You can use this list to adjust permissions for each of the files or registry keys. For example, for shared items such as files in the Windows directory, grant the service account the necessary rights, leaving any existing permissions in place. For private files in the program's directory, remove all existing permissions, including inherited permissions, allow administrators Full Control, and give the service account you created at least Read and Execute access, although that account will often need to create or modify files, depending on the application.

Rather than using Windows Explorer to set each permission individually, use a tool such as CACLS or FILEACL (see http://www.microsoft.com/downloads/details.aspx?FamilyID=723f64ea-34f0-4e6d-9a72-004 d35de4e64&DisplayLang=en) to script each change. Doing so will save you from needing to redo this entire process if you later set up another server or must reinstall this one.

As you review the list, keep an eye out for undocumented registry settings that you might be able to use for further hardening of the product. You might, for example, notice settings to disable certain features that you aren't using, which can further reduce the application's attack surface. A program might also have an undocumented setting that determines where it stores its log files.

User Rights
Some applications require special Windows user rights to operate. A Web or FTP server, for example, might need to impersonate other user accounts as users log on. To assign user rights, open the MMC Local Security Policy snap-in (or domain policy if it's a domain account) and select User Rights Assignment under Local Policies.

At a minimum, the service account you created will need the Log on as a service right. It might also need other rights such as Generate security audits, Log on as a batch job, or Replace a process level token. Note that, by default, Windows assigns some rights to the built-in Service group, which includes any user that logs on as a service. By logging on as a service, the user account you created will automatically become a part of that group.

To make it more difficult for others to exploit your service account, you might want to specifically deny the account certain rights, such as Deny access to this computer from the network, Deny log on as a batch job, Deny log on locally, and Deny log on through Terminal Services.

The Final Run
After you configure permissions and rights, try running the application under the context of the service account you created. Stop the service and set the service properties to log on with the new user account. Start the service and wait for any errors. If the service doesn't start successfully, check the system's or application's event log for specific errors. You might need to repeat the Log Parser queries I mentioned earlier to track down the specific problem. Most applications will start fine with minor tweaking of permissions in file and registry access, unless the applications make extensive use of administrator privileges.

If you still have trouble getting the service to start, you might want to try troubleshooting the problem by using some of the tools that you see in Table 1. When you get everything working, take a few minutes to write up what changes were necessary to get the service-working. Send your list to the software publisher or post it in any relevant forums so that others might benefit.

Ultimately, some applications refuse to run with anything less than administrator privileges. If that's the case, make sure to inform the software developer of the security risks and ask the company to change its execution requirements. With enough effort and education, perhaps we can all make a difference.