Writeup: FlareOn 2020: 004 - report

Task description

1. TLDR

report graph

2. Dane wejściowe

Plik z zadaniem znajduje się tutaj. Hasło: flare.

Przedmiot zadania stanowi arkusz kalkulacyjny report.xls. Z treści zadania wiadomo, że znajduje się w nim makro, w którym ukryto flagę.

3. Inspekcja pliku report.xls

Zweryfikowałem plik narzędziem file:

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

Poniżej przedstawiłem arkusz po otwarciu w LibreOffice Calc:

Spreadsheet

Potwierdziłem istnienie makra, wykorzystując do tego celu narzędzie oleid:

$ 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. Inspekcja makra

W arkuszu faktycznie było wykorzystywane makro. W celu wykonania wstępnej analizy, uruchomiłem narzędzie olevba:

$ 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             |
+----------+--------------------+---------------------------------------------+

Narzędzie wylistowało używane funkcje, biblioteki oraz metody, których użycie zostało zaklasyfikowane jako podejrzane.

Na szczególną uwagę zasługuje informacja o wykorzystaniu metody VBA Stomping.

3.1 Pozyskanie makra

Wyodrębniłem makro w 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 Analiza makra: VBA

3.2.1 Funkcja rigmarole

Funkcja rigmarole odpowiadała za odkodowanie ciągów bajtów:

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

do postaci:

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 Funkcja canoodle

Funkcja canoodle odpowiadała za odszyfrowanie ciągu danych szyfrem Vernama.

3.2.3 Funkcja folderol

Funkcja folderol była główną funkcją makra, która była automatycznie uruchamiana po załadowaniu arkusza. Oprócz realizowania faktycznego zamiaru programisty, odpowiadała za weryfikację obecności połączenia sieciowego oraz detekcję wirtualnego środowiska uruchomieniowego. Mechanizm detekcji polegał na przeszukaniu listy procesów w celu ujawnienia obecności procesu zawierającego ciąg znaków “vmw”, “vmt” lub “vbox”.

Właściwą funkcjonalnością realizowaną przez funkcję folderol było:

Spreadsheet

3.2.4 Analiza pliku stomp.mp3

Odtworzyłem plik stomp.mp3, gdzie było słyszalne kilka tupnięć. Następnie odczytałem metadane z wykorzystaniem narzędzia exiftool:

$ 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)

Jeżeli do tej pory ktoś nie zauważył wykorzystania metody VBA Stomping, to w tym momencie można było odczytać dwie wskazówki:

3.3 Analiza makra: P-code - wariant 1

Wiedząc, że wykorzystano metodę VBA Stomping, odczytałem zdeasemblowany P-code:

$ pcodedmp report.xls | tee report.pcode

3.3.1 Ukryty kod makra

Manualnie przeprowadzona analiza różnicowa P-code’u oraz kodu VBA ujawniła fragment P-code’u:

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 Analiza ukrytego kodu

Analiza P-code pozwoliła odtworzyć możliwy kod VBA:

    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 Analiza makra: P-code - wariant 2

Wykorzystując narzędzie pcode2code.py, pozyskałem zdekompilowany do VBA kod P-code:

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

Analiza kodu VBA pozwoliła ustalić istotny fragment odpowiedzialny za poprawne odszyfrowanie szyfrogramu:

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. Odczytanie flagi

Moją uwagę zwrócił fakt, że klucz do odszyfrowania był wyznaczany z nazwy maszyny. Ponadto skrypt wymagał, żeby była to nazwa “FLARE-ON”.

Wykonałem zatem skrypt:

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

Jako skutek wykonania makra, został zapisany plik %AppData%\Microsoft\v.png, który zawierał flagę:

Flag