2019 4月16日前所学


pwntools:

(参照//www.jianshu.com/p/355e4badab50)

使用from pwn import *将所有的模块导入到当前namespace

模块:

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

dynelf : 用于远程符号泄漏,需要提供leak方法

elf : 对elf文件进行操作

gdb : 配合gdb进行调试

memleak : 用于内存泄漏

shellcraft : shellcode的生成器

tubes : 包括tubes.sock, tubes.process, tubes.ssh, tubes.serialtube,分别适用于不同场景的PIPE

utils : 一些实用的小功能,例如CRC计算,cyclic pattern等

连接:

本地 :sh = porcess("./level0")

远程:sh = remote("127.0.0.1",10001)对于remote函数可以接url并且指定端口

关闭连接:sh.close()

数据处理:

主要是对整数进行打包:p32、p64是打包为二进制,u32、u64是解包为二进制

IO模块:

容易跟zio搞混,zio是read、write,pwn是recv、send

sh.send(data)  发送数据

sh.sendline(data)  发送一行数据,相当于在数据后面加\n

sh.recv(numb =2048, timeout = dufault)  接受数据,numb指定接收的字节,timeout指定超时

sh.recvline(keepends=True)  接受一行数据,keepends为是否保留行尾的\n

sh.recvuntil("Hello,World\n",drop=fasle) 接受数据直到我们设置的标志出现

sh.recvall()  一直接收直到EOF

sh.recvrepeat(timeout =default)  持续接受直到EOF或timeout

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

汇编和反汇编:

利用asm和disasm

asm需要binutils中的as工具辅助

context可用来指定cpu类型以及操作系统,如:

context.arch ='i386'

context.os ='linux'

 context.endian ='little'

 context.word_size =32

Shellcode生成payload:

得到payload

from pwn import*

context(os='linux',arch='amd64')

shellcode = asm(shellcraft.sh())

或者

from pwn import* 

shellcode = asm(shellcraft.amd64.linux.sh())

除了直接执行sh之外,还可以进行其它的一些常用操作例如提权、反向连接

ELF文件求地址:

ELF可重定位目标文件的节:

.bss(Block Strorage Start) 储存未初始化的全局和c变量,和被初始化为0的全局和静态变量

>>> e = ELF('/bin/cat')

>>> print hex(e.address)# 文件装载的基地址

>>> print hex(e.symbols['write'])# 函数地址

>>> print hex(e.got['write'])# GOT表的地址

>>> print hex(e.plt['write'])# PLT的地址

>>> print hex(e.search('/bin/sh').next())# 字符串/bin/sh的地址

脚本常用:

context.arch ='amd64'//设置架构

context.log_level ='debug'//显示log详细信息

libc = ELF('./libc-2.24.so')//加载库文件

做pwn题时的一些调试技巧:参考(https://blog.csdn.net/zszcr/article/details/79834303)

脚本调试:

1、context.log_level="debug"

脚本在执行时就会输出debug的信息,你可以通过观察这些信息查找哪步出错了

2、pwnlib.gdb.attach(p)

在发送payload前加入这条语句,同时加上pause() 时脚本暂停

然后就会弹出来一个开启着gdb的终端,你先在gdb中设置好断点

然后再运行脚本的那个终端按一下回车继续运行脚本,程序就会运行到断点,你就可以查看相应的寄存器,或者是栈的信息

格式:payload = .....

           pwnlib.gdb.attach(p)

           pause()

           p.sendline(payload)

           p.interactive()

Egg hunting:

使用情况:可用缓冲区太短装不了所有的shellcode。

Egg hunting这种技巧可以被归为“分级shellcode”,它主要可以支持你用一小段特制的shellcode来找到你的实际的(更大的)shellcode(我们的‘鸡蛋‘),原理就是通过在内存中搜索我们的最终shellcode。换句话说,一段短代码先执行,然后再去寻找真正的shellcode并执行。

条件:

1.  你必须能跳到(jmp,call,push/ret)并且执行“一些”shellcode。可用缓冲区空间可以相对较小,因为它只需要包含一些所谓的“鸡蛋猎人”。

2.  最终的shellcode必须在一个可用的存储空间中(堆、栈)

3.  你必须要用一个独特的记号标记最终的shellcode。最初的shellcode(短小的“鸡蛋猎人”)会遍历内存空间,寻找这个小标记。找到它后,用一个jmp或call 指令跳转到小标记后面的代码中执行。这就意味着你需要在鸡蛋猎人代码中定义这个标记,并且把标记写到实际shellcode的前面。

搜索内存是相当需要处理器资源的,并且会花一段时间。因此:

1.搜寻内存时,很快CPU就被占满了。

2.执行shellcode前会先花上一段时间。

所涉及的汇编代码:

or dx,0xfff;获取页尾地址

inc edx;计数器

push edx;

push byte +0x02;NtAccessCheckAndAuditAlarm的调用号;或者用0x43调用NtDisPlayString()

pop eax  ;0x02或0x43装入eax,这样就能当做参数调用系统函数了

int 0x2e  ;告诉内核我想用之前的寄存器调用系统函数

cmp al,0x5    ;检查是否触发非法访问;0xc0000005==ACCESS_VIOLATION 

pop edx    ;返回edx

je xxxx    ;74 EF   跳回开头dx  0xfff处

mov eax,0x50905090;标签(鸡蛋)

mov edi,edx;  edi用作指针

scasd    ;对比状态位

jnz xxxxxx  ;75EA跳回inc ebx,检查找到没

scasd    ;当找到鸡蛋后

jnz xxxxx  ;跳回inc edx ;仅当第一个鸡蛋被找到

jmp edi  ;edi指向shellcode的开头

你可能感兴趣的:(2019 4月16日前所学)