Excel Maldocs: Hidden Sheets

Published: 2020-03-08
Last Updated: 2020-03-08 23:01:42 UTC
by Didier Stevens (Version: 1)
8 comment(s)

Sheets in Excel workbooks can be hidden. To unhide them, right-click a sheet tab and select "Unhide":

Xavier wrote a diary entry about a malicious Excel spreadsheet with Excel 4 macros. Opening the spreadsheet inside a VM, he did not see an Excel 4 macros sheet, nor could he unhide one:

The reason is the following. When you use my tool oledump.py with plugin plugin_biff, you can see that Xavier's malicious Excel 4.0 macro sheet is "very hidden".

The byte value at position 5 in a BOUNDSHEET record defines the visibility of a sheet: visible (0x00), hidden (0x01) or very hidden (0x02).

Visible and hidden can be toggled with Excel's GUI (right-click menu), but very hidden not.

You have a couple of options to make a very hidden sheet visible:

  • Use a tool like ShowSheets
  • Change a sheet's visible property programmatically
  • Use VBE
  • Use a hex editor (in this example, search for 3A 84 01 00 02 01 0A 00 and replace 02 with 00)
  • ...

Please post a comment if you know other methods.

 

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com

Keywords:
8 comment(s)

Comments

With this “very hidden” attribute, are typical AV vendors able to still detect the malicious code?
Interesting question. I would expect AVs to have no problem with this setting, but it's something I should test to be 100% sure.
The xls file can be converted into a xlsx file. Unzip it. Then, you will find the malicious code is stored in one of the XML files.
In the status bar Libre Office / Open Office shows the number of sheete, including "xlVeryHidden".

With Powershell (for xlsm set the "Application.AutomationSecurity"):

$Exc = new-object -ComObject Excel.Application

$WB = $Exc.workbooks.open("C:\Temp\Sheets_visible.xlsx")
$WB.sheets | Select-Object -Property Name, visible

$WB.close()
$Exc.Quit()
You can also set (or read) this attribute in python using openpyxl.

ws.sheet_state = 'veryHidden'

You can still enumerate them from openpyxl and it will show the Very Hidden worksheet so you could script something to enumerate sheet names, read their sheet_state and then act on any returning 'veryHidden'.
Turns out the hex string to search for doesn't work for all sheets. The first two bytes can be removed. I used '01 00 02 01 0A 00' as the search for 4 new xls documents that came through and was able to change the 02 to 00 and successfully read the 'very hidden' sheet.

dsplice
That is correct dsplice, the first 2 bytes are an offset to the sheet records themselves, and thus this will be different for every sheet.
I wrote a Powershell script
https://github.com/denk-core/ExcelSheetUnhide
This is simple command line tool with error handling that sets the Visible property of the Excel ComObject, while using the “AutomationSecurity” property on opening.
Full documentation on switches and features with usage case scenario examples is available.

Diary Archives