Writeup: FlareOn 2020: 004 - report

Task description

1. TLDR

report graph

2. Input data

The challenge file is here. Password: flare.

The subject of the task is the report.xls spreadsheet. From the content of the task it is known that there is a macro with a flag hidden in it.

3. Inspection of report.xls file

I verified the file using file tool:

$ file report.xls  
report.xls: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, Code page: 1252, 0x17: 1048576CDFV2 Microsoft Excel

Below is the spreadsheet when opened in LibreOffice Calc:

Spreadsheet

I confirmed the existence of the macro using the oleid tool:

$ oleid report.xls
oleid 0.54 - http://decalage.info/oletools
THIS IS WORK IN PROGRESS - Check updates regularly!
Please report any issue at https://github.com/decalage2/oletools/issues

Filename: report.xls
 Indicator                      Value   
 OLE format                     True    
 Has SummaryInformation stream  False   
 Application name               unknown 
 Encrypted                      False   
 Word Document                  False   
 VBA Macros                     True    
 Excel Workbook                 True    
 PowerPoint Presentation        False   
 Visio Drawing                  False   
 ObjectPool                     False   
 Flash objects                  0  

3. Inspection of macro

A macro was actually used in the sheet. In order to perform an initial analysis, I launched the olevba tool:

$ olevba --analysis report.xls
olevba 0.55.1 on Python 2.7.17 - http://decalage.info/python/oletools
===============================================================================
FILE: report.xls
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO ThisWorkbook.cls 
in file: report.xls - OLE stream: u'_VBA_PROJECT_CUR/VBA/ThisWorkbook'
-------------------------------------------------------------------------------
VBA MACRO Sheet1.cls 
in file: report.xls - OLE stream: u'_VBA_PROJECT_CUR/VBA/Sheet1'
-------------------------------------------------------------------------------
VBA MACRO F.frm 
in file: report.xls - OLE stream: u'_VBA_PROJECT_CUR/VBA/F'
-------------------------------------------------------------------------------
VBA MACRO VBA_P-code.txt 
in file: VBA P-code - OLE stream: 'VBA P-code'
-------------------------------------------------------------------------------
VBA FORM STRING IN 'report.xls' - OLE stream: u'_VBA_PROJECT_CUR/F/o'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
�9655B040B64667238524D15D6201.B95D4E01C55CC562C7557405A532D768C55FA12DD074DC697
...
C14B7C4E8F1F8F21CB64
-------------------------------------------------------------------------------
VBA FORM STRING IN 'report.xls' - OLE stream: u'_VBA_PROJECT_CUR/F/o'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
H�,�p
-------------------------------------------------------------------------------
VBA FORM STRING IN 'report.xls' - OLE stream: u'_VBA_PROJECT_CUR/F/o'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
58c7661f00634702555f664b7756884c864edc4fef2d9c48881bac0911082214334e424f552f661
...
4c0046004e00060068000b001600ef000e002600cc
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |Auto_Open           |Runs when the Excel Workbook is opened       |
|AutoExec  |Workbook_Open       |Runs when the Excel Workbook is opened       |
|Suspicious|CreateObject        |May create an OLE object                     |
|Suspicious|Environ             |May read system environment variables        |
|Suspicious|Write               |May write to a file (if combined with Open)  |
|Suspicious|Put                 |May write to a file (if combined with Open)  |
|Suspicious|Open                |May open a file                              |
|Suspicious|Lib                 |May run code from a DLL                      |
|Suspicious|Chr                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Xor                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Binary              |May read or write a binary file (if combined |
|          |                    |with Open)                                   |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|IOC       |wininet.dll         |Executable file name                         |
|IOC       |winmm.dll           |Executable file name                         |
|Suspicious|VBA Stomping        |VBA Stomping was detected: the VBA source    |
|          |                    |code and P-code are different, this may have |
|          |                    |been used to hide malicious code             |
+----------+--------------------+---------------------------------------------+

The tool has enumerated the functions, libraries and methods used, the use of which was classified as suspicious.

Particularly noteworthy is the information on the use of the VBA Stomping method .

3.1 Macro acquisition

I’ve extracted a macro in VBA:

$ olevba --code report.xls | tee report.vbs

Kod VBA zamieściłem poniżej:

