Hack 57 Metabase Hacks

figs/expert.gif figs/hack57.gif

Here are 10 things you might want to change with IIS, but you can do them only by editing the metabase.

These are a few of my favorite IIS metabase hacks. You can find lots more information?too much, perhaps?in the IIS SDK's IIS Metabase Properties Reference on MSDN (http://msdn.microsoft.com/library/en-us/iisref/htm/reference.asp). Most of the information there is pretty dry stuff?lists of different settings that provide little insight into what might be useful to tweak?which is why I want to start you off with a few interesting hacks to inspire you. Still, it is a good idea to get familiar with how to read the Reference, because it details the allowable values for each property in the metabase.

Except where stated otherwise, all of the following hacks work on both IIS 5 and IIS 6, though the effect in some cases might differ depending on the rest of your IIS configuration; I try to make note of such differences when appropriate. Also, most of these properties require IIS to be restarted before they take effect?something that's usually a good idea anyway whenever you edit the metabase manually. Even on IIS 6, which lets you edit the metabase while IIS services are running, it's often a good idea to use the iisreset command to stop and start IIS after making metabase changes and see if there is any effect.

A Warning Before Hacking the Metabase

Before you start hacking the metabase, remember that editing the metabase (like editing the Registry) shouldn't be done lightly; the preferred method is to configure IIS using the Internet Services Manager GUI tool. Unfortunately, a number of useful metabase settings are inaccessible from the GUI and you have to dig right into the metabase to change them.

