Pwn学习随笔( 三 )


>>> context.arch= 'i386'>>> context.os= 'linux'>>> context.endian= 'little'>>> context.word_size = 32当然 , 你也可以一次性设置好这些变量:
>>> asm('nop')'\x90'>>> context(arch='arm', os='linux', endian='big', word_size=32)>>> asm('nop')'\xe3 \xf0\x00'

  • IO模块:这个比较容易跟zio搞混 , 记住zio是read、write , pwn是recv、send
  • send(data): 发送数据sendline(data) : 发送一行数据 , 相当于在末尾加\nrecv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时recvuntil(delims, drop=False) : 接收到delims的pattern(以下可以看作until的特例)recvline(keepends=True) : 接收到\n , keepends指定保留\nrecvall() : 接收到EOFrecvrepeat(timeout=default) : 接收到EOF或timeoutinteractive() : 与shell交互
    • ELF模块:获取基地址、获取函数地址(基于符号)、获取函数got地址、获取函数plt地址
    e = ELF('/bin/cat')>>> print hex(e.address)# 文件装载的基地址0x400000>>> print hex(e.symbols['write']) # 函数地址0x401680>>> print hex(e.got['write']) # GOT表的地址0x60b070>>> print hex(e.plt['write']) # PLT的地址0x401680>>> print hex(e.search('/bin/sh').next())# 字符串/bin/sh的地址
    • 在编写exp时 , 最常见的工作就是在整数之间转换 , 而且转换后 , 它们的表现形式就是一个字节序列 , pwntools提供了打包函数 。
    p32/p64: 打包一个整数 , 分别打包为32位或64位u32/u64: 解包一个字符串 , 得到整数# 比如将0xdeadbeef进行32位的打包 , 将会得到'\xef\xbe\xad\xde'(小端序)payload = p32(0xdeadbeef)#pack 32 bits numberpayload = p64(0xdeadbeef)#pack 64 bits number
    • 汇编和反汇编
      # 汇编:>>> asm('nop')'\x90'>>> asm('nop', arch='arm')'\x00\xf0 \xe3'# 可以使用context来指定cpu类型以及操作系统>>> context.arch= 'i386'>>> context.os= 'linux'>>> context.endian= 'little'>>> context.word_size = 32# 反汇编>>> print disasm('6a0258cd80ebf9'.decode('hex'))0:6a 02push0x22:58popeax3:cd 80int0x805:eb f9jmp0x0注意 , asm需要binutils中的as工具辅助 , 如果是不同于本机平台的其他平台的汇编 , 例如在我的x86机器上进行mips的汇编就会出现as工具未找到的情况 , 这时候需要安装其他平台的cross-binutils 。
    • Shellcode生成器
      >>> print shellcraft.i386.nop().strip('\n')nop>>> print shellcraft.i386.linux.sh()/* push '/bin///sh\x00' */push 0x68push 0x732f2f2fpush 0x6e69622f...结合asm可以可以得到最终的pyaload
      from pwn import *context(os='linux',arch='amd64')shellcode = asm(shellcraft.sh())或者from pwn import *shellcode = asm(shellcraft.amd64.linux.sh())
    • ROP链生成器
      elf = ELF('ropasaurusrex')rop = ROP(elf)rop.read(0, elf.bss(0x80))rop.dump()# ['0x0000:0x80482fc (read)',#'0x0004:0xdeadbeef',#'0x0008:0x0',#'0x000c:0x80496a8']str(rop)# '\xfc\x82\x04\x08\xef\xbe\xad\xde\x00\x00\x00\x00\xa8\x96\x04\x08'
    ? 因为ROP对象实现了getattr的功能 , 可以直接通过func call的形式来添加函数 , rop.read(0, elf.bss(0x80))实际相当于rop.call('read', (0,elf.bss(0x80))) 。通过多次添加函数调用 , 最后使用str将整个rop chain dump出来就可以了 。