olevba 0.55.1 on Python 2.7.17 - http://decalage.info/python/oletools
===============================================================================
FILE: report.xls
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO ThisWorkbook.cls 
in file: report.xls - OLE stream: u'_VBA_PROJECT_CUR/VBA/ThisWorkbook'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub Workbook_Open()
Sheet1.folderol
End Sub

Sub Auto_Open()
Sheet1.folderol
End Sub
-------------------------------------------------------------------------------
VBA MACRO Sheet1.cls 
in file: report.xls - OLE stream: u'_VBA_PROJECT_CUR/VBA/Sheet1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Private Declare Function InternetGetConnectedState Lib "wininet.dll" _
(ByRef dwflags As Long, ByVal dwReserved As Long) As Long

Private 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 Long

Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" _
    (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal lBuffer As Long) As Long

Public Function GetInternetConnectedState() As Boolean
  GetInternetConnectedState = InternetGetConnectedState(0&, 0&)
End Function

Function 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 Function

Function 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 If

    Set 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 Function

Function 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

3.2 Macro analysis: VBA

3.2.1 rigmarole function

The rigmarole function was responsible for decoding sequences of bytes:

9655B040B64667238524D15D6201
B95D4E01C55CC562C7557405A532D768C55FA12DD074DC697A06E172992CAF3F8A5C7306B7476B38
C555AC40A7469C234424
853FA85C470699477D3851249A4B9C4E
A855AF40B84695239D24895D2101D05CCA62BE5578055232D568C05F902DDC74D2697406D7724C2CA83FCF5C2606B547A73898246B4BC14E941F9121D464D263B947EB77D36E7F1B8254
853FA85C470699477D3851249A4B9C4E
9A55B240B84692239624
CC55A940B44690238B24CA5D7501CF5C9C62B15561056032C468D15F9C2DE374DD696206B572752C8C3FB25C3806
A8558540924668236724B15D2101AA5CC362C2556A055232AE68B15F7C2DC17489695D06DB729A2C723F8E5C65069747AA389324AE4BB34E921F9421
CB55A240B5469B23
AC559340A94695238D24CD5D75018A5CB062BA557905A932D768D15F982D
D074B6696F06D5729E2CAE3FCF5C7506AD47AC388024C14B7C4E8F1F8F21CB64

to the form:

AppData
\Microsoft\stomp.mp3
play 
FLARE-ON
Sorry, this machine is not supported.
FLARE-ON
Error
winmgmts:\\.\root\CIMV2
SELECT Name FROM Win32_Process
vbox
WScript.Network
\Microsoft\v.png

3.2.2 canoodle function

The canoodle function was responsible for decrypting the data string with the Vernam cipher.

3.2.3 folderol function

The folderol function was the main macro function that was automatically run when the sheet was loaded. In addition to implementing the actual intention of the programmer, it was responsible for verifying the presence of a network connection and detecting the virtual runtime environment. The detection mechanism consisted in searching the list of processes to reveal the presence of a process containing the string “vmw”, “vmt” or “vbox”.

The actual functionality realized by the folderol function was:

Spreadsheet

3.2.4 Analysis stomp.mp3 file

I played the file stomp.mp3 where I heard a few thumps. Then I read the metadata using the exiftool tool:

$ exiftool stomp.mp3
ExifTool Version Number         : 12.00
File Name                       : stomp.mp3
Directory                       : .
File Size                       : 165 kB
File Modification Date/Time     : 2020:09:21 20:59:31+02:00
File Access Date/Time           : 2020:09:21 20:59:31+02:00
File Inode Change Date/Time     : 2020:09:21 20:59:31+02:00
File Permissions                : rw-r--r--
File Type                       : MP3
File Type Extension             : mp3
MIME Type                       : audio/mpeg
MPEG Audio Version              : 1
Audio Layer                     : 3
Audio Bitrate                   : 160 kbps
Sample Rate                     : 44100
Channel Mode                    : Joint Stereo
MS Stereo                       : Off
Intensity Stereo                : Off
Copyright Flag                  : False
Original Media                  : False
Emphasis                        : None
ID3 Size                        : 4096
Publisher                       : FLARE
Year                            : 2020
Title                           : This is not what you should be looking at...
Band                            : P. Code
Date/Time Original              : 2020
Duration                        : 8.23 s (approx)

If until now you did not notice the use of the VBA Stomping method, at this point can be read two tips:

3.3 Macro analysis: P-code - option no. 1

