[WDB-2018] 网鼎杯Bin题部分writeup

说明

此writeup包含4场网鼎杯大部分bin题,exp和二进制文件见附录

场次

day1

RE

beijing, advanced, blend

PWN

guess, blind, babyheap, heylow, heylow2, hangman, easycoin

day2

RE

give_a_try, game, martricks, rua

PWN

fmt, fgo, hvm, memffle

day3

RE

最好的语言, SimpleSMC, babyre, i_like_pack

暂无i_like_back的二进制文件

PWN

note, note2, soEasy, pesp

day4

RE

chaoyang, compenc, dalao

PWN

impossible, ipowtn, ipowtn2

RE

beijing

脑洞题

把bytedump出来拿到
s = ‘aLgYi)nBb\reqf4j\xc6m\x8al\x7f{\xaez\x92}\xec_W’
通过函数调用顺序得到下列序号
a=[6, 9, 0, 1, 0xa, 0, 8, 0, 0xb, 2, 3, 1, 0xd, 4, 5, 2, 7, 2, 3, 1, 0xc]
s.find(‘f’), l, a, g得到[12, 18, 0, 2]
猜测flag为

1
2
3
4
5
6
s = 'aLgYi)nBb\reqf4j\xc6m\x8al\x7f{\xaez\x92}\xec_W'
a=[6, 9, 0, 1, 0xa, 0, 8, 0, 0xb, 2, 3, 1, 0xd, 4, 5, 2, 7, 2, 3, 1, 0xc]
ret = ''
for i in a:
ret += s[i*2]
print(ret)

advanced

blend

give_a_try

game

martricks

rua

PWN

guess

程序存在栈溢出,同时fork了3次,也就是nc一次可以猜测3次flag,这3次程序的地址都不会发生变化

考虑通过stack smashing detected leak数据

第一次覆盖argv为got表地址,leak出libc的地址,计算出environ的位置

第二次覆盖其为environ的地址,leak出栈的地址,计算出flag的位置

第三次直接覆盖为flag的位置,计算出flag的值

guess1

blind

blind是一个堆题,只允许malloc(0x68)的chunk,存在UAF,但是没有leak函数

考虑通过fastbin attack申请到bss段的内存,从而在bss段上伪造stdout的结构体以及其虚表,让他指向system(“/bin/sh”),从而getshell

伪造的stdout如图

blind1

伪造的虚表如图

blind

babyheap

UAF,只允许malloc(0x20)的chunk

在leak出堆的地址后,用fastbin attack修改现有chunk信息,可根据下图构造出unlink的条件

babyheap1

触发unlink后可以去除edit的次数限制,以及任意地址写,很容易leak出libc的基址,最后修改__malloc_hook为one_gadget即可

heylow & heylow2

程序比较大,但是有一个格式化字符串的漏洞,当输入出错时会触发报错,这时候会触发格式化字符串漏洞

heylow1.png

直接修改__free_hook为one_gadget然后使字符串很长触发malloc和free即可

heylow与heylow2的区别在于heylow2只允许printf小于0x4f的字符串,然而payload只要51 byte

所以一个payload可以打2个题

hangman

暂空

easycoin

暂空

fmt

本题存在格式化字符串漏洞

fmt1

修改got表为system然后printf/bin/sh即可getshell

fgo

堆题,存在UAF

fgo1

可以看到在free后指针并没有清空

覆盖函数指针为printf后leak出libc地址

随后覆盖为system地址即可getshell

hvm

这题是个虚拟机,逆向opcode结果为

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
rax x1
rbx x2
rcx x3
rdx x4
rsi x5
rdi x6

07 00 00 00
6F 0A 00 00 push 0xa6f

07 00 00 00
68 65 6C 6C push 0x6c6c6568 // push hello

0C 00 00 00 mov x5, stackptr // hello

18 00 00 00
00 00 00 01 mov x6, 0x1

04 00 00 00
00 00 00 06 mov x4, 0x6

01 00 00 00
00 00 00 01 mov x1, 0x1

0E 00 00 00 syscall

14 00 00 00 push pcoffset

05 00 00 00
00 00 00 0E jmp next 0xe // jmp tag

07 00 00 00
00 00 00 00 push 0

07 00 00 00
62 79 65 0A push 0xa657962 //bye\n

0C 00 00 00 mov x5, stackptr

18 00 00 00
00 00 00 01 mov x6, 0x1

04 00 00 00
00 00 00 06 mov x4, 0x6

01 00 00 00
00 00 00 01 mov x1, 0x1

0E 00 00 00 syscall

19 00 00 00 exit(0)

10 00 00 00 push stackbase // tag

11 00 00 00 mov stackbase, stackptr

0F 00 00 00
00 00 00 30 sub stackptr, 0x30

0C 00 00 00 mov x5, stackptr

18 00 00 00
00 00 00 00 mov x6, 0x0

04 00 00 00
00 00 00 F0 mov x4, 0xf0

01 00 00 00
00 00 00 00 mov x1, 0

0E 00 00 00 syscall

12 00 00 00 mov stackptr, stackbase

13 00 00 00 pop stackbase

06 00 00 00 jmp [stackptr]+3; pop //ret

发现其虚拟栈上存在栈溢出

看源码发现虚拟代码段和虚拟栈都是mmap出来的

hvm1.png

gdb调试发现buf_addr = stack_addr + 0x2000

考虑栈溢出将返回地址指向虚拟栈上,自己写入opcode后执行execve(‘/bin/sh’, NULL, NULL)

memffle

题目要求输入组数据,并对其进行随机排序,可以输入无数个数据导致栈溢出

其中随机数生成使用了

1
srand(time(0));

若是在连接的同时本地也以当前时间作为种子,若是时间是同步的话,本地也可以生成和远程相同的随机队列。

逆向后可以得到生成随机序列的算法为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def srand():
libc['srand'](libc['time'](0))

def rand():
return libc['rand']()
# 生成乱序序列
def shuffling(n):
srand()
ret = []
for i in xrange(n):
ret.append(i)
for i in xrange(n):
j = n - i - 1
v = rand() % (j + 1)
ret[j], ret[v] = ret[v], ret[j]
return ret

查看read函数发现其末尾没有置零,同时还存在1byte的溢出

memffle1.png

可以在输入名字时把buff填满从而leak出canary

发现题目送了1byte的system的地址

通常system地址为0xf7abcdef 其中def固定,给出了bc,可以爆破出剩下的半byte的地址

直接rop即可

note

note2

soEasy

pesp

附录

暂空