Vulnerability Development mailing list archives
Re: development of wordpad exploit
From: dullien () GMX DE (Thomas Dullien)
Date: Sat, 20 Nov 1999 16:00:51 +0100
On Fri, 19 Nov 1999 19:45:28 -0800, Blue Boar wrote:
Folks who are AGAINST discussing Windows overflow basics here because they'd be wildly bored hashing over something they already know, mail me privately. I'll use that as a sort of voting mechanism.
Well, I am all for it :) In case of wordpad, I did a little analysis this afternoon: ;-------- snip ------------------- Allrighty... how do we go about exploiting the Wordpad flaw ? I will explain what I did so far, and I assume you have a good kernel-debugger (such as TRW for Win9x or Numega Softice for WinNT), a hex editor and a dis- assembler handy. First of all, we need to collect as much data as possible on what exactly is going on when this overflow occurs. For this reason, we first use wordpad to create a simple rtf file, containing any text you wish. Mine looks like this when viewed in notepad: ;--- snip ;>---------- {\rtf1\ansi\deff0\deftab720{\fonttbl{\f0\fswiss MS Sans Serif;}{\f1\froman\fcharset2 Symbol;}{\f2\froman Times New Roman;}} {\colortbl\red0\green0\blue0;} \deflang1031\pard\plain\f2\fs20 HOLA :) \par } ;--- snap ;>----------- Now, the overflow occured in the first line where the text 'ansi' is, according to the post to bugtraq. Allrighty, lets see what we can do. Change the string "ansi" to "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRR SSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ111122223333444455556666777799990000". I do this to be able to determine how long the overwritten buffer is when EIP is totaled, more on this later. Now, I assume you have a debugger (preferably something like Softice) loaded. Load this file into wordpad and see what happens: Wordpad crashes with 0x6B6B6B6B (="kkkk") in EIP. Lets have a look at our registers and memory for information gathering... The memory at ESP-18 looks in my case exactly like this: :dd esp-0x18 l 60 0023:0012EFBC 6A6A6A6A 6B6B6B6B 0000001B 00000212 jjjjkkkk........ 0023:0012EFCC 0012EFD4 00000023 6C6C6C6C 6D6D6D6D ....#...llllmmmm 0023:0012EFDC 6E6E6E6E 6F6F6F6F 70707070 71717171 nnnnooooppppqqqq 0023:0012EFEC 72727272 73737373 74747474 75757575 rrrrssssttttuuuu 0023:0012EFFC 76767676 77777777 78787878 79797979 vvvvwwwwxxxxyyyy 0023:0012F00C 7A7A7A7A 00000200 00000000 00000000 zzzz............ What can we learn from this memory image ? 1. Obviously our string was stripped of all numbers and converted to lower case 2. The last executed instruction must've been a "RET 0x10", since there is a 16-byte gap between the "kkkk" which was popped into EIP by the RET and the current ESP. 3. The overflow happened in a standard C-convention function probably, as usually the last stack-related instruction executed before RET'ing is POP EBP, and our EBP when the program crashes is 0x6A6A6A6A. Now, we would just love to learn where exactly that RET was executed, since it is always easier seeing if we can exploit something if we have a little more info on what happens before the crash. Now, lets try to figure out where that RET came from... For this purpose, we will truncate our string at the last "j". Why that ? Well, if the string is copied with a standard string copy routine, only the lowest-order byte of the return address will be overwritten by a NULL character which terminates the string. The rest of the return address will remain intact, so that we can determine a 255 byte range in which our RET has to occur. Now, in my case I get an exception at an invalid instruction, and the stack at ESP-0x14 shows me a return address of 0x75023A00. Allrighty, we know that the last '00' is due to our copied string, so the call to our routine which doesn't return properly because we smash its stack is somewhere between 0x75023A00 and 0x75023AFF. This is inside the address region of riched32.dll, not riched20.dll. Lets disassemble riched32.dll. In the address range from where our CALL came, we have only 3 possible calls: 1. 75023A23: CALL 7502339E 2. 75023A5E: CALL 750238CD 3. 75023A69: CALL 750236DF Well, lets load Wordpad again and set breakpoints on these calls. Each time the debugger breaks in, we step over the calls (not into it yet) to see if the call crashes. On the third break, I stepped over the call at 75023A69 and hello (!), there we have our crash. We now know that the exploitable function is the one at 750236DF. Lets narrow it down further and look at this function: PUSH EBP MOV EBP, ESP SUB ESP, 0x24 Well, 36 bytes of stack space are reserved; the stack and local vars look kinda like this: szString db 35 dup(0) variable1 db ? reg_save_EBP dd ? return_Address dd ? So it becomes clear that when we stuff anything longer than 34 letters into our buffer, the internal variable1 will get corrupted, if we stuff more than 38 letters into it, we will corrupt EBP, and if we stuff 42 or more letters into the buffer, we can corrupt the RET address. (Greets to Deep Thought on this one ;) Well, lets step through this function a bit... The function will start copying the string in the file into the local buffer szString, and will only check the first letter whether it is any of these: 0x27, 0x2A (='*'), 0x2D (='-'), 0x5C (='\'), 0x0A (=LF), 0x0D (=CR), 0x34 (=':'), 0x5F (='_'), 0x7B (="{"), 0x7C (='{'), 0x7D (='}'), 0x7E (='~'). Well well well... we have a nice amount of information here. Now, to safely turn control to the data we pass onto the stack, we need some kind of either JMP ESP or CALL ESP, as none of the registers we have point to the data buffer we're overflowing. The opcodes for JMP ESP are 0xFF, 0xE4 and the opcodes for the CALL ESP are 0xFF, 0xD4. Now, lets search in memory for something like this. Note: In order to create a truly stable exploit, we'd have to find such data at an address that is _static_ on all service packs. I don't know of any CALL/JMP ESP's that are static on all service packs, so I can't really help in this case but to do version-specific work. If anyone winds up with a nicer solution, please tell me :) In my case, a nice CALL ESP resides in mfc42u.dll, on my computer (NT4SP5) at address 75ea991C. Now lets try if we can set EIP to this value. Add the "kkkk" at the end of our buffer again, then fire up a hex editor and sub- stitute them for 0x1C, 0x99, 0xea, 0x75. Now when trying to run this baby, we see that all non-characters are filtered out. Damn. We have a problem here. I doubt that this overflow can be easily exploited in a by-the book manner, as the data we pass on the stack is too heavily filtered in order to be put to regular use as 'code we inject'... anyone have any suggestions here ? Thomas Dullien dullien () gmx de Win32 Security Consultant ;-> Hire me !
Current thread:
- Re: development of wordpad exploit, (continued)
- Re: development of wordpad exploit Riley, Steven (Nov 19)
- Re: development of wordpad exploit Thomas Dullien (Nov 19)
- Re: development of wordpad exploit Harlan Carvey (Nov 19)
- Re: development of wordpad exploit Vanna P. Rella (Nov 19)
- Re: development of wordpad exploit Witold Chrabaszcz (Nov 19)
- Re: development of wordpad exploit Blue Boar (Nov 19)
- Re: development of wordpad exploit Rodrick Brown (Nov 19)
- [Fwd: INZIDER!] Blue Boar (Nov 19)
- Re: development of wordpad exploit Seth R Arnold (Nov 20)
- Re: development of wordpad exploit Witold Chrabaszcz (Nov 19)
- Re: development of wordpad exploit Aubrey Smith (Nov 20)
- Re: development of wordpad exploit Thomas Dullien (Nov 20)
- Re: development of wordpad exploit Dave Harvill (Nov 20)
- Re: development of wordpad exploit Pauli Ojanpera (Nov 21)
- Re: development of wordpad exploit Thomas Dullien (Nov 22)