what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Microsoft IIS Semi-Colon Mitigation Code

Microsoft IIS Semi-Colon Mitigation Code
Posted Dec 30, 2009
Authored by Derek Soeder

This code was released to mitigate the Microsoft IIS semi-colon vulnerability. It's intended for IIS 4.0, 5.x, and 6.0.

SHA-256 | 258979f3104b310429262a5ee76831642e3256b938d895463e1848938fa31d00

Microsoft IIS Semi-Colon Mitigation Code

Change Mirror Download
/*

This mitigation should help block attempts to exploit the IIS
semicolon zero-day (BID 37460), but no warranties and no guarantees.
It didn't crash my web servers during testing, but I make no
representations as to how it will or won't perform on anyone else's
web servers. This mitigation is only intended for IIS 4.0, 5.x, and
6.0; IIS 7.0 does not appear to be vulnerable (although in my
testing, IIS 4.0, 5.0, and 5.1 didn't appear to be vulnerable,
either), and 7.5 is also reportedly not vulnerable.

If an attack is blocked, it should show up in the IIS logs with HTTP
status 403 and the made-up substatus 59; for example, on IIS 6.0:

2009-12-27 12:34:56 W3SVC1 169.254.123.200 GET /evil.asp;x.jpg
- 80 - 169.254.123.100 Mozilla/4.0+(compatible;+MSIE+...) 403 59 0

When passed a malformed file name by IIS due to the vulnerability,
most (non-.NET) ISAPI extensions will process the file, including:

asp.dll / asp51.dll: .asa, .asp, .cdx, .cer, .htr
httpodbc.dll: .idc
ssinc.dll: .shtm, .shtml, .stm

So to get the most protection, you'll need to remap the file
extensions for each different ISAPI extension to a different copy of
the mitigation DLL -- it uses the file name with which it loads to
figure out which ISAPI extension it's wrapping. You'll also need to
set up the registry to tell it where to find the ISAPI extension it's
replacing. For example:

[HKEY_LOCAL_MACHINE\SOFTWARE\iissemi1]
"iissemi1_asp.dll" = "C:\WINDOWS\system32\inetsrv\asp.dll"
"iissemi1_ssinc.dll" = "C:\WINDOWS\system32\inetsrv\ssinc.dll"

Try out a malformed file name after deploying to make sure you have
everything set up properly.

Sorry I can't host an installer right now to automate all of this.
Hopefully most people won't need to use this mitigation, but if the
other options for reducing exposure aren't viable in your situation,
I hope this one will be.

-- Derek


P.S. The vulnerability can also be exploited if a subdirectory
containing ".xxx;" can be created; for instance, accessing
"/~y.asp;y/z.jpg" would cause "z.jpg" to be executed by the
ASP ISAPI extension as though it were an ASP script.

*/