Knowing that the VBA Stomping method was used, I read the disassembled P-code:

$ pcodedmp report.xls | tee report.pcode

3.3.1 Hidden macro code

Manually performed differential analysis of the P-code and the VBA code revealed the following fragment of the P-code:

Line #53:
	SetStmt 
	LitDI2 0x000A 
	ArgsLd onzo 0x0001 
	ArgsLd rigmarole 0x0001 
	ArgsLd CreateObject 0x0001 
	Set groke 
Line #54:
	Ld groke 
	MemLd UserDomain 
	St firkin 
Line #55:
	Ld firkin 
	LitDI2 0x0003 
	ArgsLd onzo 0x0001 
	ArgsLd rigmarole 0x0001 
	Ne 
	IfBlock 
Line #56:
	LitDI2 0x0004 
	ArgsLd onzo 0x0001 
	ArgsLd rigmarole 0x0001 
	Ld vbCritical 
	LitDI2 0x0006 
	ArgsLd onzo 0x0001 
	ArgsLd rigmarole 0x0001 
	ArgsCall MsgBox 0x0003 
Line #57:
	End 
Line #58:
	EndIfBlock 
Line #59:
Line #60:
	Ld firkin 
	FnLen 
	St n 
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 
	Next 
Line #64:
Line #65:
	Ld F 
	MemLd T 
	MemLd Text 
	LitDI2 0x0002 
	LitDI4 0x5C21 0x0004 
	Ld buff 
	ArgsLd canoodle 0x0004 
	St wabbit 
Line #66:
	LitDI2 0x0000 
	ArgsLd onzo 0x0001 
	ArgsLd rigmarole 0x0001 
	ArgsLd Environ 0x0001 
	LitDI2 0x000B 
	ArgsLd onzo 0x0001 
	ArgsLd rigmarole 0x000"FLARE-ON"1 
	Concat 
	St mf 

3.3.2 Hidden code analysis

P-code analysis allowed to restore possible VBA code:

    Set groke = CreateObject("WScript.Network")
    Dim firkin As String
    firkin = groke.UserDomain

    If firkin <> "FLARE-ON" Then
        MsgBox rigmarole(onzo(4)), vbCritical, rigmarole(onzo(6))
        End
    End If
    
    Dim n As Integer
    n = Len(firkin)
    For i = 1 To n
        buff(n - i) = Asc(Mid(firkin, i, 1))
    Next
        
    wabbit = canoodle(F.T.Text, 2, 285729, buff)
    mf = Environ("AppData") & "\Microsoft\v.png"

3.4 Macro analysis: P-code - option no. 2

Using the pcode2code.py tool, I obtained the P-code decompiled into VBA:

$ python /home/remnux/.local/lib/python2.7/site-packages/pcode2code/pcode2code.py report.xls | tee report.pcode2vba

The analysis of the VBA code allowed to establish an important fragment responsible for the correct decryption of the ciphertext:

Set groke = CreateObject(rigmarole(onzo(10)))
firkin = groke.UserDomain
If firkin <> rigmarole(onzo(3)) Then
  MsgBox rigmarole(onzo(4)), vbCritical, rigmarole(onzo(6))
  End
End If

n = Len(firkin)
For i = 1 To n
  buff(n - i) = Asc(Mid$(firkin, i, 1))
Next

wabbit = canoodle(F.T.Text, 2, 285729, buff)
mf = Environ(rigmarole(onzo(0))) & rigmarole(onzo(11))

4. Reading the flag

I pay attention to the fact that the key to decrypt was determined from the machine name. Also, the script required it to be “FLARE-ON”.

So I executed the script:

Function folderol()
    Dim wabbit() As Byte
    Dim fn As Integer: fn = FreeFile
    Dim mf As String
    Dim buff(0 To 7) As Byte

    Dim firkin As String
    firkin = "FLARE-ON"
    
    Dim n As Integer
    n = Len(firkin)
    For i = 1 To n
        buff(n - i) = Asc(Mid(firkin, i, 1))
    Next
        
    wabbit = canoodle(F.T.Text, 2, 285729, buff)
    mf = Environ("AppData") & "\Microsoft\v.png"
    Open mf For Binary Lock Read Write As #fn
      Put #fn, , wabbit
    Close #fn
End Function

As a result of executing the macro, the %AppData%\Microsoft\v.png file was saved, which contained the flag:

Flag