Rating: 5.0

Task

> A deadly virus was released, can you decipher its contents?
>
> /!\ Real malware sample, be careful
>
> Attachment: update.zip

Category: Practical

First things first:

```bash
$ unzip update.zip
$ file update
update: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, Code page: 1252, Title: Repellendus., Template: Normal.dotm, Revision Number: 1, Name of Creating Application: Microsoft Office Word, Create Time/Date: Tue Sep 15 17:11:00 2020, Last Saved Time/Date: Fri Sep 25 13:47:00 2020, Number of Pages: 1, Number of Words: 4, Number of Characters: 24, Security: 0
```

Well, malware + Word Document, then probably = macrovirus.

With no Microsoft Office in sight, lets find something else to analyze this sample. [Oletools](https://github.com/decalage2/oletools) is the first result we get on Altavista.

> oletools - python tools to analyze MS OLE2 files (Structured Storage, Compound File Binary Format) and MS Office documents, for malware analysis, forensics and debugging.

Inside [Oletools](https://github.com/decalage2/oletools) we have [olevba](https://github.com/decalage2/oletools/wiki/olevba) that is a...

> ... script to parse OLE and OpenXML files such as MS Office documents (e.g. Word, Excel), to detect VBA Macros, extract their source code in clear text, and detect security-related patterns such as auto-executable macros, suspicious VBA keywords used by malware, anti-sandboxing and anti-virtualization techniques, and potential IOCs (IP addresses, URLs, executable filenames, etc). It also detects and decodes several common obfuscation methods including Hex encoding, StrReverse, Base64, Dridex, VBA expressions, and extracts IOCs from decoded strings.

A command line tool written in python. Lovely!

So here we go...

```bash
virtualenv -p python3 venv
. venv/bin/activate
pip3 install oletools
olevba update > olevba.log
cat olevba.log
```

We get a long report from this tool. Almost 3k lines long:

```
olevba 0.56 on Python 3.7.3 - http://decalage.info/python/oletools
===============================================================================
FILE: update
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO Xhx92_rprjsbz.cls
in file: update - OLE stream: 'Macros/VBA/Xhx92_rprjsbz'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Private Sub CheckCreds_Click()
If txtUsername.Text = "admin" And txtPassword.Text = "1234" Then
MsgBox "Great! The flag is EKO{}", vbOKOnly, "Right!"
Else
MsgBox "Oops!", vbCritical, "Wrong!"
End If
End Sub
-------------------------------------------------------------------------------
VBA MACRO Hpsd9g_lf27k5l2ku.frm
in file: update - OLE stream: 'Macros/VBA/Hpsd9g_lf27k5l2ku'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Private Sub CheckCreds_Click()
If txtUsername.Text = "admin" And txtPassword.Text = "1234" Then
MsgBox "Great! The flag is EKO{}", vbOKOnly, "Right!"
Else
MsgBox "Oops!", vbCritical, "Wrong!"
End If
End Sub
-------------------------------------------------------------------------------
VBA MACRO VBA_P-code.txt
in file: VBA P-code - OLE stream: 'VBA P-code'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Processing file: update
' ===============================================================================
' Module streams:
' Macros/VBA/Xhx92_rprjsbz - 2089 bytes
' Line #0:
' LineCont 0x0004 02 00 00 00
' FuncDefn (Sub Document_open())
' Line #1:
' Ld Vrp7b4xtd7xq1ofe_n
' LitStr 0x002E "Gidy0bs0we474V4k8fu6h59cvq31wn F7pz34r6u5bola5"
' Add

...

-------------------------------------------------------------------------------
VBA FORM Variable "b'Jfuz55y9lj1'" IN 'update' - OLE stream: 'Macros/Hpsd9g_lf27k5l2ku'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
b'tu'
-------------------------------------------------------------------------------
VBA FORM Variable "b'Rwoat0n0ugte3'" IN 'update' - OLE stream: 'Macros/Hpsd9g_lf27k5l2ku'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
b'Wssxu7hazphw'
+----------+--------------------+---------------------------------------------+
|Type |Keyword |Description |
+----------+--------------------+---------------------------------------------+
|AutoExec |Document_open |Runs when the Word or Publisher document is |
| | |opened |
|AutoExec |CheckCreds_Click |Runs when the file is opened and ActiveX |
| | |objects trigger events |
|Suspicious|Create |May execute file or a system command through |
| | |WMI |
|Suspicious|showwindow |May hide the application |
|Suspicious|CreateObject |May create an OLE object |
|Suspicious|Chr |May attempt to obfuscate specific strings |
| | |(use option --deobf to deobfuscate) |
|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 first parts (`Macros/VBA/Xhx92_rprjsbz`, `Macros/VBA/Hpsd9g_lf27k5l2ku`) are classic VB macros, really easy to understand and we get nothing relevant from them.

We then get a lot of VBA P-Code and a table detailing some things (strings, mostly) that olevba found suspicious.

If the first blocks were easy, then trying to understand the P-Code is another thing. So we go back again to Excit-- err, Altavista in search of something to make thing a little bit easier for us.

Luckily there's [pcode2code](https://pypi.org/project/pcode2code/):

> ... To be able to analyze such "stomped" documents, Dr. Bontchev (@VessOnSecurity) released pcodedmp, a tool printing out the VBA bytecode of a document in a readable manner. However, the output might be still hardly readable and analyzable (please check out macaroni in tests folder). As such, pcode2code decompiles, based on pcodedmp's output, the VBA code.

I'll say kudos to Philippe Lagadec, Nicolas Zilio & Dr. Bontchev for their brave fight against VBA obfuscation.

```bash
pip3 install -U pcode2code
olevba --code --show-pcode update > update.pcode # extract p-code only
pcode2code -p update.pcode -o update.vbsource # reconvert to source code
cat update.vbsource
```

Now, this is better.

```
stream : ' Macros/VBA/Xhx92_rprjsbz - 2089 bytes
########################################

stream : ' Macros/VBA/Hpsd9g_lf27k5l2ku - 21823 bytes
########################################

stream : Macros/VBA/Xhx92_rprjsbz - 2089 bytes
########################################

Sub Document_open()
Q6mb0h8sd2svvfz = Array(Vrp7b4xtd7xq1ofe_n + "Gidy0bs0we474V4k8fu6h59cvq31wn F7pz34r6u5bola5" + Xv6h65qbofvov1i, Thy9qdbsqlaagqxc36, Hpsd9g_lf27k5l2ku.Ntqlz_4vvxnddx, D3g2pqnlwicj5vbyd + "Wf4tn2t5p70ss S6divrjsc4pkobg D4u271cwophwas C1qu0s4dwdoca")
End Sub
Sub Kfgl49jnmfs3()
Md9lkj23nb = Chr(109) & Chr(69) & Chr(125) & Chr(99) & Chr(75) & Chr(48) & Chr(123) & Chr(79) & Chr(52) & Chr(100) & Chr(108)
KLsjnj309nnnf = Mid(Md9lkj23nb, 2, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 5, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 8, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 7, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 1, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 9, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 11, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 10, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 6, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 4, 1)
KLsjnj309nnnf = KLsjnj309nnnf & Mid(Md9lkj23nb, 3, 1)
MsgBox(KLsjnj309nnnf)
End Sub
stream : Macros/VBA/Hpsd9g_lf27k5l2ku - 21823 bytes
########################################

Function Ntqlz_4vvxnddx(id_FFFE As Variant)
On Error Resume Next
Set O19rsczr9gng = Xhx92_rprjsbz.Signatures
wzWrspw = "jlXBPtd1 f6AkKoQjzwGjCbLvuk73QJc1lSazWAa"
CMPYjuYGVj = Mid(wzWrspw, 21, 1)
ipiirDE = CMPYjuYGVj
mlmaRVf = "v05iZdfKC W47oI0B29OrzT"
nShDLRmDHl = Mid(mlmaRVf, 7, 1)

...
```

Function `Ntqlz_4vvxnddx()` is quite long, and after that function there are some more with similar content. The first subprocess `Document_open()` is the one that we think it is executed, well, when the user opens that document. The second subprocess `Kfgl49jnmfs3()` sounds interesting, as it shows a `MsgBox()`.

Lets try to translate this into something more palatable:

- the [`Chr()` function in VBA](https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/chr-function) is similar to Python's own `chr()` function,
- the [`&` operator in VBA](https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/ampersand-operator) concatenates strings, as the `+` does in Python,
- the [`Mid()` function](https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/mid-function) extracts fragments from string, like the slice operator (but keep in mind that in VBA, indexes start at 1),
- finally, we'll replace `MsgBox()` with `print`.

So the whole block turns to be something like

```python
def Kfgl49jnmfs3():
Md9lkj23nb = chr(109) + chr(69) + chr(125) + chr(99) + chr(75) + chr(48) + chr(123) + chr(79) + chr(52) + chr(100) + chr(108)
KLsjnj309nnnf = Md9lkj23nb[1] # one less than in VBA source
KLsjnj309nnnf = KLsjnj309nnnf + Md9lkj23nb[4] # ibid.
KLsjnj309nnnf = KLsjnj309nnnf + Md9lkj23nb[7] # "
KLsjnj309nnnf = KLsjnj309nnnf + Md9lkj23nb[6]
...
```

that, for the sake of brevity, I'll turn into

```python
Md9lkj23nb = chr(109) + chr(69) + chr(125) + chr(99) + chr(75) + chr(48) + chr(123) + chr(79) + chr(52) + chr(100) + chr(108)
KLsjnj309nnnf = ''
for i in (2, 5, 8, 7, 1, 9, 11, 10, 6, 4, 3):
KLsjnj309nnnf += Md9lkj23nb[i - 1]
print(KLsjnj309nnnf)
```

Flag: `EKO{m4ld0c}`