////////////////////////////////////////////////////////////////
// iissemi1.cpp
//==============================================================
// Mitigation to prevent processing of file names that contain a
// semicolon or aberrant colon, to guard against the IIS
// semicolon zero-day.
//
// All file extensions that would normally execute an ISAPI
// extension must be manually remapped to a copy of the
// mitigation DLL. The mitigation works by passing requests to
// the original ISAPI extension unless they contain a semicolon
// or improper colon. It is hard-coded to track down asp.dll
// and a few other DLLs, if the mitigation DLL itself loads with
// a file name that indicates which ISAPI extension it's
// replacing; to override this default behavior, or to support
// an unrecognized ISAPI extension, add a registry value
// matching the mitigation DLL's file name in the
// "HKEY_LOCAL_MACHINE\SOFTWARE\iissemi1" registry key.
//
// To build:
//
// 1. Start Visual Studio 2008 (2005 should also work)
// 2. File -> New -> Project
// 3. Choose Visual C++: Win32: Win32 Project
// 4. Enter "iissemi1" for the name
// 5. In the Win32 Application Wizard, choose an
// "Application type" of "DLL", and under "Additional
// options", check "Empty project"
// 6. In the Solution Explorer, right-click on "Source Files",
// Add -> New Item
// 7. Choose "C++ File (.cpp)" and enter "iissemi1.cpp" for
// the name
// 8. Paste all of this source code into the new .cpp file
// 9. In the Solution Explorer, right-click again on "Source
// Files", Add -> New Item
// 10. Choose "Module-Definition File (.def)" and enter
// "iissemi1.def" for the name
// 11. Paste everything in the block comment below (between the
// rows of ****'s) into the new .def file
// 12. Build -> Configuration Manager; for "Active solution
// configuration", choose "Release"
// 13. For maximum portability, Project -> Properties,
// Configuration Properties: C/C++: Code Generation: set
// "Runtime Library" to "Multi-threaded (/MT)"; this will
// keep iissemi1.dll from requiring MSVCR*.DLL
// 14. (While you're in there, Project -> Properties,
// Configuration Properties: Linker: Input, and make sure
// that "Module Definition File" contains "iissemi1.def")
// 15. Build -> Build Solution
//
// To use:
//
// 16. Open Internet Information Services Manager MMC snap-in
// (run "inetmgr")
// 17. Right-click on "Web Sites" or machine node, Properties
// (Master Properties: Edit, as applicable)
// 18. Home Directory tab, Configuration
// 19. Copy iissemi1.dll to a different file name for each
// distinct ISAPI extension you need to replace; e.g.,
// "iissemi1_asp.dll" if you need to replace "asp.dll",
// "iissemi1_httpodbc.dll" for "httpodbc.dll", etc.
// 20. Remap the file extensions for every ISAPI extension which
// you wouldn't want users to be able to supply with
// arbitrary files, to instead use a copy of iissemi1.dll.
// Make sure to keep a record of each mapping changed, so
// that you can easily reverse the changes later.
// (Note that you might get "requested resource is in use"
// errors if you don't remap every file extension belonging
// to an ISAPI extension -- e.g., if you remap ".asp" but
// not ".asa", you might get HTTP 500 errors when you
// access an ASA file.)
// 21. IIS 6.0: In the IIS Manager, go to the "Web Service
// Extensions" folder, Action -> Add a new web service
// extension, enter "iissemi1" for the extension name, add
// each file created in Step 19 to the "Required files"
// list, check "Set extension status to Allowed", OK
// 22. In Regedit, create the registry key
// "HKEY_LOCAL_MACHINE\SOFTWARE\iissemi1"
// 23. In this new key, create string (REG_SZ or REG_EXPAND_SZ)
// registry values named after the copies of iissemi1.dll
// created in Step 19. The data of each registry value
// should be the full path and file name of the ISAPI
// extension that was replaced; e.g., set the value named
// "iissemi1_asp.dll" to
// "C:\WINDOWS\system32\inetsrv\asp.dll", set the value named
// "iissemi1_httpodbc.dll" to
// "C:\WINDOWS\system32\inetsrv\httpodbc.dll", etc.
// 24. Restart W3SVC (run "iisreset")
//
// To uninstall, remap the file extension mappings changed in
// Step 20 back to their original executable paths.
//
// NO WARRANTIES. Use at your own risk. Redistribution of this
// source code in its original, unmodified form is permitted.
//
// Copyright (C) Derek Soeder - 12/27/2009
////////////////////////////////////////////////////////////////

/**** Paste the following into a new .def file: *************

LIBRARY "iissemi1.dll"

EXPORTS
AspStatusHtmlDump
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
GetExtensionVersion
HttpExtensionProc
TerminateExtension

***************************************************************/

#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <objbase.h>
#include <httpext.h>
#include <stdio.h>

////////////////////////////////////////////////////////////////
// Original ISAPI wrapper
////////////////////////////////////////////////////////////////

WCHAR g_wszMyself[1024];

