For this challenge, we’re provided a file “fun.docm”, with the extension implying that we’ll be having (no)fun with macros!

After opening the document, we’re presented with the text “MORE MACROS = MORE FUN” in large color-changing font with a lovely air-horn sound that plays on repeat. Attempting to open the VB Project reveals that it’s password protected, so we’ll need to bypass this first.

As the new format for Doc files are archives, we’ll open it up in 7z and look for the ‘vbaProject.bin’ file under the ‘\word\’ directory. Open this up in a hex editor and search for the string ‘DPB=”’ then simply change it to something like ‘DPX=”’ and save the file. When you load the file now you’ll receive an error about the project containing an invalid key with an option to continue loading it anyway. Now you’ll be able to access the VB Project and can go into the Project Properties and unselect ‘Lock project for viewing’ to remove the password protection.

Looking at the project, we can see that there are two forms, ‘NpuXrzgq’ and ‘U8pblvDZuAh8Gy’, along with one module ‘Z1yiWeP’. Looking at the code in the main document and the module, it looks like there are a lot of functions so we’ll start by debugging it and get a feel for what it’s trying to do. Putting a ‘Stop’ after the initial ‘Document_Open()’ function starts the process.

Before even getting into the meat of the macro we can see we may have a problem as it’s checking if there are four ‘VBcomponents’ when we only have three. Stepping through the ‘zkceuV405Q5LjUp587OYxTI7OR9zTyPdvz8k’ function, we find this to be the series of events that decode the embedded WAV file and continuously play the air-horn while changing the text in the document.

If we adjust the code so it doesn’t fail the first check, we follow the macro to ‘XiqyXdC809pP5esSrC633ag92w0x6otQylY0’ function, which immediately calls ‘zoycqKJvqznJMeMpHe7Z61xYJfLLmbObxBVy’ and then begins to enumerate the function names.

The function ‘BqNFmKCS7cTPv9XNFOd2mCLrdqCfmdNm6HBz’ begins a process of base-64 decoding the function name and then modifying the byte-values based on various fields of the document.

Both of the functions are one-byte XoR’s, 44 and 32 respectively, which then get compared to the base-64 decoded value of ‘U8pblvDZuAh8GY.Label1.Caption’, which is ‘xRgWTqWr7ipEjFBfESrOiaYFu9i9Jml3Q171’.

Based on this, we can grab all of the function names and quickly determine the match by base64 decoding each and XoR’ing the bytes by 44 and 32.

>>> a = base64.b64decode("yRQaQqmn4iZIgFxTHSbChaoJt9SxKmV7T1L5")
>>> b = base64.b64decode("xRgWTqWr7ipEjFBfESrOiaYFu9i9Jml3Q171")
>>> b
'\xc5\x18\x16N\xa5\xab\xee*D\x8cP_\x11*\xce\x89\xa6\x05\xbb\xd8\xbd&iwC^\xf5'
>>> c = ""
>>> for i in a:
...     c += chr(ord(i) ^ 44 ^ 32)
...
>>> c
'\xc5\x18\x16N\xa5\xab\xee*D\x8cP_\x11*\xce\x89\xa6\x05\xbb\xd8\xbd&iwC^\xf5'

Now that we have our interesting function name, we can force the macro to use this value and continue debugging it.

Back in the ‘XiqyXdC809pP5esSrC633ag92w0x6otQylY0’ function, it will take another function name, ‘d7KRoSK5UEDh35jJNkj0TtcJjOIbmBZlyCql’ and pass it along with our matching name to another function, which base64 decodes ‘d7KRoSK5UEDh35jJNkj0TtcJjOIbmBZlyCql’ into an array before sending us to function ‘XWn5TNdoykQb0QoitVEG7sLOxIRSi97XmqmM’ which has a ‘MsgBox’ call, presumably to print our flag!

Looking at the function we can see there are a few more XoR and comparison checks against property values for the forms within the VBProject.

At this point it XoR’s the ‘d7KRoSK5UEDh35jJNkj0TtcJjOIbmBZlyCql’ function name by 144 and 85, takes the result of that and XoR’s it against the base-64 decoded value of ‘XJCR/DogZt7bduvvusJgAQu6QX9DmtKN+bZB’ to see if they match…which they won’t.

Since we know two parts of the puzzle, we can just work backwards to figure out what the initial second function name should be and go from there. We’ll base-64 decode the ‘XJCR’ string and ‘yRQa’ string, XoR them together, then XoR each resulting byte by 144 and 85.

>>> a = base64.b64decode("yRQaQqmn4iZIgFxTHSbChaoJt9SxKmV7T1L5")
>>> b = base64.b64decode("XJCR/DogZt7bduvvusJgAQu6QX9DmtKN+bZB")
>>> c = ""
>>> for index,value in enumerate(a):
...     c += chr((ord(value) ^ ord(b[index])) ^ 144 ^ 85)
...
>>> c
'PAN{VBA=V3ryb!gAdv3n7ur3s!}'

‘PAN{VBA=V3ryb!gAdv3n7ur3s!}’