Deobfuscating Ostap Downloader

Recently, our team has noticed a slight uptick in malicious Word documents using Ostap to deliver a TrickBot payload. These documents tend to have a low detection rate and are very fussy about running in a sandbox. In order to get a better idea of how they work, we needed to deobfuscate the downloader by hand.

The Malicious Word Document

The Ostap downloader is delivered inside a Microsoft Word Document (.doc) which contains a VBA macro and JScript in the body of the document. The JScript is hidden as white text, as you can see by the document word and page count. The macro basically executes the JSE and is not that important to look at in-depth in this case.

The JScript

We can simply highlight the white text and copy it into another document in order to read it. As JScript is very similar to JavaScript in its syntax, we can use a JavaScript beautify tool to get it in an easier to read format.

The code contains a lot of garbage variables and logic intended to throw off analysis, though at the bottom of the screenshot you can see an­ interesting string being built containing “fromCharCode”. Searching the code for any calls to the function “qzxRabn” yields around 1600 results, so it looks like character codes are being passed to this function, which is then building strings from them.

We can see some basic maths is being performed, and finally “qzxRabn” is called with two arguments; a few of these functions are chained together, so eventually the variable “UcqfAbeing53” will contain a string.

  • Variable “Doil99” is always 2100, meaning “Doil99” – “Doil99” / 3 will always be 1400
  • Function “qzxRabnTrf” always returns 0

Simplifying the arguments on line 113 gives us return qzxRabn((70 – 1), 76) which will return the character E.

Testing this theory with the full code block above spells out Error: great, it looks like we are getting somewhere. Unfortunately, there are thousands of functions which decode each letter of the deobfuscated script, and we do not want to decode each one manually. There is a pattern in each function though: they all use the same variable “Doil99” as an array index, and they all set the two indexes in the same order; so all we need to do is pull each one out of the obfuscated code and calculate the character code finally being sent to “qzxRabn”. Once we have all of the character codes we can simply decode them ourselves.

In order to do this quickly, we wrote two small regex queries to extract the values being set. They are as follows: Note this regex was run on non-beautified code; adjust spacing for beautified code.

/(?<=\[Doil99-\(Doil99\/3\)\]=)[^ ;]+/g

/(?<=\[Doil99\]=)[^ ;]+/g

Once we have the values extracted, 1671 pairs in total, we can simply put them in a spreadsheet and subtract one from the other.

Finally, we can convert the character codes to plaintext to reveal the deobfuscated script containing the final payload URL.

The Final Payload – TrickBot

We won’t go into the working of TrickBot here, but it’s safe to say the final payload is TrickBot. The JScript downloads a purposefully broken Base64 encoded binary.

This can be fixed by performing a find and replace on the string “aKamaZi”, replacing the string with nothing.

Running the fixed binary in a sandbox, we can see that TrickBot is delivered as expected.


doc f2f00bc1337ff5634835158c438fdb3d
Payload e8dcd4cb9b5ba0c8dadebe251788f386
Payload URL hxxp://185[.]216[.]35[.]24/atB3n/M8lvg.php?
TrickBot e8dcd4cb9b5ba0c8dadebe251788f386
TrickBot config cf7f12006a4665673ace9a69d2ecbfd1