CRITICAL_SECTION g_csWrappers;
HMODULE g_hmISAPI;
WCHAR g_wszISAPI[1024];

typedef BOOL (WINAPI * PFNASPSTATUSHTMLDUMP)( PVOID, PVOID );
typedef HRESULT (STDAPICALLTYPE * PFNDLLREGISTERSERVER)();
typedef HRESULT (STDAPICALLTYPE * PFNDLLUNREGISTERSERVER)();

PFNASPSTATUSHTMLDUMP g_pfnAspStatusHtmlDump;
LPFNCANUNLOADNOW g_pfnDllCanUnloadNow;
LPFNGETCLASSOBJECT g_pfnDllGetClassObject;
PFNDLLREGISTERSERVER g_pfnDllRegisterServer;
PFNDLLUNREGISTERSERVER g_pfnDllUnregisterServer;
PFN_GETEXTENSIONVERSION g_pfnGetExtensionVersion;
PFN_HTTPEXTENSIONPROC g_pfnHttpExtensionProc;
PFN_TERMINATEEXTENSION g_pfnTerminateExtension;

const struct { void * ppfn; const char * sz; } LOOKUP[] =
{
{ &g_pfnAspStatusHtmlDump, "AspStatusHtmlDump" },
{ &g_pfnDllCanUnloadNow, "DllCanUnloadNow" },
{ &g_pfnDllGetClassObject, "DllGetClassObject" },
{ &g_pfnDllRegisterServer, "DllRegisterServer" },
{ &g_pfnDllUnregisterServer, "DllUnregisterServer" },
{ &g_pfnGetExtensionVersion, "GetExtensionVersion" },
{ &g_pfnHttpExtensionProc, "HttpExtensionProc" },
{ &g_pfnTerminateExtension, "TerminateExtension" }
} ;

BOOL read_reg_path(
LPCWSTR wszKeyName,
LPCWSTR wszValueName )
{
HKEY hkey;
DWORD dwtype, cb, cwch;
WCHAR wsz[ sizeof(g_wszISAPI) /
sizeof(g_wszISAPI[0]) ];

if ( RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszKeyName, 0,
KEY_READ, &hkey ) != ERROR_SUCCESS )
{
return FALSE;
}

cb = (sizeof(g_wszISAPI) - sizeof(g_wszISAPI[0]));

if (RegQueryValueExW( hkey, wszValueName, NULL, &dwtype,
(LPBYTE)g_wszISAPI, &cb ) != ERROR_SUCCESS ||
cb < sizeof(g_wszISAPI[0]) ||
cb > (sizeof(g_wszISAPI) - sizeof(g_wszISAPI[0])) )
{
RegCloseKey( hkey );
return FALSE;
}

RegCloseKey( hkey );

g_wszISAPI[cb / sizeof(g_wszISAPI[0])] = L'\0';

if (dwtype == REG_EXPAND_SZ)
{
cwch = ExpandEnvironmentStringsW( g_wszISAPI,
wsz, ((sizeof(wsz) / sizeof(wsz[0])) - 1) );

if ( cwch == 0 ||
cwch >= (sizeof(wsz) / sizeof(wsz[0])) - 1)
{
return FALSE;
}

wsz[cwch] = L'\0';

memcpy( g_wszISAPI,
wsz, ((cwch + 1) * sizeof(g_wszISAPI[0])) );
}
else if (dwtype != REG_SZ)
return FALSE;

return TRUE;
} //read_reg_path

const wchar_t * __wcsstri(
const wchar_t * _Str,
const wchar_t * _SubStr )
{
size_t cwchstr, cwchsub;

cwchstr = wcslen( _Str );
cwchsub = wcslen( _SubStr );

if (cwchstr < cwchsub)
return 0;

for (cwchstr -= cwchsub; ; cwchstr--, _Str++)
{
if (_wcsnicmp( _Str, _SubStr, cwchsub ) == 0)
return _Str;

if (cwchstr == 0) break;
}

return 0;
} //__wcsstri

