mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-24 03:01:15 +07:00
update pwntools
This commit is contained in:
parent
058c9c5e70
commit
da67b9a3e4
@ -40,12 +40,47 @@ $ yaourt -S python2-pwntools
|
||||
|
||||
$ yaourt -S python2-pwntools-git
|
||||
```
|
||||
但是由于 Arch 没有 PPA 源,如果想要支持更多的体系结构(如 arm, aarch64 等),只能手动编译安装相应的 binutils,使用下面的脚本,注意将变量 `V` 和 `ARCH` 换成你需要的。[binutils](https://ftp.gnu.org/gnu/binutils/)
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
V = 2.29 # binutils version
|
||||
ARCH = arm # target architecture
|
||||
|
||||
cd /tmp
|
||||
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.xz
|
||||
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.xz.sig
|
||||
|
||||
# gpg --keyserver keys.gnupg.net --recv-keys C3126D3B4AE55E93
|
||||
# gpg --verify binutils-$V.tar.xz.sig
|
||||
|
||||
tar xf binutils-$V.tar.xz
|
||||
|
||||
mkdir binutils-build
|
||||
cd binutils-build
|
||||
|
||||
export AR=ar
|
||||
export AS=as
|
||||
|
||||
../binutils-$V/configure \
|
||||
--prefix=/usr/local \
|
||||
--target=$ARCH-unknown-linux-gnu \
|
||||
--disable-static \
|
||||
--disable-multilib \
|
||||
--disable-werror \
|
||||
--disable-nls
|
||||
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
测试安装是否成功:
|
||||
```python
|
||||
>>> import pwn
|
||||
>>> pwn.asm("xor eax,eax")
|
||||
'1\xc0'
|
||||
>>> from pwn import *
|
||||
>>> asm('nop')
|
||||
'\x90'
|
||||
>>> asm('nop', arch='arm')
|
||||
'\x00\xf0 \xe3'
|
||||
```
|
||||
|
||||
|
||||
@ -68,7 +103,7 @@ Pwntools 分为两个模块,一个是 `pwn`,简单地使用 `from pwn import
|
||||
- `libcdb`:libc 数据库
|
||||
- `log`:日志记录
|
||||
- **`memleak`**:用于内存泄露
|
||||
- `rop`:ROP 利用模块,包括 rop 和 srop
|
||||
- **`rop`**:ROP 利用模块,包括 rop 和 srop
|
||||
- `runner`:运行 shellcode
|
||||
- **`shellcraft`**:shellcode 生成器
|
||||
- `term`:终端处理
|
||||
@ -107,106 +142,310 @@ Pwntools 分为两个模块,一个是 `pwn`,简单地使用 `from pwn import
|
||||
- `close()`:关闭管道
|
||||
|
||||
下面是一个例子,先使用 listen 开启一个本地的监听端口,然后使用 remote 开启一个套接字管道与之交互:
|
||||
```
|
||||
In [1]: from pwn import *
|
||||
|
||||
In [2]: l = listen()
|
||||
```text
|
||||
>>> from pwn import *
|
||||
>>> l = listen()
|
||||
[x] Trying to bind to 0.0.0.0 on port 0
|
||||
[x] Trying to bind to 0.0.0.0 on port 0: Trying 0.0.0.0
|
||||
[+] Trying to bind to 0.0.0.0 on port 0: Done
|
||||
[x] Waiting for connections on 0.0.0.0:35117
|
||||
[x] Waiting for connections on 0.0.0.0:46147
|
||||
>>> r = remote('localhost', l.lport)
|
||||
[x] Opening connection to localhost on port 46147
|
||||
[x] Opening connection to localhost on port 46147: Trying ::1
|
||||
[x] Opening connection to localhost on port 46147: Trying 127.0.0.1
|
||||
[+] Opening connection to localhost on port 46147: Done
|
||||
>>> [+] Waiting for connections on 0.0.0.0:46147: Got connection from 127.0.0.1 on port 38684
|
||||
|
||||
In [3]: r = remote('localhost', l.lport)
|
||||
[x] Opening connection to localhost on port 35117
|
||||
[x] Opening connection to localhost on port 35117: Trying ::1
|
||||
[x] Opening connection to localhost on port 35117: Trying 127.0.0.1
|
||||
[+] Opening connection to localhost on port 35117: Done
|
||||
|
||||
[+] Waiting for connections on 0.0.0.0:35117: Got connection from 127.0.0.1 on port 36966
|
||||
In [4]: c = l.wait_for_connection()
|
||||
|
||||
In [5]: r.send('hello\n')
|
||||
|
||||
In [6]: c.recv()
|
||||
Out[6]: 'hello\n'
|
||||
|
||||
In [7]: r.send('hello\n')
|
||||
|
||||
In [8]: c.recvline()
|
||||
Out[8]: 'hello\n'
|
||||
|
||||
In [9]: r.sendline('hello')
|
||||
|
||||
In [10]: c.recv()
|
||||
Out[10]: 'hello\n'
|
||||
|
||||
In [11]: r.sendline('hello')
|
||||
|
||||
In [12]: c.recvline()
|
||||
Out[12]: 'hello\n'
|
||||
|
||||
In [13]: r.sendline('hello')
|
||||
|
||||
In [14]: c.recvline(keepends=False)
|
||||
Out[14]: 'hello'
|
||||
|
||||
In [15]: r.send('hello world')
|
||||
|
||||
In [16]: c.recvuntil('hello')
|
||||
Out[16]: 'hello'
|
||||
|
||||
In [17]: c.recv()
|
||||
Out[17]: ' world'
|
||||
|
||||
In [18]: c.close()
|
||||
[*] Closed connection to 127.0.0.1 port 36966
|
||||
|
||||
In [19]: r.close()
|
||||
[*] Closed connection to localhost port 35117
|
||||
>>> c = l.wait_for_connection()
|
||||
>>> r.send('hello\n')
|
||||
>>> c.recv()
|
||||
'hello\n'
|
||||
>>> r.send('hello\n')
|
||||
>>> c.recvline()
|
||||
'hello\n'
|
||||
>>> r.sendline('hello')
|
||||
>>> c.recv()
|
||||
'hello\n'
|
||||
>>> r.sendline('hello')
|
||||
>>> c.recvline()
|
||||
'hello\n'
|
||||
>>> r.sendline('hello')
|
||||
>>> c.recvline(keepends=False)
|
||||
'hello'
|
||||
>>> r.send('hello world')
|
||||
>>> c.recvuntil('hello')
|
||||
'hello'
|
||||
>>> c.recv()
|
||||
' world'
|
||||
>>> c.close()
|
||||
[*] Closed connection to 127.0.0.1 port 38684
|
||||
>>> r.close()
|
||||
[*] Closed connection to localhost port 46147
|
||||
```
|
||||
|
||||
下面是一个与进程交互的例子:
|
||||
```
|
||||
In [1]: p = process('/bin/sh')
|
||||
```text
|
||||
>>> p = process('/bin/sh')
|
||||
[x] Starting local process '/bin/sh'
|
||||
[+] Starting local process '/bin/sh': pid 32165
|
||||
|
||||
In [2]: p.sendline('sleep 3; echo hello world;')
|
||||
|
||||
In [3]: p.recvline(timeout=1)
|
||||
Out[3]: 'hello world\n'
|
||||
|
||||
In [4]: p.sendline('sleep 3; echo hello world;')
|
||||
|
||||
In [5]: p.recvline(timeout=1)
|
||||
Out[5]: ''
|
||||
|
||||
In [6]: p.recvline(timeout=5)
|
||||
Out[6]: 'hello world\n'
|
||||
|
||||
In [7]: p.interactive()
|
||||
[+] Starting local process '/bin/sh': pid 26481
|
||||
>>> p.sendline('sleep 3; echo hello world;')
|
||||
>>> p.recvline(timeout=1)
|
||||
'hello world\n'
|
||||
>>> p.sendline('sleep 3; echo hello world;')
|
||||
>>> p.recvline(timeout=1)
|
||||
''
|
||||
>>> p.recvline(timeout=5)
|
||||
'hello world\n'
|
||||
>>> p.interactive()
|
||||
[*] Switching to interactive mode
|
||||
whoami
|
||||
firmy
|
||||
^C[*] Interrupted
|
||||
>>> p.close()
|
||||
[*] Stopped process '/bin/sh' (pid 26481)
|
||||
```
|
||||
|
||||
In [8]: p.close()
|
||||
[*] Stopped process '/bin/sh' (pid 32165)
|
||||
#### shellcraft
|
||||
使用 shellcraft 模块可以生成对应架构和 shellcode 代码,直接使用链式调用的方法就可以得到,首先指定体系结构,再指定操作系统:
|
||||
```
|
||||
>>> print shellcraft.i386.nop().strip('\n')
|
||||
nop
|
||||
>>> print shellcraft.i386.linux.sh()
|
||||
/* execve(path='/bin///sh', argv=['sh'], envp=0) */
|
||||
/* push '/bin///sh\x00' */
|
||||
push 0x68
|
||||
push 0x732f2f2f
|
||||
push 0x6e69622f
|
||||
mov ebx, esp
|
||||
/* push argument array ['sh\x00'] */
|
||||
/* push 'sh\x00\x00' */
|
||||
push 0x1010101
|
||||
xor dword ptr [esp], 0x1016972
|
||||
xor ecx, ecx
|
||||
push ecx /* null terminate */
|
||||
push 4
|
||||
pop ecx
|
||||
add ecx, esp
|
||||
push ecx /* 'sh\x00' */
|
||||
mov ecx, esp
|
||||
xor edx, edx
|
||||
/* call execve() */
|
||||
push SYS_execve /* 0xb */
|
||||
pop eax
|
||||
int 0x80
|
||||
```
|
||||
|
||||
#### asm
|
||||
该模块用于汇编和反汇编代码。
|
||||
|
||||
#### dynelf
|
||||
体系结构,端序和字长需要在 `asm()` 和 `disasm()` 中设置,但为了避免重复,运行时变量最好使用 `pwnlib.context` 来设置。
|
||||
|
||||
汇编:(`pwnlib.asm.asm`)
|
||||
```text
|
||||
>>> asm('nop')
|
||||
'\x90'
|
||||
>>> asm(shellcraft.nop())
|
||||
'\x90'
|
||||
>>> asm('nop', arch='arm')
|
||||
'\x00\xf0 \xe3'
|
||||
>>> context.arch = 'arm'
|
||||
>>> context.os = 'linux'
|
||||
>>> context.endian = 'little'
|
||||
>>> context.word_size = 32
|
||||
>>> context
|
||||
ContextType(arch = 'arm', bits = 32, endian = 'little', os = 'linux')
|
||||
>>> asm('nop')
|
||||
'\x00\xf0 \xe3'
|
||||
```
|
||||
```
|
||||
>>> asm('mov eax, 1')
|
||||
'\xb8\x01\x00\x00\x00'
|
||||
>>> asm('mov eax, 1').encode('hex')
|
||||
'b801000000'
|
||||
```
|
||||
请注意,这里我们生成了 i386 和 arm 两种不同体系结构的 `nop`,当你使用不同与本机平台的汇编时,需要安装该平台的 binutils,方法在上面已经介绍过了。
|
||||
|
||||
反汇编:(`pwnlib.asm.disasm`)
|
||||
```text
|
||||
>>> print disasm('\xb8\x01\x00\x00\x00')
|
||||
0: b8 01 00 00 00 mov eax,0x1
|
||||
>>> print disasm('6a0258cd80ebf9'.decode('hex'))
|
||||
0: 6a 02 push 0x2
|
||||
2: 58 pop eax
|
||||
3: cd 80 int 0x80
|
||||
5: eb f9 jmp 0x0
|
||||
```
|
||||
|
||||
构建具有指定二进制数据的 ELF 文件:(`pwnlib.asm.make_elf`)
|
||||
```text
|
||||
>>> context.clear(arch='amd64')
|
||||
>>> context
|
||||
ContextType(arch = 'amd64', bits = 64, endian = 'little')
|
||||
>>> bin_sh = asm(shellcraft.amd64.linux.sh())
|
||||
>>> bin_sh
|
||||
'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
|
||||
>>> filename = make_elf(bin_sh, extract=False)
|
||||
>>> filename
|
||||
'/tmp/pwn-asm-V4GWGN/step3-elf'
|
||||
>>> p = process(filename)
|
||||
[x] Starting local process '/tmp/pwn-asm-V4GWGN/step3-elf'
|
||||
[+] Starting local process '/tmp/pwn-asm-V4GWGN/step3-elf': pid 28323
|
||||
>>> p.sendline('echo hello')
|
||||
>>> p.recv()
|
||||
'hello\n'
|
||||
```
|
||||
这里我们生成了 amd64,即 64 位 `/bin/sh` 的 shellcode,配合上 asm 函数,即可通过 `make_elf` 得到 ELF 文件。
|
||||
|
||||
另一个函数 `pwnlib.asm.make_elf_from_assembly` 允许你构建具有指定汇编代码的 ELF 文件:
|
||||
```text
|
||||
>>> asm_sh = shellcraft.amd64.linux.sh()
|
||||
>>> print asm_sh
|
||||
/* execve(path='/bin///sh', argv=['sh'], envp=0) */
|
||||
/* push '/bin///sh\x00' */
|
||||
push 0x68
|
||||
mov rax, 0x732f2f2f6e69622f
|
||||
push rax
|
||||
mov rdi, rsp
|
||||
/* push argument array ['sh\x00'] */
|
||||
/* push 'sh\x00' */
|
||||
push 0x1010101 ^ 0x6873
|
||||
xor dword ptr [rsp], 0x1010101
|
||||
xor esi, esi /* 0 */
|
||||
push rsi /* null terminate */
|
||||
push 8
|
||||
pop rsi
|
||||
add rsi, rsp
|
||||
push rsi /* 'sh\x00' */
|
||||
mov rsi, rsp
|
||||
xor edx, edx /* 0 */
|
||||
/* call execve() */
|
||||
push SYS_execve /* 0x3b */
|
||||
pop rax
|
||||
syscall
|
||||
|
||||
>>> filename = make_elf_from_assembly(asm_sh)
|
||||
>>> filename
|
||||
'/tmp/pwn-asm-ApZ4_p/step3'
|
||||
>>> p = process(filename)
|
||||
[x] Starting local process '/tmp/pwn-asm-ApZ4_p/step3'
|
||||
[+] Starting local process '/tmp/pwn-asm-ApZ4_p/step3': pid 28429
|
||||
>>> p.sendline('echo hello')
|
||||
>>> p.recv()
|
||||
'hello\n'
|
||||
```
|
||||
与上一个函数不同的是,`make_elf_from_assembly` 直接从汇编生成 ELF 文件,并且保留了所有的符号,例如标签和局部变量等。
|
||||
|
||||
#### elf
|
||||
该模块用于 ELF 二进制文件的操作,包括符号查找、虚拟内存、文件偏移,以及修改和保存二进制文件等功能。(`pwnlib.elf.elf.ELF`)
|
||||
```text
|
||||
>>> e = ELF('/bin/cat')
|
||||
[*] '/bin/cat'
|
||||
Arch: amd64-64-little
|
||||
RELRO: Full RELRO
|
||||
Stack: Canary found
|
||||
NX: NX enabled
|
||||
PIE: PIE enabled
|
||||
>>> print hex(e.address)
|
||||
0x400000
|
||||
>>> print hex(e.symbols['write'])
|
||||
0x401680
|
||||
>>> print hex(e.got['write'])
|
||||
0x60b070
|
||||
>>> print hex(e.plt['write'])
|
||||
0x401680
|
||||
```
|
||||
上面的代码分别获得了 ELF 文件装载的基地址、函数地址、GOT 表地址和 PLT 表地址。
|
||||
|
||||
我们常常用它打开一个 libc.so,从而得到 system 函数的位置,这在 CTF 中是非常有用的:
|
||||
```text
|
||||
>>> e = ELF('/usr/lib/libc.so.6')
|
||||
[*] '/usr/lib/libc.so.6'
|
||||
Arch: amd64-64-little
|
||||
RELRO: Full RELRO
|
||||
Stack: Canary found
|
||||
NX: NX enabled
|
||||
PIE: PIE enabled
|
||||
>>> print hex(e.symbols['system'])
|
||||
0x42010
|
||||
```
|
||||
|
||||
我们甚至可以修改 ELF 文件的代码:
|
||||
```text
|
||||
>>> 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'
|
||||
```
|
||||
|
||||
下面是一些常用函数:
|
||||
- `asm(address, assembly)`:汇编指定指令并插入到 ELF 的指定地址处,需要使用 ELF.save() 保存
|
||||
- `bss(offset)`:返回 `.bss` 段加上 `offset` 后的地址
|
||||
- `checksec()`:打印出文件使用的安全保护
|
||||
- `disable_nx()`:关闭 NX
|
||||
- `disasm(address, n_bytes)`:返回对指定虚拟地址进行反汇编后的字符串
|
||||
- `offset_to_vaddr(offset)`:将指定偏移转换为虚拟地址
|
||||
- `vaddr_to_offset(address)`:将指定虚拟地址转换为文件偏移
|
||||
- `read(address, count)`:从指定虚拟地址读取 `count` 个字节的数据
|
||||
- `write(address, data)`:在指定虚拟地址处写入 `data`
|
||||
- `section(name)`:获取 `name` 段的数据
|
||||
- `debug()`:使用 `gdb.debug()` 进行调试
|
||||
|
||||
最后还要注意一下 `pwnlib.elf.corefile`,它用于处理核心转储文件(Core Dump),当我们在写利用代码时,核心转储文件是非常有用的,关于它更详细的内容已经在前面 Linux基础一章中讲过,这里我们还是使用那一章中的示例代码,但使用 pwntools 来操作。
|
||||
```
|
||||
>>> core = Corefile('/tmp/core-a.out-30555-1507796886')
|
||||
[x] Parsing corefile...
|
||||
[*] '/tmp/core-a.out-30555-1507796886'
|
||||
Arch: i386-32-little
|
||||
EIP: 0x565cd57b
|
||||
ESP: 0x4141413d
|
||||
Exe: '/home/firmy/a.out' (0x565cd000)
|
||||
Fault: 0x4141413d
|
||||
[+] Parsing corefile...: Done
|
||||
>>> core.registers
|
||||
{'xds': 43, 'eip': 1448924539, 'xss': 43, 'esp': 1094795581, 'xgs': 99, 'edi': 0, 'orig_eax': 4294967295, 'xcs': 35, 'eax': 1, 'ebp': 1094795585, 'xes': 43, 'eflags': 66182, 'edx': 4151195744, 'ebx': 1094795585, 'xfs': 0, 'esi': 4151189032, 'ecx': 1094795585}
|
||||
>>> print core.maps
|
||||
565cd000-565ce000 r-xp 1000 /home/firmy/a.out
|
||||
565ce000-565cf000 r--p 1000 /home/firmy/a.out
|
||||
565cf000-565d0000 rw-p 1000 /home/firmy/a.out
|
||||
57b3c000-57b5e000 rw-p 22000
|
||||
f7510000-f76df000 r-xp 1cf000 /usr/lib32/libc-2.26.so
|
||||
f76df000-f76e0000 ---p 1000 /usr/lib32/libc-2.26.so
|
||||
f76e0000-f76e2000 r--p 2000 /usr/lib32/libc-2.26.so
|
||||
f76e2000-f76e3000 rw-p 1000 /usr/lib32/libc-2.26.so
|
||||
f76e3000-f76e6000 rw-p 3000
|
||||
f7722000-f7724000 rw-p 2000
|
||||
f7724000-f7726000 r--p 2000 [vvar]
|
||||
f7726000-f7728000 r-xp 2000 [vdso]
|
||||
f7728000-f774d000 r-xp 25000 /usr/lib32/ld-2.26.so
|
||||
f774d000-f774e000 r--p 1000 /usr/lib32/ld-2.26.so
|
||||
f774e000-f774f000 rw-p 1000 /usr/lib32/ld-2.26.so
|
||||
ffe37000-ffe58000 rw-p 21000 [stack]
|
||||
>>> print hex(core.fault_addr)
|
||||
0x4141413d
|
||||
>>> print hex(core.pc)
|
||||
0x565cd57b
|
||||
>>> print core.libc
|
||||
f7510000-f76df000 r-xp 1cf000 /usr/lib32/libc-2.26.so
|
||||
```
|
||||
|
||||
#### dynelf
|
||||
`pwnlib.dynelf.DynELF`
|
||||
|
||||
该模块是专门用来应对无 libc 情况下的漏洞利用。它首先找到 glibc 的基地址,然后使用符号表和字符串表对所有符号进行解析,直到找到我们需要的函数的符号。这是一个有趣的话题,我们会专门开一个章节去讲解它。详见 *4.4 使用 DynELF 泄露函数地址*
|
||||
|
||||
#### fmtstr
|
||||
`pwnlib.fmtstr.FmtStr`,`pwnlib.fmtstr.fmtstr_payload`
|
||||
|
||||
该模块用于格式化字符串漏洞的利用,格式化字符串漏洞是 CTF 中一种常见的题型,我们会在后面的章节中详细讲述,关于该模块的使用也会留到那儿。详见 *3.3.1 格式化字符串漏洞*
|
||||
|
||||
#### gdb
|
||||
|
||||
#### memleak
|
||||
|
||||
#### shellcraft
|
||||
#### rop
|
||||
|
||||
#### util
|
||||
|
||||
|
30
src/Others/2.7_pwntools.sh
Normal file
30
src/Others/2.7_pwntools.sh
Normal file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
V = 2.29 # binutils version
|
||||
ARCH = arm # target architecture
|
||||
|
||||
cd /tmp
|
||||
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.xz
|
||||
wget -nc https://ftp.gnu.org/gnu/binutils/binutils-$V.tar.xz.sig
|
||||
|
||||
# gpg --keyserver keys.gnupg.net --recv-keys C3126D3B4AE55E93
|
||||
# gpg --verify binutils-$V.tar.xz.sig
|
||||
|
||||
tar xf binutils-$V.tar.xz
|
||||
|
||||
mkdir binutils-build
|
||||
cd binutils-build
|
||||
|
||||
export AR=ar
|
||||
export AS=as
|
||||
|
||||
../binutils-$V/configure \
|
||||
--prefix=/usr/local \
|
||||
--target=$ARCH-unknown-linux-gnu \
|
||||
--disable-static \
|
||||
--disable-multilib \
|
||||
--disable-werror \
|
||||
--disable-nls
|
||||
|
||||
make
|
||||
sudo make install
|
Loading…
Reference in New Issue
Block a user