Hello, Worm!: Mapping SSH probes with a bash script
Tags: linux, bash, security
Published: 2019-05-08 00:00:53

*Please note this is meant to be more fun than serious security advice*

Contributing to [TLDR Pages](http://tldr-pages.github.io) has introduced me to tons of interesting and useful commands like `lastb`, which shows the details of failed login attempts. Of course you can't write good instructions for unfamiliar material so I ran `lastb -iw` on one of my AWS VMs and got a rather unpleasant surprise:

```
AWS_VM: sudo lastb -iw | wc -l 
967
```

967 failed logins? I know this wasn't me because I authorize with public keys. I doubt that this is a targeted attack because this VM doesn't have an aftermarket CNAME or publicized IP address. Are there really this many botnets in-flight? 

The nice people from GCP offer a no-strings micro VM for free, let's provision one and see how long it sits unmolested before it's probed for SSH 

```bash
GCP_VM: uptime
22:21:47 up 5 min,  1 user,  load average: 0.00, 0.00, 0.00
GCP_VM: lastb | wc -l 
2
```

Well this is a grim development: 5 minutes until the first SSH probe. I would like to see where these people are coming from, but don't want to waste my (very) limited resources on a dedicated honeypot; let's try for lightweight data collection on already-running VMs.

### Choose Your Weapon

• bash and awk can be considered part of the Linux firmament.  
• curl is pretty ubiquitous on interactive VMs.  
• https://mapbox.io graciously offers an SVG mapping API with a free-tier.  
• https://ipstack.com offers an IP address geolocation API with a free-tier.  

To avoid overwhelming the goodwill of these API providers, we will restrict our queries to IPs that probed our VM in the last 24 hours.


```bash
#!/bin/bash

# Set token data here. Because requests want a token in the URL,
# a .netrc file can't be used to store credentials
#
IPSTACK_TOKEN=""
MAPBOX_TOKEN=""

# Get a timestamp of 24 hours ago in epoch seconds
#
STANDOFF=$(date -d "24 hours ago" +%s)

# Capture failed logins with a timestamp < 24-hours-ago to a buffer file
#
sudo lastb -i | awk '{ print $3,$5,$6,$7 }' | while read ip datum
do
  [[ "$(date -d "$datum" +%s)" -gt "$STANDOFF" ]] && echo -e "$ip"
done > /tmp/LASTB_IP_BUFFER

# Get the top 150 IPs by connection count
sort /tmp/LASTB_IP_BUFFER | uniq -c | sort -rnk1 | awk '{ print $2,$1 }' | head -150 | while read IP time
do
    # Get Lat/Long data
    curl -s "http://api.ipstack.com/$IP?access_key=$IPSTACK_TOKEN&fields=longitude,latitude" | python -m json.tool | awk '/longitude|latitude/ { printf $NF" " }' | tr -d "," | awk '$1 != "null" { print "pin-s+0FF("$2","$1")," }'

# Smush all coordinates into a string to make a single call to Mapbox.io
done | tr -d "\n" | sed -e 's/,$//g' > /tmp/coords

curl -s "https://api.mapbox.com/styles/v1/mapbox/dark-v10/static/"$(cat /tmp/coords)"/0,40,1.35,0/1280x1024?access_token=$MAPBOX_TOKEN" > worms.png

rm /tmp/LASTB_IP_BUFFER /tmp/coords
```

And here we have a handsome world map with pins stuck in every probing botnet's source-IP location, suitable for framing or scaring your boss.

![](https://thepracticaldev.s3.amazonaws.com/i/vsy3sg6ts4ww67ogosmn.png)