BOOL try_defaults(
LPCWSTR wszMyFileName )
{
LPCWSTR wszdll;

if (__wcsstri( wszMyFileName, L"asp51" ))
{
if ( read_reg_path( L"SOFTWARE\\Classes\\CLSID\\"
L"{D97A6DA0-A861-11cf-93AE-00A0C90C2BD8}\\"
L"InprocServer32", NULL ) )
{
return TRUE;
}

wszdll = L"\\asp51.dll";
}
else if (__wcsstri( wszMyFileName, L"asp" ))
{
if ( read_reg_path( L"SOFTWARE\\Classes\\CLSID\\"
L"{D97A6DA0-A861-11cf-93AE-00A0C90C2BD8}\\"
L"InprocServer32", NULL ) )
{
return TRUE;
}

wszdll = L"\\asp.dll";
}
else if (__wcsstri( wszMyFileName, L"httpodbc" ))
wszdll = L"\\httpodbc.dll";
else if (__wcsstri( wszMyFileName, L"ssinc" ))
wszdll = L"\\ssinc.dll";
else if (__wcsstri( wszMyFileName, L"urlauth" ))
wszdll = L"\\urlauth.dll";
else if (__wcsstri( wszMyFileName, L"w3isapi" ))
wszdll = L"\\w3isapi.dll";
else return FALSE;

if ( read_reg_path( L"SOFTWARE\\Microsoft\\InetStp",
L"InstallPath" ) &&
( (sizeof(g_wszISAPI) / sizeof(g_wszISAPI[0])) -
wcslen( g_wszISAPI ) ) > (wcslen( wszdll ) + 1) )
{
wcscat( g_wszISAPI, wszdll );
return TRUE;
}

g_wszISAPI[0] = L'\0';
return FALSE;
} //try_defaults

BOOL load_isapi()
{
LPCWSTR wcp;
size_t i;

EnterCriticalSection( &g_csWrappers );

__try
{
if (g_hmISAPI != NULL)
return TRUE;

wcp = wcsrchr( g_wszMyself, L'\\' );
if (wcp) wcp++; else wcp = g_wszMyself;

if (!read_reg_path( L"SOFTWARE\\iissemi1", wcp ))
{
if (!try_defaults( wcp ))
return FALSE;
}

g_hmISAPI = LoadLibraryW( g_wszISAPI );
if (g_hmISAPI == NULL) return FALSE;

for ( i = 0;
i < (sizeof(LOOKUP) / sizeof(LOOKUP[0])); i++ )
{
*(void * *)(LOOKUP[i].ppfn) =
(void *)GetProcAddress(
g_hmISAPI, LOOKUP[i].sz );
}
}
__finally
{
LeaveCriticalSection( &g_csWrappers );
}

return TRUE;
} //load_isapi

////////////////////////////////////////////////////////////////
// ISAPI extension replacement exports
////////////////////////////////////////////////////////////////

BOOL WINAPI AspStatusHtmlDump(
PVOID pArg0,
PVOID pArg1 )
{
if (!load_isapi() || g_pfnAspStatusHtmlDump == NULL)
return FALSE;

return g_pfnAspStatusHtmlDump( pArg0, pArg1 );
} //AspStatusHtmlDump

STDAPI DllCanUnloadNow()
{
if (!load_isapi() || g_pfnDllCanUnloadNow == NULL)
return S_OK;

return g_pfnDllCanUnloadNow();
} //DllCanUnloadNow

STDAPI DllGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID * ppv )
{
if (!load_isapi() || g_pfnDllGetClassObject == NULL)
return E_UNEXPECTED;

return g_pfnDllGetClassObject( rclsid, riid, ppv );
} //DllGetClassObject

