In "Protect Your IIS Server with URLScan," July 2002, InstantDoc ID 25230, I offer an overview of Microsoft's URLScan tool and discuss how to download and test URLScan on a nonproduction server that contains a copy of your Web site. URLScan, which is bundled as part of the IIS Lockdown Tool (available for download at http://www.microsoft.com/downloads/release.asp?releaseid=33961), is an Internet Server API (ISAPI) filter that intercepts every request your Web server receives from the Internet and scans each request for anything unusual. The current version is URLScan 2.5, which you install over URLScan 2.0. (URLScan 2.5's new features let you change the log-file directory, log long URLs, and restrict the size of requests.) When you download URLScan 2.5, the new version adds entries to urlscan.ini but doesn't overwrite current settings.
Now let's delve into the process of customizing the tool for your environment. I take you step by step through urlscan.ini's sections (i.e., \[options\], \[AllowVerbs\], \[DenyVerbs\], \[AllowExtensions\], \[DenyExtensions\], \[DenyHeaders\], \[DenyUrlSequences\], and \[RequestLimits\]) and explain the tool's configuration options.
In addition to containing the majority of URLScan's options, the \[options\] section contains 16 settings that URLScan uses to interpret other urlscan.ini sections: UseAllowVerbs, UseAllowExtensions, NormalizeUrlBeforeScan, VerifyNormalization, AllowHighBitCharacters, AllowDotInPath, RemoveServerHeader, AlternateServerName, EnableLogging, PerProcessLogging, PerDayLogging, LogLongUrls, LoggingDirectory, AllowLateScanning, RejectResponseUrl, UseFastPathReject. You set most of these settings to 1 (true) or 0 (false).
\[AllowVerbs\] and \[DenyVerbs\]
Verbs (also called methods) are the commands that a browser uses at the beginning of a URL to communicate with a server. GET and HEAD are the most common verbs that Web browsers use for simple browsing. For example, when a browser requests contactus.html, it sends, in part, GET /articles/contactus.html. Browsers use other verbs, such as PUT, POST, and REPLY, to modify Web site content. Microsoft FrontPage Server Extensions, for example, use POST and OPTIONS (in addition to GET and HEAD) to maintain Web content.
To control which HTTP verbs URLScan permits or rejects in incoming requests, you can use urlscan.ini's UseAllowVerbs setting. This setting lets you use either the \[AllowVerbs\] section to specify a list of verbs to accept or the \[DenyVerbs\] section to specify a list of verbs to reject. To tell URLScan which section to use, you set UseAllowVerbs to 0 or 1. When you set UseAllowVerbs to 1, URLScan examines only \[AllowVerbs\] and ignores \[DenyVerbs\]—even when you list verbs under the latter section. In fact, if you set UseAllowVerbs to 1 and specify GET in both \[AllowVerbs\] and \[DenyVerbs\], users will be able to GET files from your Web site. When you set UseAllowVerbs to 0, URLScan looks at \[DenyVerbs\] and ignores \[AllowVerbs\]. Conceptually, IIS is most secure when you deny all verbs by default, then list exceptions. Therefore, I suggest you use the \[AllowVerbs\] section to list specific permitted verbs.
\[AllowExtensions\] and \[DenyExtensions\]
URLScan's \[AllowExtensions\] and \[DenyExtensions\] sections work similarly to \[Allow Verbs\] and \[Deny Verbs\] but control which file extensions incoming requests can access. You probably want users to be able to request common Web files (e.g., .html, .jpeg, Active Server Pages—.asp) but not executable files (e.g., .exe, .cmd, .bat), log files, or configuration files.
The urlscan_static.ini file contains a good sample list of file extensions that you can safely permit on most Web sites—and a long list of potentially dangerous extensions. After you determine which extensions you want users to be able to access through your Web site, set UseAllowExtensions to 1 and list the permitted extensions in the \[AllowExtensions\] section. That way, you block all other extensions. I recommend using \[DenyExtensions\] instead of \[AllowExtensions\] only if you must let users upload various types of files to your Web site and share the files with others. In that case, set UseAllowExtensions to 0, list the file extensions you consider to be dangerous in the \[DenyExtensions\] section, and notify your users that they can't use files of those types.
Be aware that \[DenyExtensions\] can break script mappings that you've configured in IIS. For example, if you deny .asp files in urlscan.ini, users can't access .asp pages even when you configure IIS to service .asp files under App Mappings in the Microsoft Management Console (MMC) Internet Information Server snap-in.
The \[DenyHeaders\] section lets you specify which client request headers that URLScan should permit or deny. For example, you can include Translate: as a denied header to prevent clients from requesting the source code of your Web site pages. (Note that not all settings offer both an \[Allow\] and \[Deny\] section.)
You'll find \[DenyHeaders\] especially valuable because you can use this section to disable WWW Distributed Authoring and Versioning (WebDAV). Because of WebDAV's vulnerabilities, you should disable it unless you use it to publish to your Web site. To prevent your servers from servicing WebDAV clients, include Translate:, If:, and Lock-Token: under \[DenyHeaders\] and include the verbs PROPFIND, PROPPATCH, MKCOL, DELETE, PUT, COPY, MOVE, LOCK, UNLOCK, OPTIONS, and SEARCH under \[DenyVerbs\], as Listing 1 shows. (Web Listing 1, http://www.windowswebsolutions.com, InstantDoc ID 25581, contains the entire sample urlscan.ini file configured to support FrontPage Server Extensions but to disable WebDAV.) Also, as Web Listing 2 shows, you should include Transfer-Encoding: as a denied header to disable chunked-encoding transfers. (By default, the URLScan-SRP variant makes transfer-encoding a denied header in urlscan.ini.)
The \[DenyUrlSequences\] section lets you scan a URL for certain dangerous character sequences that intruders often use to trick IIS into running malicious commands. The default sequences that Web Listing 3 shows catch character sequences known to be dangerous to both IIS and Windows 2000, but you might want to add other sequences that can pose a danger to applications to which you forward form input. For example, Web sites often incorporate form input into SQL queries without checking for malicious input that can fool the SQL server into running commands that an attacker selects.
You can also use \[DenyUrlSequences\] to block requests that attempt to access commands or executables you want to protect (e.g., cmd.exe, explorer.exe) or that use any other suspicious strings (e.g., winnt, system32). The Beyond-Security SecuriTeam article "Combining URLScan With FrontPage (HOWTO)" at http://www.securiteam.com/windowsntfocus/6Z0010U2UU.html includes a urlscan.ini file that blocks Nimba attacks that target IIS. Of course, be aware that blocking these requests can inadvertently block legitimate client requests. For example, if your Web site hosts a discussion forum about Windows NT, blocking the winnt string will prevent anyone from discussing files in that folder. \[DenyUrlSequences\] can also break Microsoft Outlook Web Access (OWA) sites. If you use OWA and want to implement URLScan, read the Microsoft articles "XCCC: IIS Lockdown and URLScan Configurations in an Exchange Environment" (http://support.microsoft.com/default.aspx?scid=kb;en-us;q309508) and "XADM: Known Issues and Fine Tuning When You Use the IIS Lockdown Wizard in an Exchange 2000 Environment" (http://support.microsoft.com/default.aspx?scid=kb;en-us;q309677).
The \[RequestLimits\] section, which is new in URLScan 2.5, lets you use three settings—MaxAllowedContentLength, MaxUrl, and MaxQueryString—to control the maximum length of three parts of the URL requests that clients send to IIS. This section is important for defeating buffer-overflow attacks that depend on sending large amounts of data in the request. URLScan 2.5 defaults are usually adequate; all values entered should be in bytes.
MaxAllowedContentLength. MaxAllowedContentLength controls the maximum permitted value for the content-length request header. For example, when you set MaxAllowedContentLength to 1024 bytes, URLScan rejects any request with a content length that exceeds 1024 bytes. When you POST or PUT a file to a Web server, content length specifies how long the attached data can be. Thus, MaxAllowedContentLength lets you limit how much data someone can PUT or POST to your server. When you install URLScan 2.5 automatically, it sets this value at about 3GB (about 3,000,000,000 bytes).
MaxUrl. MaxUrl specifies the maximum permitted length for the portion of a URL request that precedes the query string. (The query string is the part of the URL request that follows a question mark and contains the information, usually form input fields, that the browser sends to request a Web page.) If you install urlscan.dll manually and don't update urlscan.ini, the default is 260 bytes. However, when you install URLScan 2.5 automatically, it sets this value to 16KB (16,384 bytes).
MaxQueryString. MaxQueryString specifies the maximum length permitted for a query string. When you don't set a value for this setting, URLScan uses a default length of 4KB (4096 bytes). When you install URLScan 2.5 automatically, it sets the same value: 4KB (4096 bytes).
Setting limits on other request headers. You can also limit the byte size of other request headers. To do so, add a setting for the header by using "Max-" to prefix the header name. (See the URLScan 2.5 documentation at http://www.microsoft.com/technet/treeview/default.asp?url=/technet/security/tools/tools/urlscan.asp.) Note that if you specify 0 as the header length, you actually instruct URLScan to forgo checking the length. Unless you're familiar with request headers, I recommend that you wait to use these options until Microsoft suggests specific settings.
Filtering Questionable URLs
The \[options\] section contains additional settings that you can use to tell URLScan how to interpret other urlscan.ini sections: NormalizeUrlBeforeScan, VerifyNormalization, AllowHighBitCharacters, AllowDotInPath, RemoveServerHeader, and AlternateServerName. Again, you can set these settings to 1 (true) or 0 (false). NormalizeUrlBeforeScan and VerifyNormalization control the normalization of URLs. Normalization is the process of standardizing capitalization and converting encoded characters to regular characters—for example, changing %2e to a period (.), which \[DenyUrlSequences\] would then catch. AllowHighBitCharacters and AllowDotInPath help you filter URLs to prevent some common attacks. You can use RemoveServerHeader and AlternateServerName to keep IIS from identifying itself to the client.
NormalizeUrlBeforeScan. NormalizeUrlBeforeScan controls whether URLScan normalizes an incoming URL before or after scanning it. I recommend that you leave NormalizeUrlBeforeScan set to 1, which is the default. If you set NormalizeUrlBeforeScan to 0, URLScan might mistakenly approve malicious URLs that the normalization process reveals.
VerifyNormalization. If you set VerifyNormalization to 1, URLScan further normalizes URLs before the program proceeds. This setting is valuable because it can catch double-encoding techniques. For example, an attacker who hides an ampersand (&) in a URL might send %2526, which one normalization pass translates to %26. However, if you set VerifyNormalization to 1, URLScan recognizes that normalization isn't complete and resolves %26 to the ampersand character, which \[DenyUrlSequences\] then catches.
AllowHighBitCharacters. If you set AllowHighBitCharacters to 0 (the default is 1), URLScan rejects non-ASCII characters, which helps defend against attacks encoded with UTF-8 and Unicode. UTF-8 is an encoding scheme that lets you send Unicode in an ASCII stream, but UTF-8 is also another way to hide attacks in URLs. I recommend setting AllowHighBitCharacters to 0 unless you use Unicode to support another language.
AllowDotInPath. When you set AllowDotInPath to 0, URLScan rejects URLs that contain more than one period. (Be aware that some Microsoft documentation is contradictory, but this definition is accurate.) Although the \[DenyExtensions\] section is useful in preventing attacks that involve file extensions, sometimes URLScan can't determine the true extension of a requested file because URLScan runs before IIS parses the URL. By setting AllowDotInPath to 0, you prevent attackers from embedding a period earlier in the path to hide the true extension of the file. Note, however, that this setting also blocks access to any legitimate folders or files that have embedded periods; you might have to rename them.
RemoveServerHeader. Usually, when IIS responds to a client, a Web server identifies in the header the type of Web server software it uses. For example, an IIS server on Win2K would send "Server: Microsoft-IIS/5.0." Identifying the server and IIS version you use might let an attacker tailor an attack to that version. Setting RemoveServerHeader to 1 prevents IIS from identifying itself, but note that this setting breaks FrontPage Server Extensions.
AlternateServerName. You can take server protection a step further and use AlternateServerName to make attackers think your server is a different type of server. For example, setting RemoveServerHeader to 1 and AlternateServerName to GWS/2.0 might make an attacker think you run GWS instead of IIS. (Note that AlternateServerName works only when you set RemoveServerHeader to 1.)
URLScan's logging capability is useful for diagnosing problems and monitoring attacks. Each time IIS starts, URLScan logs a detailed description of its current configuration. Then, each time URLScan rejects a request, it logs the date, time, and raw URL—and records exactly why it rejected the URL. Five settings in the \[options\] section—EnableLogging, PerProcessLogging, PerDayLogging, LogLongUrls, and LoggingDirectory—control whether and how URLScan performs logging.
EnableLogging. EnableLogging controls whether URLScan logs activity. Because the URLScan log is invaluable, I recommend that you accept the default value of 1 to enable logging.
PerProcessLogging. I recommend leaving PerProcessLogging set to 0, which is the default, to avoid the need to check multiple logs. However, if you run applications at different levels of application protection and therefore in different processes (see http://www.microsoft.com/windows2000/en/server/iis/default.asp?url=/windows2000/en/server/iis/htm/core/iiwarndc.htm for information about IIS's application-protection options), you might want to set PerProcessLogging to 1 to instruct URLScan to create separate log files for each process. URLScan appends the process ID for each process to the corresponding log's filename.
PerDayLogging. I recommend that you set PerDayLogging to 1. URLScan then creates a new log each day, which helps keep your URLScan logs manageable. The format for log filenames is urlscan.mmddyy.log. I also recommend checking your logs at least once a week to note any attacks on your server.
LogLongUrls. When URLScan versions earlier than URLScan 2.5 logged rejected URL requests, the tool limited the line written to the log file to 1024 characters. Usually, that log-file size is long enough to accommodate the entire line, including the URL. However, this new URLScan setting lets you configure URLScan to log very long URLs. If you set LogLongUrls to 1, URLScan logs up to 128KB for each line.
LoggingDirectory. Earlier versions of URLScan created log files in the same folder in which urlscan.dll resided—usually in \%winroot%\system32\inetsrv\urlscan. With URLScan 2.5, you can send URLScan logs to a different folder by setting LoggingDirectory to the appropriate fully qualified path (e.g., C:\urlscanlogs).
Filter Priority Settings
The AllowLateScanning setting controls whether URLScan loads as a high-priority or low-priority filter. Usually, you should set AllowLateScanning to 0 so that URLScan runs as a high-priority filter to catch and reject problem URLs before they reach other ISAPI filters. When you set AllowLateScanning to 1 and run URLScan as a low-priority filter, URLScan examines URLs after any other ISAPI filters have modified them. If you use the low-priority setting, which is required for FrontPage extensions, also make sure that URLScan is low in the list of ISAPI filters when you install it.
Two settings control how URLScan rejects URLs and what information it returns to the user: RejectResponseUrl and UseFastPathReject.
RejectResponseUrl. RejectResponseUrl lets you specify the path (e.g., /errormsgs/badurl.html) to a file on the local server that contains the text for the error page that the server will display when URLScan rejects a request. URLScan creates three server variables that you can reference in your file:
- HTTP_URLSCAN_STATUS_HEADER provides the reason that URLScan rejected the request.
- HTTP_URLSCAN_ORIGINAL_VERB specifies the verb the client sent.
- HTTP_URLSCAN_ORIGINAL_URL specifies the original URL the client requested.
Web Listing 4 contains some sample .asp code, badurl.asp, that shows the server variables in action. The output in Figure 1 shows the text that users would see when they request a URL that includes a period.
In general, be careful how much information you reveal in error messages: You don't want to make life any easier for attackers. I recommend that you avoid showing the client HTTP_URLSCAN_STATUS_HEADER or HTTP_URLSCAN_ORIGINAL_VERB for security reasons, but you might want to return a generic error message such as Your request failed and supply a copy of HTTP_URLSCAN_ORIGINAL_URL along with support contact information. That way, legitimate users can give you enough information to find the rejected URL in URLScan's logs and analyze the problem. (Remember that URLScan reports the same information that it shows to users when you specify HTTP_URLSCAN_ORIGINAL_URL to the URLScan log.) Also, if you've configured IIS to log cs-uri-query (one of several fields you can direct IIS to include in its log), rejected URLs will show up in the IIS log as well.
RejectResponseUrl also provides a useful logging-only mode. When you set RejectResponseUrl to /~*, URLScan logs the requests you set it to reject but services them as if you hadn't installed the tool. (As Web Figure 2 shows, the URLScan log reminds you that it's running in logging-only mode.)
UseFastPathReject. You might want to report rejected URLs as quickly as possible with the least resource use. If you set UseFastPathReject to 1, URLScan ignores RejectResponseUrl and instead returns a standard 404 error message to the client. When you use UseFastPathReject, the IIS log doesn't log the original URL and other related information, but the URLScan log does.
You need to configure URLScan as strictly as possible but still make sure the tool accepts the verbs, headers, and file extensions that your Web site requires. To get maximum protection from URLScan, you might need to modify certain areas of your Web site. For example, you might need to change the paths in your Web site or the format of your URLs so that URLScan won't reject legitimate requests. Avoid using periods in folder names or filenames. Also avoid using colons (:), ampersands, percent signs (%), or backslashes (\) in URLs.
In addition, several Microsoft and non-Microsoft add-ons require specific URLScan configurations. To learn about those required configurations, see the Web-exclusive sidebar "Configuring URLScan to Support Specific Products," InstantDoc ID 25614.
URLScan offers defense in depth because it examines any packet bound for IIS against a set of rules that you can define in urlscan.ini. URLScan's approach of preventing unusual requests from being processed offers protection against future exploits.