Flare-On 7 2020 Challenge #4: report
When I tried to open the report.xls file I received an error:
After pressing the “OK” button we received the Visual Basic code:
Private Declare Function InternetGetConnectedState Lib "wininet.dll" _
(ByRef dwflags As Long, ByVal dwReserved As Long) As LongPrivate Declare PtrSafe Function mciSendString Lib "winmm.dll" Alias _
"mciSendStringA" (ByVal lpstrCommand As String, ByVal _
lpstrReturnString As Any, ByVal uReturnLength As Long, ByVal _
hwndCallback As Long) As LongPrivate Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" _
(ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal lBuffer As Long) As LongPublic Function GetInternetConnectedState() As Boolean
GetInternetConnectedState = InternetGetConnectedState(0&, 0&)
End FunctionFunction rigmarole(es As String) As String
Dim furphy As String
Dim c As Integer
Dim s As String
Dim cc As Integer
furphy = ""
For i = 1 To Len(es) Step 4
c = CDec("&H" & Mid(es, i, 2))
s = CDec("&H" & Mid(es, i + 2, 2))
cc = c - s
furphy = furphy + Chr(cc)
Next i
rigmarole = furphy
End FunctionFunction folderol()
Dim wabbit() As Byte
Dim fn As Integer: fn = FreeFile
Dim onzo() As String
Dim mf As String
Dim xertz As Variant
onzo = Split(F.L, ".")
If GetInternetConnectedState = False Then
MsgBox "Cannot establish Internet connection.", vbCritical, "Error"
End
End IfSet fudgel = GetObject(rigmarole(onzo(7)))
Set twattling = fudgel.ExecQuery(rigmarole(onzo(8)), , 48)
For Each p In twattling
Dim pos As Integer
pos = InStr(LCase(p.Name), "vmw") + InStr(LCase(p.Name), "vmt") + InStr(LCase(p.Name), rigmarole(onzo(9)))
If pos > 0 Then
MsgBox rigmarole(onzo(4)), vbCritical, rigmarole(onzo(6))
End
End If
Next
xertz = Array(&H11, &H22, &H33, &H44, &H55, &H66, &H77, &H88, &H99, &HAA, &HBB, &HCC, &HDD, &HEE)wabbit = canoodle(F.T.Text, 0, 168667, xertz)
mf = Environ(rigmarole(onzo(0))) & rigmarole(onzo(1))
Open mf For Binary Lock Read Write As #fn
Put #fn, , wabbit
Close #fn
mucolerd = mciSendString(rigmarole(onzo(2)) & mf, 0&, 0, 0)
End FunctionFunction canoodle(panjandrum As String, ardylo As Integer, s As Long, bibble As Variant) As Byte()
Dim quean As Long
Dim cattywampus As Long
Dim kerfuffle() As Byte
ReDim kerfuffle(s)
quean = 0
For cattywampus = 1 To Len(panjandrum) Step 4
kerfuffle(quean) = CByte("&H" & Mid(panjandrum, cattywampus + ardylo, 2)) Xor bibble(quean Mod (UBound(bibble) + 1))
quean = quean + 1
If quean = UBound(kerfuffle) Then
Exit For
End If
Next cattywampus
canoodle = kerfuffle
End Function
We also have something that looks like a key and encrypted message:
Double click on of them shows there function name:
I extracted them to two files in GitHub because of their size:
Analyzing the Visual Basic Code
It’s time to understand what the code is doing. The main function is folderol
:
It starts by splitting F.L
to the array called onzo
. Later there are number of calls to rigmarole
function with onzo[<nub>]
while <num>
is being changed. It’s a decoded function, so I converted the code (the interesting parts) to Python code to be able to print some of its variables and understand them. For example, I used it to print all the decoded variables of onzo
:
onzo[0]: AppData
onzo[1]: \Microsoft\stomp.mp3
onzo[2]: play
onzo[3]: FLARE-ON
onzo[4]: Sorry, this machine is not supported.
onzo[5]: FLARE-ON
onzo[6]: Error
onzo[7]: winmgmts:\\.\root\CIMV2
onzo[8]: SELECT Name FROM Win32_Process
onzo[9]: vbox
onzo[10]: WScript.Network
onzo[11]: \Microsoft\v.png
Use them as a menu and the code is much more clear. The code is using WMI service to search for vmware process (“vmw” and “vmt”):
Then it writes something to file named “stomp.mp3” (onzo(1)
):
Notice that it uses the encrypted text of F.T.Text
with the function canoodle
which decrypts it.
This is our converted code to Python and it wrote the mp3 file:
with open(r'C:\tmp\flare2020\4\hex_T.txt', 'r') as f:
lines_t = f.read()
with open(r'C:\tmp\flare2020\4\hex_L.txt', 'r') as f:
lines_l = f.read()
def mid(s, offset, amount):
return s[offset:offset+amount]
def rigmarole(es):
furphy = ''
for i in range(0, len(es), 4):
c = int(mid(es, i, 2), 16)
s = int(mid(es, i+2, 2), 16)
cc = c - s
furphy = furphy + chr(cc)
return furphy
def canoodle(panjandrum, ardylo, s, bibble):
kerfuffle = [None]*s
quean = 0
for cattywampus in range(0, len(panjandrum), 4):
a = int(mid(panjandrum, cattywampus + ardylo, 2), 16)
b = bibble[quean % (len(bibble))]
result = a ^ b
kerfuffle[quean] = result
quean += 1
if quean == len(kerfuffle):
break
return kerfuffle
onzo = lines_l.split(".")
fudgel = rigmarole(onzo[7])
xertz = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE]
mp3 = canoodle(lines_t, 0, 168667, xertz)
with open(r'C:\tmp\flare2020\4\stomp2.mp3', 'wb') as f:
f.write(bytes(mp3))
MP3 file
When I played the MP3 file, it played some music, like mini march but that it. I thought maybe this is steganography but look the hint I saw when I played it:
It says something about P. Code.
P-Code
According to Wikipedia, P-Code is:
P-Code is a name for several of Microsoft’s proprietary intermediate languages.
So, I guess we need to see the P-Code of the visual basic code, maybe there is something hiding there.
I found a cool tool that decompile the code:
After installing and running the tool on the report.xls file, it decompiled it and you can view all the decompiled file here.
Finding hiding commands
I followed the code to see if there is something different from the visual basic code we saw in the beginning and I found new commands.
At line #55 I noticed to a new variable called firkin
and how it assigns it the name “FLARE-ON”:
Line #55:
Ld firkin
LitDI2 0x0003
ArgsLd onzo 0x0001
ArgsLd rigmarole 0x0001
Ne
IfBlock// firkin = rigmarole(onzo(3)) // 3 - "FLARE-ON"
At line #60 it calculates it length:
Line #60:
Ld firkin
FnLen
St n// n = Len(firkin)
At lines #61-#63, there is a loop that reverse the string “FLARE-ON” to “NO-ERALF”:
Line #61:
StartForVariable
Ld i
EndForVariable
LitDI2 0x0001
Ld n
For
Line #62:
Ld firkin
Ld i
LitDI2 0x0001
ArgsLd Mid$ 0x0003
ArgsLd Asc 0x0001
Ld n
Ld i
Sub
ArgsSt buff 0x0001
Line #63:
StartForVariable
Nextfor i = 1 To n
buff(n-i) = Asc(Mid(firkin,i,1))
# Print it the opposite:
"NO-ERALF"
The last piece is at line #65 when there is a call to canoodle
but with different arguments we saw in the beginning:
Line #65:
Ld F
MemLd T
MemLd Text
LitDI2 0x0002
LitDI4 0x5C21 0x0004
Ld buff
ArgsLd canoodle 0x0004
St wabbitcanoodle(F.T.Text, 2, 0x45C21, buff)
We re-wrote the Python script with these new details:
with open(r'C:\tmp\flare2020\4\hex_T.txt', 'r') as f:
lines_t = f.read()
with open(r'C:\tmp\flare2020\4\hex_L.txt', 'r') as f:
lines_l = f.read()
def mid(s, offset, amount):
return s[offset:offset+amount]
def rigmarole(es):
furphy = ''
for i in range(0, len(es), 4):
c = int(mid(es, i, 2), 16)
s = int(mid(es, i+2, 2), 16)
cc = c - s
furphy = furphy + chr(cc)
return furphy
def canoodle(panjandrum, ardylo, s, bibble):
kerfuffle = [None]*s
quean = 0
for cattywampus in range(0, len(panjandrum), 4):
a = int(mid(panjandrum, cattywampus + ardylo, 2), 16)
b = bibble[quean % (len(bibble))]
result = a ^ b
kerfuffle[quean] = result
quean += 1
if quean == len(kerfuffle):
break
return kerfuffle
# ASC function returns the ASCII value of a character or the first character in a string
buff = [None]*8
for i in range(0,8):
buff[7-i] = ord(mid('FLARE-ON',i,1))
png = canoodle(lines_t, 2, 0x45C21, buff)
with open(r'C:\tmp\flare2020\4\flag.png', 'wb') as f:
f.write(bytes(png))
The result is a PNG that contains the flag:
flag: thi5_cou1d_h4v3_b33n_b4d@flare-on.com