STDAPI DllRegisterServer()
{
if (!load_isapi() || g_pfnDllRegisterServer == NULL)
return E_UNEXPECTED;

return g_pfnDllRegisterServer();
} //DllRegisterServer

STDAPI DllUnregisterServer()
{
if (!load_isapi() || g_pfnDllUnregisterServer == NULL)
return E_UNEXPECTED;

return g_pfnDllUnregisterServer();
} //DllUnregisterServer

BOOL WINAPI GetExtensionVersion(
HSE_VERSION_INFO * pVer )
{
if (!load_isapi() || g_pfnGetExtensionVersion == NULL)
return FALSE;

return g_pfnGetExtensionVersion( pVer );
} //GetExtensionVersion

DWORD WINAPI HttpExtensionProc(
EXTENSION_CONTROL_BLOCK * pECB )
{
HSE_CUSTOM_ERROR_INFO hseerr;
BOOL fdanger;
const char * cp;

if (!load_isapi() || g_pfnHttpExtensionProc == NULL)
return HSE_STATUS_ERROR;

if (pECB != NULL && pECB->lpszPathTranslated != NULL)
{
fdanger = FALSE;

if (strchr( pECB->lpszPathTranslated, ';' ))
fdanger = TRUE;

#if 1 // also check for colon that doesn't belong
cp = pECB->lpszPathTranslated;

if ( cp[0] == '\\' && cp[1] == '\\' &&
(cp[2] == '.' || cp[2] == '?') &&
cp[3] == '\\' && cp[4] != '\0' && cp[5] == ':' )
{
cp += 6;
}
else if ( cp[0] == '\\' && cp[1] == '?' &&
cp[2] == '?' && cp[3] == '\\' &&
cp[4] != '\0' && cp[5] == ':' )
{
cp += 6;
}
else if (cp[0] != '\0' && cp[1] == ':')
{
cp += 2;
}

if (strchr( cp, ':' ))
fdanger = TRUE;
#endif

if (fdanger)
{
if (pECB->ServerSupportFunction != NULL)
{
pECB->ServerSupportFunction(
pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER,
"403 Forbidden",
NULL, NULL );

hseerr.pszStatus = "403 Forbidden";
hseerr.uHttpSubError = 59;

pECB->ServerSupportFunction(
pECB->ConnID,
HSE_REQ_SEND_CUSTOM_ERROR,
&hseerr, NULL, NULL );
} //if(pECB->ServerSupportFunction)

pECB->dwHttpStatusCode = 403;

return HSE_STATUS_SUCCESS;
} //if(fdanger)
} //if(pECB&&pECB->lpszPathTranslated)

return g_pfnHttpExtensionProc( pECB );
} //HttpExtensionProc

BOOL WINAPI TerminateExtension(
DWORD dwFlags )
{
if (!load_isapi() || g_pfnTerminateExtension == NULL)
return FALSE;

return g_pfnTerminateExtension( dwFlags );
} //TerminateExtension

////////////////////////////////////////////////////////////////
// DLL initialization
////////////////////////////////////////////////////////////////

BOOL WINAPI DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved )
{
DWORD cwch;

if (fdwReason == DLL_PROCESS_ATTACH)
{
cwch = GetModuleFileNameW( hinstDLL, g_wszMyself,
( ( sizeof(g_wszMyself) /
sizeof(g_wszMyself[0]) ) - 1 ) );

if ( cwch == 0 ||
cwch >= ( ( sizeof(g_wszMyself) /
sizeof(g_wszMyself[0]) ) - 1 ) )
{
return FALSE;
}

InitializeCriticalSection( &g_csWrappers );
g_hmISAPI = NULL;
g_wszISAPI[0] = L'\0';
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
// do this in TerminateExtension?
//if (g_hmISAPI != NULL)
//{
// FreeLibrary( g_hmISAPI );
// g_hmISAPI = NULL;
//}

DeleteCriticalSection( &g_csWrappers );
}

return TRUE;
} //DllMain
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    23 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close