My SSH Server Became a Target in a Global Cybersecurity Scuffle

March 23, 2025 - 2 min read

Many years ago, I wrote about how random computers all over the world were trying to crack my SSH server.

Background

What is this video showing?

While I was away from home for college, I still wanted to access my files on my personal computer at home. Perhaps foolishly, I decided to port forward an SSH server through my parent’s comcast router. I did my best to secure the server - disabling password logins and keeping the service up to date. Even so, I noticed many failed login attempts in the logs:

May 20 11:51:06 MyComputer sshd[20393]: User root from 121.18.238.XXX not allowed because not listed in AllowUsers |

Locations

In conjunction with ip-api.com, I can take the IP address from the above log and estimate a location:

{
   "status": "success",
   "country": "China",
   "countryCode": "CN",
   "region": "HE",
   "regionName": "Hebei",
   "city": "Zhangjiakou",
   "zip": "075000",
   "lat": 40.7687,
   "lon": 114.886,
   "timezone": "Asia/Shanghai",
   "isp": "CNC Group CHINA169 Hebei Province Network",
   "org": "",
   "as": "AS4837 CHINA UNICOM China169 Backbone",
   "query": "121.18.238.XXX"
}

This presented an interesting opportunity, what if I could take all these failed requests, and then produce a map of where all these requests are coming from?

Map of attacks from across the world

If I had the code, I’d provide it. Regardless, it’s a fairly straight forward implementation. Regex for IP addresses, convert to GPS coordinates, and then plot those on a map of the world.

Finally, my script updated my site’s git to published the image.

Making the animation

The time lapse was fairly easy to put together.

First, I used the code I found here to create a frame for every version of the file in my git repo.

I also had to change the names of the files into something I could work with (i.e. frame_0001.png).

for file in "${sorted_files[@]}"; do     new_name=$(printf "frame_%04d.png" "$count");     mv -- "$file" "$new_name";     count=$((count + 1)); done

Second, I ran ffmpeg to compile the frames into a single video.

fmpeg -framerate 10 -i /tmp/all_versions_exported/frame_%04d.png -vf "crop=iw:ih-mod(ih\,2)" -c:v libx264 -pix_fmt yuv420p output.mp4

Next, I had to reverse the video so that it was properly chronological.

ffmpeg -i output.mp4 -vf "reverse" -af "areverse" reversed_output.mp4

Finally, I added the music.

ffmpeg -i reversed_output.mp4 -i output.wav -c copy -map 0:v:0 -map 1:a:0 final.mp4

As an additional step, I used VLC to properly encode the video (YouTube wouldn’t accept it otherwise).

My time lapse was good to go!

Conclusion

I have a few regrets from this project. Firstly, I failed to save any of the code that I wrote to generate these maps. Secondly, is not keeping the raw data to create more detailed graphs and visualizations.

Finally, this project has taught me that fail2ban, a tool that bans any IP address that fails to login too many times, would go a long way to secure something like an SSH server.


© 2025 - Curtis Lowder