Vulnerability Development mailing list archives
Re: No-Exec Stack Smashing 101
From: huuskone () CC HELSINKI FI (Taneli Huuskonen)
Date: Thu, 27 Apr 2000 00:00:47 +0300
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 "Granquist, Lamont" <lamont () ICOPYRIGHT COM> wrote:
Okay, lets say that you've got: 1. non-exec stack 2. libc remapped to location with 0x00 in it 3. statically linked executable, so no PLT functions And assume the bug is a simple buffer overflow in a string function which terminates on a 0x00 (i.e. ignore for the moment ways around a 0x00 "canary")
You mean the possibility of overflowing the same buffer several times within the same function and such?
How can you get around that? Is there a more general way around non-exec stacks than return-into-PLT exploits?
Well, the following possibilities spring to mind: 1) Certainly the simplest case is when the programme calls system() itself - just "return" to the call. 2) Call some other legitimate subroutine with rogue parameters. For instance, call an initialization routine to read a bogus configuration file. 3) Use some other part of memory that is both writable and executable. For instance, a user-supplied string might be copied to a malloc()'ed or static buffer at a predictable address, which might be executable. 4) Use a subroutine within the accessible address range to shift some values around on the stack so that after two levels of return, the libc routine is called with user-supplied arguments. This needs a bit more explanation. Assume that there is a subroutine that copies a value from, say, BP+8 to BP-0x14, (that'd be a parameter to a local variable) and doesn't do anything much after that before returning. Let the address of the subroutine, after the stack manipulation on entry, be 0x88888888, and let the value of BP be 0xCCCCCCCC when the buffer overflow occurs. Let the address of the system() function be 0x00102030. The overflowed buffer could contain the following data at given addresses (0xDEADBEEF denotes unimportant values): 0xCCCCCC80: the string "echo foo::0:0::/:/bin/sh >>/etc/passwd;" 0xCCCCCCCC: 0xCCCCCCEC - the value for BP for the sub at 0x88888888 0xCCCCCCD0: 0x88888888 - "return" address 0xCCCCCCD4: 0xDEADBEEF - value for BP when system() is called 0xCCCCCCD8: 0xDEADBEEF - will be overwritten by 0x00102030 0xCCCCCCDC: 0xDEADBEEF - address that system() returns to 0xCCCCCCE0: 0xCCCCCC80 - the parameter for system() 0xCCCCCCE4: 0xDEADBEEF 0xCCCCCCE8: 0xDEADBEEF 0xCCCCCCEC: 0xCCCCCCD4 - value for BP in the second end-of-sub 0xCCCCCCF0: 0x88888888 - any end-of-subroutine would do 0xCCCCCCF4: 0x00102030 - possible on a little-endian machine Now, when the subroutine containing the overflow terminates, the value of BP (0xCCCCCCCC) is moved to SP. Then BP gets the new value 0xCCCCCCEC from stack, and control returns to 0x88888888. This address is in the middle of a subroutine, so BP is not pushed onto the stack and replaced by the value of SP. The subroutine copies the value 0x00102030 from 0xCCCCCCF4 (BP+8) to 0xCCCCCCD8 (BP-0x14), moves BP to SP, pops 0xCCCCCCD4 into BP, and "returns" to 0x88888888. An irrelevant value is copied from 0xCCCCCCDC (BP+8) to 0xCCCCCCC0 (BP-0x14), BP is moved to SP, an irrelevant value for BP is popped from the stack (location 0xCCCCCCD4), and the subroutine "returns" to the address 0x00102030, that is, to the system() library function. The value of SP is now 0xCCCCCCDC. At that address, system() expects to find a return address, followed by the address of the parameter string. The system() function passes the string at 0xCCCCCC80 to the shell, then returns to a bogus address and crashes in this example. 5) Find a "jump to register" opcode somewhere, set up the register suitably, then "return" to the address of the register jump. For instance, if the subroutine containing the buffer overflow also parses a decimal integer and leaves the result in DX before returning, you could hunt for an opcode for "jump dx", including the value 1056816 (0x00102030) in the input and returning to the jump instruction. The two-byte opcode (or equivalent) is reasonably likely to exist purely by chance in most programmes except for quite small ones. 6) Ditto, but with a "syscall" opcode. I don't know how difficult this type of exploit would be in practice, but it's theoretically quite possible, at least in combination with (2) above. Of course, buffer overflows can be exploited in ways that don't affect the path of execution at all - directing some output to the wrong file can be effective enough, for example. Taneli Huuskonen -----BEGIN PGP SIGNATURE----- Version: PGPfreeware 5.0i for non-commercial use Charset: noconv iQA/AwUBOQdYTF+t0CYLfLaVEQL/xACg0IsaJ0LAmG4PkvjCI7gz21x6LysAn1qu Ecc2STwA6ZHTRHfeSUjEoZPu =9MPO -----END PGP SIGNATURE----- -- I don't | All messages will be PGP signed, | Fight for your right to speak for | encrypted mail preferred. Keys: | use sealed envelopes. the Uni. | http://www.helsinki.fi/~huuskone/ | http://www.gilc.org/
Current thread:
- Re: Blind Remote Buffer Overflow, (continued)
- Re: Blind Remote Buffer Overflow Sebastian (Apr 29)
- Re: Blind Remote Buffer Overflow Mark L. Jackson (Apr 29)
- Re: Blind Remote Buffer Overflow Arturo Busleiman (Apr 30)
- Re: Blind Remote Buffer Overflow Arturo Busleiman (Apr 30)
- Replacing Kernel Functions via a LKM Granquist, Lamont (Apr 27)
- Re: Replacing Kernel Functions via a LKM Dragos Ruiu (Apr 27)
- Re: Replacing Kernel Functions via a LKM Dragos Ruiu (Apr 28)
- Re: Replacing Kernel Functions via a LKM Prateek Jetly (Apr 27)
- Re: No-Exec Stack Smashing 101 Michael H. Warfield (Apr 26)
- Re: No-Exec Stack Smashing 101 Crispin Cowan (Apr 26)
- Re: No-Exec Stack Smashing 101 Taneli Huuskonen (Apr 26)
- Re: No-Exec Stack Smashing 101 Michael H. Warfield (Apr 20)