Also, before you edit the metabase make sure you back it up. That way, if you make a mistake and break IIS, you can restore the metabase from backup and get IIS working again. We looked at ways you can back up the metabase [Hack #54] earlier in this chapter, but it's also a good idea to make a copy of the metabase and edit the copy instead of editing the metabase itself. Then, when you've made your changes, you can stop IIS, rename metabase.bin to metabase.old, rename your copy of the metabase from whatever you called it to metabase.bin, and restart IIS. Should something go wrong, your original metabase is still there in the form of metabase.old and can be used to restore IIS to the configuration it had previously. That may sound like overkill, but you can never be too careful when it comes to manually editing critical configuration files. You should at least follow that procedure with IIS 5 (Windows 2000). With IIS 6 (Windows Server 2003), you can probably get by without following this approach, because the history feature saves a copy of the metabase every time you make a configuration change to it. You decide, though. Like most things in IT, it's a tradeoff, and in this case, the tradeoff is between convenience and safety. Making backups of backups is not convenient, but it might help prevent you from burning your fingers.

Also remember that MetaEdit (the downloadable tool for editing the IIS 5 metabase) doesn't check your modifications to ensure that the values you entered are within the allowable range for the properties you edit. Editing the IIS 6 metabase using Notepad or some other text editor is even more dangerous, because you could even assign a string value to a metabase property that should be numeric. So, before you change any metabase property manually, check the Reference to see which range of values is allowed.


Sometimes, IIS cracks under the weight of too many client requests, even though it still has lots of memory and CPU cycles to work with. Typically, clients start getting "Server too Busy" errors and have to click Refresh several times before they are able to see any content. At the server end, this might happen on only one IP address, and any others might behave as they should. With a packet-sniffing tool such as the Microsoft Systems Management Server's Network Monitor, you'll see TCP connections resetting almost as soon as they are established. The problem is that the application layer of the TCP/IP stack has run out of resources. To increase the resources available for this layer, you can edit two metabase properties: ServerListenBacklog and MaxEndPointConnections (we will discuss the latter in the next section).

The ServerListenBacklog property determines the maximum number of outstanding TCP socket connections that can be queued. By default, this property is set in the metabase schema and depends on how the Performance Tuning setting is configured on the Performance tab of your web server's properties sheet in the GUI. Specifically, ServerListenBacklog has defaults of 5, 40, or 100, depending on whether you tune the GUI to expect fewer than 10,000 hits per day, less than 100,000 hits per day, or more than 100,000 hits per day. You can override the schema defaults for this property by adding a ServerListenBacklog key at the web site's level (/LM/W3SVC) or at the level of an individual web site, such as the Default Web Site (/LM/W3SVC/1); assign the ServerListenBacklog key any value from 5 to 1000 (on IIS 5) or 500 (on IIS 6). More pending connections are queued as you increase the value for this key, but IIS will consume more memory resources. Experiment to find the best performance for your hardware.


Another property you can tweak to improve performance under heavy load is MaxEndPointConnections, which indicates the maximum number of TCP sockets in a LISTENING state that can be allowed for a single IP address, network interface, or TCP port. By default, this property has the value 100 on IIS 5 and is also set in the schema, but you can add a key to set it at the /LM/W3SCV level or the /LM/W3SVC/n level, where n is the site ID of the web site that contains the application. To get better performance under heavy load, try increasing this setting to 500 or even higher and evaluate the result from the client standpoint. On IIS 5, MaxEndPointConnections works in conjunction with ServerListenBacklog and IIS uses the property with the lower value by default. On IIS 6, however, MaxEndPointConnections is set to 4294967295 in the schema, which means unlimited connections and is usually best left as is.


Thread gating is a feature of IIS that is turned off by default, but if you turn it on, IIS dynamically adjusts the number of concurrent threads, depending on the load. If threads become blocked (for example, when an ASP application on IIS has to wait for a back-end SQL database to respond), then IIS starts more threads to handle client requests. If processor usage hits the wall, IIS begins decommissioning threads to reduce the amount of context switching going on. The lower- and upper-level CPU usages that start or kill threads are determined by two other metabase properties: AspThreadGateLoadLow and AspThreadGateLoadHigh. By default, these properties have values of 50 and 80 (percent), respectively, but you can change them to see if it improves performance.

I've sometimes found that changing AspThreadGateEnabled from off (0) to on (1) can improve performance somewhat for web servers that host mainly static content. For servers that host ASP applications, use the Performance console first to check if ASP requests are becoming excessively queued. If so, try changing AspThreadGateEnabled to 1 and use Performance again to see if things improve.

This key is already present in the metabase at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level by creating the appropriate key. Note that this particular metabase property applies only to IIS 5, not IIS 6.


The AspProcessorThreadMax property determines the maximum number of worker threads IIS allows for handling ASP requests. The default value is 25 (threads per processor), and if you multiply the number of processors on your machine by the value of AspProcessorThreadMax, the product represents the maximum number of threads that can service a single ASP application?regardless of how you have tweaked the previously described AspThreadGateLoadHigh property. In some cases, you might want to try increasing this value?for example, when ASP requests are being blocked by slow response from a back-end database. In other cases, decreasing it to 15 or even 5 might improve performance by better utilizing available processor resources, especially under relatively light loads. Basically, just play with it and see what happens. This property is defined at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level.


The AspAllowSessionState property enables session state persistence for ASP applications and is set to 1 (on) by default. One way you can often improve ASP performance is to change this property to 0 (off) and then recode your applications to explicitly override session state persistence for pages that use session objects. Simply add the following statement to the top of each ASP page as needed:

<% @EnableSessionState=False %>

This property is defined at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level.


Big improvements in ASP performance can often be achieved by turning ASP buffering on using the AspBufferingOn property. This is because ASP buffering lets IIS collect the output of an ASP application in a buffer before flushing it to the client. Fortunately, this property is set to 1 (on) in IIS, provided you're working with a clean installation of Windows 2000 or Windows Server 2003. If you previously upgraded your web server from Windows NT 4.0, however, this property is set to 0 (off) and should generally be changed to 1, at least on all your production servers. However, while turning this property on increases ASP response times overall, from a user perspective it might actually seem to make sites less responsive. This is because instead of feeding the output of the ASP page to the user slowly, bit by bit, the entire output has to be generated and cached before any of it can be returned to the user. So, you'll have to play with this and see what how it feels from a client perspective, but in most cases it's best left turned on. You can also recode your ASP applications to make more use of the Response.Flush method to improve the performance from the user's point of view. This property is defined at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level.


Ever tried to access a page that wouldn't load, so you kept refreshing impatiently? On the older IIS 4 platform, this had the unpleasant result of filling up the ASP request queue with multiple requests from the same user for the same page, which was quite annoying. Fortunately, in IIS 5 the AspQueueConnectionTestTime metabase property was added to foil this kind of unintentional denial-of-service attack on your web server. The default value for this key is 3 (seconds), but you can tweak it depending on how your ASP application is designed. For example, if you have an application in which the user usually just clicks through a number of pages without needing to fill in or read anything, you could add this key to the /LM/W3SVC/n level for that site and lower its value to 2 or even 1. That way, IIS will check more frequently to make sure the client is still connected before responding to another connection request from the same client. This property is defined at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level.


The AspScriptFileCacheSize property determines how many precompiled script files or templates are cached in memory by IIS, in case they need to be reused. The default value for this setting is 250 (in IIS 5) or 500 (in IIS 6), but this can be increased to 1000 or more if needed. You can also set it to -1 (on IIS 5) or 4294967295 (on IIS 6) to allow unlimited caching of scripts. Unlimited caching is probably not a good idea unless you have unlimited RAM on your motherboard, but you definitely might consider increasing this setting to 1000 or higher if your server is running applications that have many different ASP pages. This property is defined at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level.


The CacheISAPI property determines whether IIS caches ISAPI extensions (such as asp.dll) in memory or unloads them whenever they're no longer used. This is set to 1 (on) and should be left that way on production servers, unless you want your applications to run like molasses. However, if you need to debug a custom ISAPI extension you've written, set CacheISAPI to 0 (off); otherwise, you'll end up testing previous versions of your extension instead of testing the current one. This property is defined at the /LM/W3SCV level, but you can also set it at the /LM/W3SVC/n level.

ID 36907

I'll end this list of hacks with something a little bit different. Until now, we've looked only at metabase properties for IIS proper. However, some other Microsoft products also use IIS; one of the most notable is Exchange 2000 Server. Every metabase property is uniquely identified by an internal ID number. For example, the CacheISAPI property has ID number 6034, which can easily be seen using MetaEdit (see Figure 6-5).

Figure 6-5. Viewing the CacheISAPI property in MetaEdit

It's a little-known fact that these ID numbers are grouped into different ranges that depend on the IIS function to which they apply (IIS, ASP, or FrontPage) or the Microsoft server product to which they belong (such as Exchange Server or Application Center). Table 6-1 details the association between metabase Ids and their associated functions or products.

Table 6-1. Metabase property ID ranges

ID range





ASP (subset)


FrontPage Server Extensions


Exchange Server: SMTP


Exchange Server: POP3


Exchange Server: NNTP


Exchange Server: IMAP4




Application Center

Metabase property 36907 falls within the range of Exchange's SMTP Service and can be used to change the default SMTP banner with which Exchange responds to incoming client connections. Changing the property's banner from its default?ESMTP MAIL Service, Version: 5.0.2195.1600 (or something similar)?is a useful security measure, because it hides Exchange from unauthorized Telnet connection attempts issued by attackers who are trying to footprint your system.

To change the banner for property 36907, open MetaEdit and find /LM/Smtpsvc/n, where n is the number of the SMTP virtual server used by Exchange. Then, select EditNewString from the menu to open the Edit Metabase Data dialog box (shown in Figure 6-6).

Figure 6-6. Adding a new property to the metabase based on its internal ID number

Since the Id drop-down box lists only standard IIS metabase properties, you have to add this property using its ID number instead. Leave the list box set to (Other) and type 36907 in the box beside it. Then, in the Data text box, type the banner you want the SMTP Service to display to clients?perhaps something like "Stop trying to footprint my server!" Finally, stop and restart the SMTP Service on your machine. Now, when a Telnet client tries to connect on port 25, he'll get the message you specified. Of course, you might not want to use that particular message; it might only annoy the attacker and make her even more determined to crack your system!

By the way, you can do the same thing with your POP3 connection and disconnection strings (IDs 41661 and 41662, respectively) and your IMAP4 connection and disconnection strings (IDs 49884 and 49885, respectively). Be sure to restart these services once you modify their metabase settings.