0%

pwn基础知识,持续更新

pwntools

process & remote

1
2
3
p = process(binary.path)

r=remote('google.com', 80)

context

1
2
3
4

exe = context.binary = ELF('./challenge-binary') #方便与asm()函数连用,找shellcode

context.log_level='debug' #所有交互的数据以十六进制显示

send、sendline、recv、recvutil、recvrepeate、recvline

1
2
3
4
5
6
7
8
9
10
11
p.send()

p.sendline('111') #发送数据,并在最后加上\n

p.recv(numb=4096, timeout=default)

recvrepeat(timeout=default) #接收到EOF或timeout

p.recvutil('abc') #直到接收到abc

p.recvline() #接收数据到换行

ELF

方便查看信息,如got、plt表等

1
2
3
4
5
6
7
8
9
>>> e = ELF('/bin/cat')
>>> print hex(e.address)
0x400000
>>> print hex(e.symbols['write'])
0x401680
>>> print hex(e.got['write'])
0x60b070
>>> print hex(e.plt['write'])
0x401680

cyclic

1
2
3
cyclic n    #生成n个字符,默认32位(-c参数改动),所以任意四个连续字符是独一无二的

cyclinc -l 0x61616166 #查找偏移

attach

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Attach directly to pid 1234
gdb.attach(1234)


# Attach to the youngest "bash" process
gdb.attach('bash')


# Start a process
bash = process('bash')

# Attach the debugger
gdb.attach(bash, '''
set follow-fork-mode child
break execve
continue
''')

# Interact with the process
bash.sendline('whoami')


# Start a forking server
server = process(['socat', 'tcp-listen:1234,fork,reuseaddr', 'exec:/bin/sh'])

# Connect to the server
io = remote('localhost', 1234)

# Connect the debugger to the server-spawned process
gdb.attach(io, '''
break exit
continue
''')

# Talk to the spawned 'sh'
io.sendline('exit')


# Connect to the SSH server
shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)

# Start a process on the server
cat = shell.process(['cat'])

# Attach a debugger to it
gdb.attach(cat, '''
break exit
continue
''')

# Cause `cat` to exit
cat.close()

pwn template

生成exp的模板

参考链接

GDB

通用

x

1
x/20wx 0x4005fe

查看address的内容,20为个数(数字可省略),w为四字节,可改为b/h/g(1/2/8字节),第二个x代表十六进制,可改为u/d/s/i(unsigned int/10进制/字符串/指令),空格后门是地址

set

1
set *address = value #将address的值设置成value,一次设置4 byte

*可以替换成{char/short/long},分别设定1/2/8 byte;也可以给寄存器设值

e.g.

1
set {int}0x0804a060 = 1337

peda

  • elfsymbol
    • 查看function .plt表
    • ROP需要
  • vvmap
    • 查看process mapping
    • 虚拟内存的权限,r=读,w=写,x=执行,s=共享,p=私有
  • readelf
    • 查看session位置
    • ret2dl_resolve需要
  • find
    • search memory里的pattern
      • 通常用来找字符串 e.g. find /bin/sh
  • record

ROP

rp++

ROPgadget

–ropchain 仅适用于静态链接

pwntools rop模块

代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
import time

bss_addr =
proc= './binary'
context.binary = proc
shellcode = asm(shellcraft.sh())

p = process(proc)

p.recvuntil('')

rop = ROP(proc)
rop.read(0,bss_addr+0x100,len(shellcode))
rop.call(bss_addr + 0x100)

p.sed('a'*20 + str(rop))
time.sleep(1)
p.send(shellcode)

p.interactive()

tips

  • read、write函数的文件描述符:标准输入(standard input)是 0,标准输出(standard output)是 1,标准错误(standard error)是 2

查看libc版本

远程

  • libcdb.com

  • Libc-database(github上的一个项目,没有前面网址全)

本地

  • ldd binary 可以看到binary使用的libc库文件

objdump

1
objdump -R binary

查看binary符号表的信息

Segment

在程序执行时才有的概念,基本会根据读写执行权限及特性分为数个segmnet,e.g. rodata、data、code、stack、heap等

  • data:rw-
  • code:r-x
  • stack:rw-
  • heap:rw-

x86 assembly

lea & mov

e.g.

1
2
3
4
5
6
7
8
lea/mov eax,[eax + 4]

eax = 3
esp + 4 = 0xbfff7488
[esp + 4] = 0xdeadbeef

lea: eax = 0xbfff7488
mov: eax = 0xdeadbeef

leave

mv ebp,esp
pop ebp

syscalls

int 0x80 即中断处理函数,用于处理 system_call

  • 操作系统实现系统调用的基本过程是
    1. 应用程序调用库函数(API)
    2. API将系统调用号存入EAX,然后通过中断调用使系统进入内核态
    3. 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用)
    4. 系统调用完成相应功能,将返回值存入EAX,返回到中断处理函数
    5. 中断处理函数返回到API中
    6. API将EAX返回给应用程序