关于缓冲区溢出的对策

ⅰ亾dé卋堺 提交于 2020-01-10 04:03:55

从编译器的角度出发

以下两种方法均是编译器采取的关于缓冲区溢出的对策

Stackshield

主要思想是在函数调用之前,将return address的副本保存在一个安全的地方,函数返回时将返回地址与预先保存的返回地址比较,以判断缓冲区溢出是否发生。

StackGuard

在返回地址和缓冲区之间添加一段guard区,该guard区中可以由编译器存放一些不可预测的值,利用该guard区的值是否被篡改,若被篡改了,则可推断返回地址被修改,即可判断缓冲区溢出发生。在gcc编译器中,可以使用 -fno-stack-protector 来关闭SyackGuard。

在这里插入图片描述

利用如下代码探究StackGuard机制:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void copy(char *str)
{
	char buffer[12];
	strcpy(buffer,str);
}
int main(int argc,char *argv[])
{
	copy(argv[1]);
	printf("Return Properly\n");
	return 1;
}

针对以上代码,在默认条件下编译以后(StackGuard机制开启),输入小于12字节参数时程序正常,当输入大于12字节,由于StackGuad机制,发现缓冲区溢出重现,故程序崩溃。
在这里插入图片描述
查看汇编代码,可以看到如下

	.file	"stackGuardTest.c"
	.text
	.globl	copy
	.type	copy, @function
copy:
.LFB5:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$48, %rsp
	movq	%rdi, -40(%rbp)
	movq	%fs:40, %rax
	movq	%rax, -8(%rbp)
	xorl	%eax, %eax
	movq	-40(%rbp), %rdx
	leaq	-20(%rbp), %rax
	movq	%rdx, %rsi
	movq	%rax, %rdi
	call	strcpy@PLT
	nop
	movq	-8(%rbp), %rax
	xorq	%fs:40, %rax
	je	.L2
	call	__stack_chk_fail@PLT
.L2:
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE5:
	.size	copy, .-copy
	.section	.rodata
.LC0:
	.string	"Return Properly"
	.text

可以看到这样一段代码,它的作用是从fs寄存器指向的内存的偏移为40的地方取8字节数组到rax寄存器中(可见guard值存储在gs:40处),并且将其存放在rbp-8处,故可以看出guard在当前gcc版本中起始地址位rbp-8.(不同版本的gcc可能不一样,我的是gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)

movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax

同时查看如下汇编代码,可以看到在函数返回时,从rbp-8处取出值存放在rax寄存器中,并且将该值与fs:20处的值比较,若相同则正常返回,若不同则调用__stack_chk_fail@PLT。这边是stackguard的实现。

     movq -8(%rbp), %rax
     xorq %fs:40, %rax
     je .L2
     call __stack_chk_fail@PLT
.L2:
     leave
     .cfi_def_cfa 7, 8
     ret

从操作系统角度

ASLR

Address Space Layout Randomization,即地址空间布局随机化,基本思想是将stack的起始位置随机化,使得一段代码在执行时,其变量的逻辑地址不再固定,这样攻击者便很难准确猜测其嵌入的shellcode的逻辑地址。
在linux上,可以通过如下命令设置ASLR,

sudo sysctl -w kernel.randomize_va_space=(数值)

数值部分可以为0、1、2
(1)数值部分为0:关闭ASLR
(2)数值部分为1:只为栈开启ASLR
(3)数值部分为2:为栈和堆均开启ASLR

NX

NX即No-eXecute,是CPU采取的一项区分代码和数据的技术,操作系统可以标记特定的内存区域,使该区域不可执行,则处理器不会执行该区域内的然和代码。在gcc中,可以使用noexecstack选项开启NX,execstack关闭NX。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!