pwntools使用以及pwn入门

(来源:yichen的信安知识库

push和pop是用来操作栈的2个指令。

push寄存器:将一个寄存器中的数据入栈

pop寄存器:出栈用一个寄存器接收数据

基本使用

  1. 首先需要 from pwn import * 把 pwntools 导入进来,它同时会把一些系统库给导入进来

  2. 本地打的话 p=process('./filename'),远程的话

    p=remote('192.168.1.103',10001)

    p.close() 关闭

  3. 发送 payload

    p.send(payload) 发送 payload

    p.sendline(payload) 发送 payload,并进行换行(末尾\n)

    p.sendafter(some_string, payload) 接收到 some_string 后, 发送你的 payload

    p.sendlineafter(some_string, payload) 接收到 some_string 后, 发送你的 payload,加个换行

  4. 接收返回内容

    p.recvn(N) 接受 N(数字) 字符

    p.recvline() 接收一行输出

    p.recvlines(N) 接收 N(数字) 行输出

    p.recvuntil(some_string) 接收到 some_string 为止

    p.interactive() 直接进行交互,相当于回到shell的模式,一般在取得shell之后使用

  5. 生成 shellcode

    asm(shellcraft.sh())

ELF

首先需要 elf=ELF('./filename') 来产生一个对象

elf.symbols['a_function'] 找到 a_function 的地址

elf.got['a_function'] 找到 a_function的 got

elf.plt['a_function'] 找到 a_function 的 plt

elf.next(e.search("some_characters")) 找到包含 some_characters 可以是字符串,汇编代码或者某个数值的地址

  • .got

GOT(Global Offset Table)全局偏移表。这是「链接器」为「外部符号」填充的实际偏移表。

  • .plt

PLT(Procedure Linkage Table)程序链接表。它有两个功能,要么在 .got.plt 节中拿到地址,并跳转。要么当 .got.plt 没有所需地址的时,触发「链接器」去找到所需地址

  • .got.plt

这个是 GOT 专门为 PLT 专门准备的节。.got.plt 中的值是 GOT 的一部分**。它包含上述 PLT 表所需地址(已经找到的和需要去触发的)

作者:madao756
链接:https://www.jianshu.com/p/5092d6d5caa3
来源:简书

ROP

rop = ROP('./filename') 还是要先创建一个对象

rop.raw('a'*32) 在构造的 rop 链里面写 32 个 a

rop.call('read', (0, elf.bss(0x80))) 调用一个函数,可以简写成:rop.read(0, elf.bss(0x80))

rop.chain() 就是整个 rop 链,发送的 payload

rop.dump() 直观地展示当前的 rop 链

rop.migrate(base_stage) 将程序流程转移到 base_stage(地址)

rop.unresolve(value) 给出一个地址,反解析出符号

rop.search(regs=['ecx','ebx']) 搜索对 eax 进行操作的 gadgets

rop.find_gadget(['pop eax','ret']) 搜索 pop eax ret 这样的 gadgets

重点:pwn入门

寄存器相关知识:

EIP:主要用于存放当前代码段即将被执行的下一条指令的偏移,但其本质上并不能直接被指令直接访问。

最典型的栈溢出利用是覆盖程序的返回地址为攻击者所控制的地址,也就是覆盖EIP

ESP:栈顶指针,始终指向栈顶

EBP:栈底指针,通常叫栈基址

软件保护机制:

CANARY(栈保护)

栈溢出保护是一种缓冲区溢出攻击缓解手段,当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。

NX(DEP)(数据执行保护 Data Execution Prevention)

NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。

PIE(ASLR)

内存地址随机化机制(address space layout randomization),有以下三种情况:

0 - 表示关闭进程地址空间随机化

1 - 表示将mmap的基址,stack和vdso页面随机化

2 - 表示在1的基础上增加堆(heap)的随机化

堆栈过程

‘N’表示NOP,存原EIP的地方覆盖成了ESP 的地址,接下去的‘S0’、‘S1’等表示ShellCode 开始的 0字节、1字节等。
函数执行完毕,要返回时堆栈指针ESP会指向保存原EIP的地方,而指令指针EIP指向Ret指令。
Ret相当于 Pop EIP ,就是把栈顶指针ESP指向的值弹出来给EIP。

所以在正常情况下,Ret执行后,就可把原来的EIP恢复,从而回到中断前的流程。

但是保存的EIP已经被我们覆盖成JMP ESP指令的地址了。这样执行 Pop EIP 后,EIP会被改为JMP ESP的地址,即指向JMP ESP。而堆栈指针ESP往下移一位,指向ShellCode的第一个字节(即‘S0’)了。
计算机继续往下执行EIP指向的指令——JMP ESP,而ESP指向的是‘S0’,这样就JMP到了‘S0’中,开始执行我们的ShellCode了!
★小知识:EIP指令指针指向下一条要执行的命令,一般会自动加1。ESP堆栈顶指针指向堆栈的顶部。在PUSH时,ESP往上走,减1;在POP时,ESP往下走,加1。★

image-20200604213031791

PWN下如何查找函数的加载地址

(pwn场景中,译者注)查找某个函数地址的典型方法是:通过计算与同一库中另一个已泄露出地址的函数的偏移量,得到所需函数的地址。然而,要使此方法有效工作,远程服务器的gLibc版本需要与我们本地的版本相同。当然我们也可以通过泄漏一些函数并在libcdb.com中搜索找到匹配的gLibc版本,但有时这种方法会失败。