zoukankan      html  css  js  c++  java
  • pwntools

    [TOC]

    ## 模块简介
    一般使用的话可以直接用from pwn import *将所有的模块导入到当前namespace,这条语句还会帮你把os,sys等常用的系统库导入。
    ** 常用的模块**
    有下面几个:

    >asm : 汇编与反汇编,支持x86/x64/arm/mips/powerpc等基本上所有的主流平台

    >dynelf : 用于远程符号泄漏,需要提供leak方法
    >
    elf : 对elf文件进行操作
    >
    gdb : 配合gdb进行调试
    >
    memleak : 用于内存泄漏
    >
    shellcraft : shellcode的生成器
    >
    tubes : 包括tubes.sock, tubes.process, tubes.ssh, tubes.serialtube,分别适用于不同场景的
    >
    PIPEutils : 一些实用的小功能,例如CRC计算,cyclic pattern等
    >



    ## 常用指令

    ### context 设置运行时变量
    ```shell
    context.log_level = 'debug'
    ```

    ### 读写函数
    无论哪种PIPE都是继承tube而来,可以用于读写函数主要有:
    >interactive() : 直接进行交互,相当于回到shell的模式,在取得shell之后使用
    >recv(numb=4096, timeout=default) : 接收指定字节
    >
    recvall() : 一直接收直到
    >
    EOFrecvline(keepends=True) : 接收一行,keepends为是否保留行尾的
    >
    recvuntil(delims, drop=False) : 一直读到delims的pattern出现为止
    >
    recvrepeat(timeout=default) : 持续接受直到EOF或timeout
    >
    send(data) : 发送数据sendline(data) : 发送一行数据,相当于在数据末尾加

    ### remote——远程读写

    使用remote(address, port)产生一个远程的socket然后就可以读写了
    ```shell
    conn = remote('ftp.debian.org',21)
    conn.recvline() 
    '220 ...'
    conn.send('USER anonymous ')
    conn.recvuntil(' ', drop=True)
    '331'
    conn.recvline()
    'Please specify the password. '
    conn.close()

    ```




    ### process——打开一个本地程序并进行交互
    同样地,使用**process可以打开一个本地程序并进行交互**

    ```shell
    sh = process('/bin/sh')
    sh.sendline('sleep 3; echo hello world;')
    sh.recvline(timeout=1)

    sh.recvline(timeout=5)
    'hello world '
    sh.close()
    ```




    ### listen来开启一个本地的监听端口

    同时,也可以使用listen来开启一个本地的监听端口

    ```python
    l = listen()
    r = remote('localhost', l.lport)
    c = l.wait_for_connection()
    r.send('hello')
    c.recv()
    'hello'

    ```


    ### 汇编与反汇编
    使用asm来进行汇编

    > asm('nop')
    'x90'
    > asm('nop', arch='arm')
    'x00xf0 xe3'
    可以使用context来指定cpu类型以及操作系统1

    > context.arch      = 'i386'
    > context.os        = 'linux'
    >context.endian    = 'little'
    > context.word_size = 32
    使用disasm进行反汇编1

    > print disasm('6a0258cd80ebf9'.decode('hex'))
       0:   6a 02                   push   0x2
       2:   58                      pop    eax
       3:   cd 80                   int    0x80
       5:   eb f9                   jmp    0x0

    注意,**asm需要binutils中的as工具辅助**,如果是不同于本机平台的其他平台的汇编,例如在我的x86机器上进行mips的汇编就会出现as工具未找到的情况,这时候需要安装其他平台的cross-binutils。



    ### ELF
    ELF文件操作这个还是挺实用的,在进行elf文件逆向的时候,总是需要对各个符号的地址进行分析,elf模块提供了一种便捷的方法能够迅速的得到文件内函数的地址,plt位置以及got表的位置。

    ```python
    >>> 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
    同样,也可以打开一个libc.so来解析其中system的位置:)甚至可以修改一个ELF的代码

    >>> e = ELF('/bin/cat')
    >>> e.read(e.address+1, 3)
    'ELF'
    >>> e.asm(e.address, 'ret')
    >>> e.save('/tmp/quiet-cat')
    >>> disasm(file('/tmp/quiet-cat','rb').read(1))
    '   0:   c3                      ret'
    ```
    ELF模块在文档里好像还没有写的样子,不过可以从源码中看到一些可用的函数asm(address, assembly) : 在指定地址进行汇编bss(offset) : 返回bss段的位置,offset是偏移值checksec() : 对elf进行一些安全保护检查,例如NX, PIE等。disasm(address, n_bytes) : 在指定位置进行n_bytes个字节的反汇编offset_to_vaddr(offset) : 将文件中的偏移offset转换成虚拟地址VMAvaddr_to_offset(address) : 与上面的函数作用相反read(address, count) : 在address(VMA)位置读取count个字节write(address, data) : 在address(VMA)位置写入datasection(name) : dump出指定section的数据

    ### ROP
    ROP链生成器现在的exploit是越来越难,一般起手题都得是NX开启的,ROP这种以前都能出400分题的技术现在也就出50-100分题了非常惨,也许跟这个工具简化了ROP过程有关系?
    先简单回顾一下ROP的原理,由于NX开启不能在栈上执行shellcode,我们可以在栈上布置一系列的返回地址与参数,这样可以进行多次的函数调用,通过函数尾部的ret语句控制程序的流程,而用程序中的一些pop/ret的代码块(称之为gadget)来平衡堆栈。其完成的事情无非就是放上/bin/sh,覆盖程序中某个函数的GOT为system的,然后ret到那个函数的plt就可以触发system('/bin/sh')。由于是利用ret指令的exploit,所以叫Return-Oriented Programming。(如果没有开启ASLR,可以直接使用ret2libc技术)好,这样来看,这种技术的难点自然就是如何在栈上布置返回地址以及函数参数了。而ROP模块的作用,就是自动地寻找程序里的gadget,自动在栈上部署对应的参数。

    ```python
    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)
    # 'xfcx82x04x08xefxbexadxdex00x00x00x00xa8x96x04x08'
    ```
    使用ROP(elf)来产生一个rop的对象,这时rop链还是空的,需要在其中添加函数。因为ROP对象实现了__getattr__的功能,可以**直接通过func call的形式来添加函数**,rop.read(0, elf.bss(0x80))实际相当于rop.call('read', (0, elf.bss(0x80)))。

    通过多次添加函数调用,最后使用str将整个rop chain dump出来就可以了。call(resolvable, arguments=()) : 添加一个调用,resolvable可以是一个符号,也可以是一个int型地址,注意后面的参数必须是元组否则会报错,即使只有一个参数也要写成元组的形式(在后面加上一个逗号)chain() : 返回当前的字节序列,即payloaddump() : 直观地展示出当前的rop chainraw() : 在rop chain中加上一个整数或字符串search(move=0, regs=None, order=’size’) : 按特定条件搜索gadget,没仔细研究过unresolve(value) : 给出一个地址,反解析出符号


    ### 整数的pack与数据的unpack(p32,p64,u32,u64)
    其他对于整数的pack与数据的unpack,可以使用p32,p64,u32,u64这些函数,分别对应着32位和64位的整数。
    另外,在utils工具中比较常用的就是可以使用cyclic pattern来找到return address的位置,这个功能在gbd peda中也是有的,这里就不过多介绍了。


    ### DynELF
    DynELF是leak信息的神器。前提条件是要提供一个输入地址,输出此地址最少1byte数的函数。
    ### args 快速访问所有的命令行参数

    ###  shellcraft 提供了很多现成shellcode

    ### cyclic and cyclic_find 
    对于直接的缓冲区溢出,可以很方便的确认再偏移多少可以控制eip


    ## Tips
    - python os.environ[‘LD_PRELOAD’] = ‘./libc-x.so’,指定libc加载

    - pwntools注意send和sendline的区别

    - pwntools dynelf 获取两个函数地址相对偏移,获取偏移之后leak一次即可获得system地址


    - 程序运行之后找字符串,system(“sh”)通常也是可行的


  • 相关阅读:
    JavaScript String常用方法和属性
    JavaScript null 和 undefined
    document.write()
    MyBatis中的@MapKey注解
    Zookeeper实现分布式锁
    zookeeper相关
    二阶段提交和三阶段提交
    代理模式
    模板方法模式
    策略模式
  • 原文地址:https://www.cnblogs.com/volva/p/11814980.html
Copyright © 2011-2022 走看看