<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Open Source &#8211; hackanooga</title>
	<atom:link href="/category/open-source/feed/" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>Confessions of a homelab hacker</description>
	<lastBuildDate>Wed, 25 Sep 2024 13:56:04 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.2</generator>

<image>
	<url>/wp-content/uploads/2024/03/cropped-cropped-avatar-32x32.png</url>
	<title>Open Source &#8211; hackanooga</title>
	<link>/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Standing up a Wireguard VPN</title>
		<link>/standing-up-a-wireguard-vpn/</link>
		
		<dc:creator><![CDATA[mikeconrad]]></dc:creator>
		<pubDate>Wed, 25 Sep 2024 13:56:04 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Self Hosted]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[SSH]]></category>
		<category><![CDATA[Blog Post]]></category>
		<guid isPermaLink="false">/?p=619</guid>

					<description><![CDATA[VPN&#8217;s have traditionally been slow, complex and hard to set up and configure. That all changed several years ago when Wireguard was officially merged into the mainline Linux kernel (src). I won&#8217;t go over all the reasons for why you should want to use Wireguard in this article, instead I will be focusing on just [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>VPN&#8217;s have traditionally been slow, complex and hard to set up and configure.  That all changed several years ago when Wireguard was officially merged into the mainline Linux kernel (<a href="https://arstechnica.com/gadgets/2020/03/wireguard-vpn-makes-it-to-1-0-0-and-into-the-next-linux-kernel/" data-type="link" data-id="https://arstechnica.com/gadgets/2020/03/wireguard-vpn-makes-it-to-1-0-0-and-into-the-next-linux-kernel/">src</a>).  I won&#8217;t go over all the reasons for why you should want to use Wireguard in this article, instead I will be focusing on just how easy it is to set up and configure. </p>



<p>For this tutorial we will be using Terraform to stand up a Digital Ocean droplet and then install Wireguard onto that. The Digital Ocean droplet will be acting as our &#8220;server&#8221; in this example and we will be using our own computer as the &#8220;client&#8221;. Of course, you don&#8217;t have to use Terraform, you just need a Linux box to install Wireguard on.  You can find the code for this tutorial on my personal Git server <a href="https://git.hackanooga.com/mikeconrad/wireguard-terraform-digitalocean" data-type="link" data-id="https://git.hackanooga.com/mikeconrad/wireguard-terraform-digitalocean">here</a>.</p>



<h3 class="wp-block-heading">Create Droplet with Terraform</h3>



<p>I have written some very basic Terraform to get us started. The Terraform is very basic and just creates a droplet with a predefined ssh key and a setup script passed as user data.  When the droplet gets created, the script will get copied to the instance and automatically executed.  After a few minutes everything should be ready to go.  If you want to clone the repo above, feel free to, or if you would rather do everything by hand that&#8217;s great too.  I will assume that you are doing everything by hand.  The process of deploying from the repo should be pretty self explainitory.  My reasoning for doing it this way is because I wanted to better understand the process.  </p>



<p>First create our main.tf with the following contents:</p>



<pre class="wp-block-code"><code># main.tf
# Attach an SSH key to our droplet
resource "digitalocean_ssh_key" "default" {
  name       = "Terraform Example"
  public_key = file("./tf-digitalocean.pub")
}

# Create a new Web Droplet in the nyc1 region
resource "digitalocean_droplet" "web" {
  image    = "ubuntu-22-04-x64"
  name     = "wireguard"
  region   = "nyc1"
  size     = "s-2vcpu-4gb"
  ssh_keys = &#91;digitalocean_ssh_key.default.fingerprint]
  user_data = file("setup.sh")
}

output "droplet_output" {
  value = digitalocean_droplet.web.ipv4_address
}</code></pre>



<p>Next create a terraform.tf file in the same directory with the following contents:</p>



<pre class="wp-block-code"><code>terraform {
  required_providers {
    digitalocean = {
      source  = "digitalocean/digitalocean"
      version = "2.41.0"
    }
  }
}

provider "digitalocean" {
}
</code></pre>



<p>Now we will need to create the ssh key that we defined in our Terraform code.  </p>



<pre class="wp-block-code"><code>$ ssh-keygen -t rsa -C "WireguardVPN" -f ./tf-digitalocean -q -N ""</code></pre>



<p>Next we need to set an environment variable for our DigitalOcean access token.</p>



<pre class="wp-block-code"><code>$ export DIGITALOCEAN_ACCESS_TOKEN=dop_v1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code></pre>



<p>Now we are ready to initialize our Terraform and apply it:</p>



<pre class="wp-block-code"><code>$ terraform init
$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.web will be created
  + resource "digitalocean_droplet" "web" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + graceful_shutdown    = false
      + id                   = (known after apply)
      + image                = "ubuntu-22-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "wireguard"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "nyc1"
      + resize_disk          = true
      + size                 = "s-2vcpu-4gb"
      + ssh_keys             = (known after apply)
      + status               = (known after apply)
      + urn                  = (known after apply)
      + user_data            = "69d130f386b262b136863be5fcffc32bff055ac0"
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

  # digitalocean_ssh_key.default will be created
  + resource "digitalocean_ssh_key" "default" {
      + fingerprint = (known after apply)
      + id          = (known after apply)
      + name        = "Terraform Example"
      + public_key  = &lt;&lt;-EOT
            ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXOBlFdNqV48oxWobrn2rPt4y1FTqrqscA5bSu2f3CogwbDKDyNglXu8RL4opjfdBHQES+pEqvt21niqes8z2QsBTF3TRQ39SaHM8wnOTeC8d0uSgyrp9b7higHd0SDJVJZT0Bz5AlpYfCO/gpEW51XrKKeud7vImj8nGPDHnENN0Ie0UVYZ5+V1zlr0BBI7LX01MtzUOgSldDX0lif7IZWW4XEv40ojWyYJNQwO/gwyDrdAq+kl+xZu7LmBhngcqd02+X6w4SbdgYg2flu25Td0MME0DEsXKiZYf7kniTrKgCs4kJAmidCDYlYRt43dlM69pB5jVD/u4r3O+erTapH/O1EDhsdA9y0aYpKOv26ssYU+ZXK/nax+Heu0giflm7ENTCblKTPCtpG1DBthhX6Ml0AYjZF1cUaaAvpN8UjElxQ9r+PSwXloSnf25/r9UOBs1uco8VDwbx5cM0SpdYm6ERtLqGRYrG2SDJ8yLgiCE9EK9n3uQExyrTMKWzVAc= WireguardVPN
        EOT
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + droplet_output = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

digitalocean_ssh_key.default: Creating...
digitalocean_ssh_key.default: Creation complete after 1s &#91;id=43499750]
digitalocean_droplet.web: Creating...
digitalocean_droplet.web: Still creating... &#91;10s elapsed]
digitalocean_droplet.web: Still creating... &#91;20s elapsed]
digitalocean_droplet.web: Still creating... &#91;30s elapsed]
digitalocean_droplet.web: Creation complete after 31s &#91;id=447469336]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

droplet_output = "159.223.113.207"
</code></pre>



<p>All pretty standard stuff.  Nice!  It only took about 30 seconds or so on my machine to spin up a droplet and start provisioning it.  It is worth noting that the setup script will take a few minutes to run.  Before we log into our new droplet, let&#8217;s take a quick look at the setup script that we are running.</p>



<pre class="wp-block-code"><code>#!/usr/bin/env sh
set -e
set -u
# Set the listen port used by Wireguard, this is the default so feel free to change it.
LISTENPORT=51820
CONFIG_DIR=/root/wireguard-conf
umask 077
mkdir -p $CONFIG_DIR/client

# Install wireguard
apt update &amp;&amp; apt install -y wireguard

# Generate public/private key for the "server".
wg genkey > $CONFIG_DIR/privatekey
wg pubkey &lt; $CONFIG_DIR/privatekey > $CONFIG_DIR/publickey

# Generate public/private key for the "client"
wg genkey > $CONFIG_DIR/client/privatekey
wg pubkey &lt; $CONFIG_DIR/client/privatekey > $CONFIG_DIR/client/publickey


# Generate server config
echo "&#91;Interface]
Address = 10.66.66.1/24,fd42:42:42::1/64
ListenPort = $LISTENPORT
PrivateKey = $(cat $CONFIG_DIR/privatekey)

### Client config
&#91;Peer]
PublicKey = $(cat $CONFIG_DIR/client/publickey)
AllowedIPs = 10.66.66.2/32,fd42:42:42::2/128
" > /etc/wireguard/do.conf


# Generate client config.  This will need to be copied to your machine.
echo "&#91;Interface]
PrivateKey = $(cat $CONFIG_DIR/client/privatekey)
Address = 10.66.66.2/32,fd42:42:42::2/128
DNS = 1.1.1.1,1.0.0.1

&#91;Peer]
PublicKey = $(cat publickey)
Endpoint = $(curl icanhazip.com):$LISTENPORT
AllowedIPs = 0.0.0.0/0,::/0
" > client-config.conf

wg-quick up do

# Add iptables rules to forward internet traffic through this box
# We are assuming our Wireguard interface is called do and our
# primary public facing interface is called eth0.

iptables -I INPUT -p udp --dport 51820 -j ACCEPT
iptables -I FORWARD -i eth0 -o do -j ACCEPT
iptables -I FORWARD -i do -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
ip6tables -I FORWARD -i do -j ACCEPT
ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Enable routing on the server
echo "net.ipv4.ip_forward = 1
      net.ipv6.conf.all.forwarding = 1" >/etc/sysctl.d/wg.conf
sysctl --system</code></pre>



<p>As you can see, it is pretty straightforward.  All you really need to do is:</p>



<p>On the &#8220;server&#8221; side:</p>



<ol class="wp-block-list">
<li>Generate a private key and derive a public key from it for both the &#8220;server&#8221; and the &#8220;client&#8221;.</li>



<li>Create a &#8220;server&#8221; config that tells the droplet what address to bind to for the wireguard interface, which private key to use to secure that interface and what port to listen on.</li>



<li>The &#8220;server&#8221; config also needs to know what peers or &#8220;clients&#8221; to accept connections from in the AllowedIPs block.  In this case we are just specifying one.  The &#8220;server&#8221; also needs to know the public key of the &#8220;client&#8221; that will be connecting.</li>
</ol>



<p>On the &#8220;client&#8221; side:</p>



<ol class="wp-block-list">
<li>Create a &#8220;client&#8221; config that tells our machine what address to assign to the wireguard interface (obviously needs to be on the same subnet as the interface on the server side).</li>



<li>The client needs to know which private key to use to secure the interface.</li>



<li>It also needs to know the public key of the server as well as the public IP address/hostname of the &#8220;server&#8221; it is connecting to as well as the port it is listening on.  </li>



<li>Finally it needs to know what traffic to route over the wireguard interface.  In this example we are simply routing all traffic but you could restrict this as you see fit.</li>
</ol>



<p>Now that we have our configs in place, we need to copy the client config to our local machine.  The following command should work as long as you make sure to replace the IP address with the IP address of your newly created droplet:</p>



<pre class="wp-block-code"><code>## Make sure you have Wireguard installed on your local machine as well.
## https://wireguard.com/install

## Copy the client config to our local machine and move it to our wireguard directory.
$ ssh -i tf-digitalocean root@157.230.177.54 -- cat /root/wireguard-conf/client-config.conf| sudo tee /etc/wireguard/do.conf</code></pre>



<p>Before we try to connect, let&#8217;s log into the server and make sure everything is set up correctly:</p>



<pre class="wp-block-code"><code>$ ssh -i tf-digitalocean root@159.223.113.207
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-113-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
 * Management:     https://landscape.canonical.com/
 * Support:        https://ubuntu.com/pro

 System information as of Wed Sep 25 13:19:02 UTC 2024

  System load:  0.03              Processes:             113
  Usage of /:   2.1% of 77.35GB   Users logged in:       0
  Memory usage: 6%                IPv4 address for eth0: 157.230.221.196
  Swap usage:   0%                IPv4 address for eth0: 10.10.0.5

Expanded Security Maintenance for Applications is not enabled.

70 updates can be applied immediately.
40 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

New release '24.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


Last login: Wed Sep 25 13:16:25 2024 from 74.221.191.214
root@wireguard:~#

</code></pre>



<p>Awesome!  We are connected.  Now let&#8217;s check the wireguard interface using the <code>wg</code> command.  If our config was correct, we should see an interface line and 1 peer line like so.  If the peer line is missing then something is wrong with the configuration.  Most likely a mismatch between public/private key.:</p>



<pre class="wp-block-code"><code>root@wireguard:~# wg
interface: do
  public key: fTvqo/cZVofJ9IZgWHwU6XKcIwM/EcxUsMw4voeS/Hg=
  private key: (hidden)
  listening port: 51820

peer: 5RxMenh1L+rNJobROkUrub4DBUj+nEUPKiNe4DFR8iY=
  allowed ips: 10.66.66.2/32, fd42:42:42::2/128
root@wireguard:~# </code></pre>



<p>So now we should be ready to go!  On your local machine go ahead and try it out:</p>



<pre class="wp-block-code"><code>## Start the interface with wg-quick up &#91;interface_name]
$ sudo wg-quick up do
&#91;sudo] password for mikeconrad: 
&#91;#] ip link add do type wireguard
&#91;#] wg setconf do /dev/fd/63
&#91;#] ip -4 address add 10.66.66.2/32 dev do
&#91;#] ip -6 address add fd42:42:42::2/128 dev do
&#91;#] ip link set mtu 1420 up dev do
&#91;#] resolvconf -a do -m 0 -x
&#91;#] wg set do fwmark 51820
&#91;#] ip -6 route add ::/0 dev do table 51820
&#91;#] ip -6 rule add not fwmark 51820 table 51820
&#91;#] ip -6 rule add table main suppress_prefixlength 0
&#91;#] ip6tables-restore -n
&#91;#] ip -4 route add 0.0.0.0/0 dev do table 51820
&#91;#] ip -4 rule add not fwmark 51820 table 51820
&#91;#] ip -4 rule add table main suppress_prefixlength 0
&#91;#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
&#91;#] iptables-restore -n

## Check our config
$ sudo wg
interface: do
  public key: fJ8mptCR/utCR4K2LmJTKTjn3xc4RDmZ3NNEQGwI7iI=
  private key: (hidden)
  listening port: 34596
  fwmark: 0xca6c

peer: duTHwMhzSZxnRJ2GFCUCHE4HgY5tSeRn9EzQt9XVDx4=
  endpoint: 157.230.177.54:51820
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 1 second ago
  transfer: 1.82 KiB received, 2.89 KiB sent

## Make sure we can ping the outside world
mikeconrad@pop-os:~/projects/wireguard-terraform-digitalocean$ ping 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=56 time=28.0 ms
^C
--- 1.1.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 27.991/27.991/27.991/0.000 ms

## Verify our traffic is actually going over the tunnel.
$ curl icanhazip.com
157.230.177.54


</code></pre>



<p>We should also be able to ssh into our instance over the VPN using the <code>10.66.66.1</code> address:</p>



<pre class="wp-block-code"><code>$ ssh -i tf-digitalocean root@10.66.66.1
The authenticity of host '10.66.66.1 (10.66.66.1)' can't be established.
ED25519 key fingerprint is SHA256:E7BKSO3qP+iVVXfb/tLaUfKIc4RvtZ0k248epdE04m8.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:130: &#91;hashed name]
Are you sure you want to continue connecting (yes/no/&#91;fingerprint])? yes
Warning: Permanently added '10.66.66.1' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-113-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
 * Management:     https://landscape.canonical.com/
 * Support:        https://ubuntu.com/pro

 System information as of Wed Sep 25 13:32:12 UTC 2024

  System load:  0.02              Processes:             109
  Usage of /:   2.1% of 77.35GB   Users logged in:       0
  Memory usage: 6%                IPv4 address for eth0: 157.230.177.54
  Swap usage:   0%                IPv4 address for eth0: 10.10.0.5

Expanded Security Maintenance for Applications is not enabled.

73 updates can be applied immediately.
40 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

New release '24.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


root@wireguard:~# 
</code></pre>



<p>Looks like everything is working!  If you run the script from the repo you will have a fully functioning Wireguard VPN in less than 5 minutes!  Pretty cool stuff!  This article was not meant to be exhaustive but instead a simple primer to get your feet wet.  The setup script I used is heavily inspired by <a href="https://github.com/angristan/wireguard-install">angristan/wireguard-install</a>.  Another great resource is the <a href="https://github.com/pirate/wireguard-docs" data-type="link" data-id="https://github.com/pirate/wireguard-docs">Unofficial docs repo</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SFTP Server Setup for Daily Inventory File Transfers</title>
		<link>/sftp-server-setup-for-daily-inventory-file-transfers/</link>
		
		<dc:creator><![CDATA[mikeconrad]]></dc:creator>
		<pubDate>Wed, 17 Jul 2024 02:15:23 +0000</pubDate>
				<category><![CDATA[Cloudflare]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Self Hosted]]></category>
		<category><![CDATA[Upwork Project]]></category>
		<guid isPermaLink="false">/?p=599</guid>

					<description><![CDATA[Job Description We are looking for an experienced professional to help us set up an SFTP server that will allow our vendors to send us inventory files on a daily basis. The server should ensure secure and reliable file transfers, allowing our vendors to easily upload their inventory updates. The successful candidate will possess expertise [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">Job Description</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>We are looking for an experienced professional to help us set up an SFTP server that will allow our vendors to send us inventory files on a daily basis. The server should ensure secure and reliable file transfers, allowing our vendors to easily upload their inventory updates. The successful candidate will possess expertise in SFTP server setup and configuration, as well as knowledge of network security protocols. The required skills for this job include:</p>



<p>&#8211; SFTP server setup and configuration<br>&#8211; Network security protocols<br>&#8211; Troubleshooting and problem-solving skills</p>



<p>If you have demonstrated experience in setting up SFTP servers and ensuring smooth daily file transfers, we would love to hear from you.</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p></p>



<h3 class="wp-block-heading">My Role</h3>



<p>I walked the client through the process of setting up a Digital Ocean account.  I created a <code>Ubuntu 22.04</code> VM and installed <a href="https://github.com/drakkan/sftpgo">SFTPGo</a>.  I set the client up with an administrator user so that they could easily login and manage users and shares.  I implemented some basic security practices as well and set the client up with a custom domain and free TLS/SSL certificate from LetsEncrypt.  With the documentation and screenshots I provided the client, they were able to get everything up and running and add users and connect other systems easily and securly.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p></p>



<h2 class="wp-block-heading">Client Feedback</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Rating is 5 out of 5.</p>



<p>Michael was EXTREMELY helpful and great to work with. We really benefited from his support and help with everything.</p>
</blockquote>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Fun with bots &#8211; SSH tarpitting</title>
		<link>/fun-with-bots-ssh-tarpitting/</link>
		
		<dc:creator><![CDATA[mikeconrad]]></dc:creator>
		<pubDate>Mon, 24 Jun 2024 13:37:43 +0000</pubDate>
				<category><![CDATA[Cloudflare]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[SSH]]></category>
		<category><![CDATA[Blog Post]]></category>
		<guid isPermaLink="false">/?p=576</guid>

					<description><![CDATA[For those of you who aren&#8217;t familiar with the concept of a network tarpit it is a fairly simple concept. Wikipedia defines it like this: A tarpit is a service on a computer system (usually a server) that purposely delays incoming connections. The technique was developed as a defense against a computer worm, and the idea is that network abuses such as spamming or broad [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>For those of you who aren&#8217;t familiar with the concept of a network tarpit it is a fairly simple concept.  Wikipedia defines it like this:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>A <strong>tarpit</strong> is a service on a <a href="https://en.wikipedia.org/wiki/Computer_system">computer system</a> (usually a <a href="https://en.wikipedia.org/wiki/Server_(computing)">server</a>) that purposely delays incoming connections. The technique was developed as a defense against a <a href="https://en.wikipedia.org/wiki/Computer_worm">computer worm</a>, and the idea is that <a href="https://en.wikipedia.org/wiki/Computer_network">network</a> abuses such as <a href="https://en.wikipedia.org/wiki/Spamming">spamming</a> or broad scanning are less effective, and therefore less attractive, if they take too long. The concept is analogous with a <a href="https://en.wikipedia.org/wiki/Tar_pit">tar pit</a>, in which animals can get bogged down and slowly sink under the surface, like in a <a href="https://en.wikipedia.org/wiki/Swamp">swamp</a>.</p>
<cite><a href="https://en.wikipedia.org/wiki/Tarpit_(networking)">https://en.wikipedia.org/wiki/Tarpit_(networking)</a></cite></blockquote>



<p>If you run any sort of service on the internet then you know as soon as your server has a public IP address and open ports, there are scanners and bots trying to get in constantly.  If you take decent steps towards security then it is little more than an annoyance, but annoying all the less.  One day when I had some extra time on my hands I started researching ways to mess with the bots trying to scan/attack my site.</p>



<p>It turns out that this problem has been solved multiple times in multiple ways.  One of the most popular tools for tarpitting ssh connections is <a href="https://github.com/skeeto/endlessh">endlessh</a>.  The way it works is actually pretty simple.  The <a href="https://datatracker.ietf.org/doc/html/rfc4253#section-4.2">SSH RFC</a> states that when an SSH connection is established, both sides MUST send an identification string.  Further down the spec is the line that allows this behavior:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<pre class="wp-block-preformatted">   The server MAY send other lines of data before sending the version
   string.  Each line SHOULD be terminated by a Carriage Return and Line
   Feed.  Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
   in ISO-10646 UTF-8 [<a href="https://datatracker.ietf.org/doc/html/rfc3629">RFC3629</a>] (language is not specified).  Clients
   MUST be able to process such lines.  Such lines MAY be silently
   ignored, or MAY be displayed to the client user.  If they are
   displayed, control character filtering, as discussed in [<a href="https://datatracker.ietf.org/doc/html/rfc4253#ref-SSH-ARCH">SSH-ARCH</a>],
   SHOULD be used.  The primary use of this feature is to allow TCP-
   wrappers to display an error message before disconnecting.</pre>
<cite>SSH RFC</cite></blockquote>



<p>Essentially this means that their is no limit to the amount of data that a server can send back to the client and the client must be able to wait and process all of this data.  Now let&#8217;s see it in action.</p>



<pre class="wp-block-code"><code>git clone https://github.com/skeeto/endlessh.git
cd endlessh
make
./endlessh &amp;</code></pre>



<p>By default this fake server listens on port 2222.  I have a port forward set up that forwards all ssh traffic from port 22 to 2222.  Now try to connect via ssh:</p>



<pre class="wp-block-code"><code>ssh -vvv localhost -p 2222</code></pre>



<p>If you wait a few seconds you will see the server send back the version string and then start sending a random banner:</p>



<pre class="wp-block-code"><code>$:/tmp/endlessh$ 2024-06-24T13:05:59.488Z Port 2222
2024-06-24T13:05:59.488Z Delay 10000
2024-06-24T13:05:59.488Z MaxLineLength 32
2024-06-24T13:05:59.488Z MaxClients 4096
2024-06-24T13:05:59.488Z BindFamily IPv4 Mapped IPv6
2024-06-24T13:05:59.488Z socket() = 3
2024-06-24T13:05:59.488Z setsockopt(3, SO_REUSEADDR, true) = 0
2024-06-24T13:05:59.488Z setsockopt(3, IPV6_V6ONLY, true) = 0
2024-06-24T13:05:59.488Z bind(3, port=2222) = 0
2024-06-24T13:05:59.488Z listen(3) = 0
2024-06-24T13:05:59.488Z poll(1, -1)
ssh -vvv localhost -p 2222
OpenSSH_8.9p1 Ubuntu-3ubuntu0.7, OpenSSL 3.0.2 15 Mar 2022
debug1: Reading configuration data /home/mikeconrad/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files
debug1: /etc/ssh/ssh_config line 21: Applying options for *
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> '/home/mikeconrad/.ssh/known_hosts'
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> '/home/mikeconrad/.ssh/known_hosts2'
debug2: resolving "localhost" port 2222
debug3: resolve_host: lookup localhost:2222
debug3: ssh_connect_direct: entering
debug1: Connecting to localhost &#91;::1] port 2222.
debug3: set_sock_tos: set socket 3 IPV6_TCLASS 0x10
debug1: Connection established.
2024-06-24T13:06:08.635Z = 1
2024-06-24T13:06:08.635Z accept() = 4
2024-06-24T13:06:08.635Z setsockopt(4, SO_RCVBUF, 1) = 0
2024-06-24T13:06:08.635Z ACCEPT host=::1 port=43696 fd=4 n=1/4096
2024-06-24T13:06:08.635Z poll(1, 10000)
debug1: identity file /home/mikeconrad/.ssh/id_rsa type 0
debug1: identity file /home/mikeconrad/.ssh/id_rsa-cert type 4
debug1: identity file /home/mikeconrad/.ssh/id_ecdsa type -1
debug1: identity file /home/mikeconrad/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/mikeconrad/.ssh/id_ecdsa_sk type -1
debug1: identity file /home/mikeconrad/.ssh/id_ecdsa_sk-cert type -1
debug1: identity file /home/mikeconrad/.ssh/id_ed25519 type -1
debug1: identity file /home/mikeconrad/.ssh/id_ed25519-cert type -1
debug1: identity file /home/mikeconrad/.ssh/id_ed25519_sk type -1
debug1: identity file /home/mikeconrad/.ssh/id_ed25519_sk-cert type -1
debug1: identity file /home/mikeconrad/.ssh/id_xmss type -1
debug1: identity file /home/mikeconrad/.ssh/id_xmss-cert type -1
debug1: identity file /home/mikeconrad/.ssh/id_dsa type -1
debug1: identity file /home/mikeconrad/.ssh/id_dsa-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.7
2024-06-24T13:06:18.684Z = 0
2024-06-24T13:06:18.684Z write(4) = 3
2024-06-24T13:06:18.684Z poll(1, 10000)
debug1: kex_exchange_identification: banner line 0: V
2024-06-24T13:06:28.734Z = 0
2024-06-24T13:06:28.734Z write(4) = 25
2024-06-24T13:06:28.734Z poll(1, 10000)
debug1: kex_exchange_identification: banner line 1: 2I=ED}PZ,z T_Y|Yc]$b{R]

</code></pre>



<p>This is a great way to give back to those bots and script kiddies.  In my research into other methods I also stumbled across this brilliant program <a href="https://github.com/iBug/fakessh">fakessh</a>.  While fakessh isn&#8217;t technically a tarpit, it&#8217;s more of a honeypot but very interesting nonetheless.  It creates a fake SSH server and logs the ip address, connection string and any commands executed by the attacker.  Essentially it allows any username/password combination to connect and gives them a fake shell prompt.  There is no actual access to any file system and all of their commands basically return gibberish.</p>



<p>Here are some logs from an actual server of mine running fakessh</p>



<pre class="wp-block-code"><code>2024/06/24 06:51:20 &#91;conn] ip=183.81.169.238:40430
2024/06/24 06:51:22 &#91;auth] ip=183.81.169.238:40430 version="SSH-2.0-Go" user="root" password="0"
2024/06/24 06:51:23 &#91;conn] ip=183.81.169.238:40444
2024/06/24 06:51:25 &#91;auth] ip=183.81.169.238:40444 version="SSH-2.0-Go" user="root" password="eve"
2024/06/24 06:51:26 &#91;conn] ip=183.81.169.238:48408
2024/06/24 06:51:27 &#91;auth] ip=183.81.169.238:48408 version="SSH-2.0-Go" user="root" password="root"
2024/06/24 06:51:28 &#91;conn] ip=183.81.169.238:48434
2024/06/24 06:51:30 &#91;auth] ip=183.81.169.238:48434 version="SSH-2.0-Go" user="root" password="1"
2024/06/24 06:51:30 &#91;conn] ip=183.81.169.238:48448
2024/06/24 06:51:32 &#91;auth] ip=183.81.169.238:48448 version="SSH-2.0-Go" user="root" password="123"
2024/06/24 06:51:32 &#91;conn] ip=183.81.169.238:48476
2024/06/24 06:51:35 &#91;auth] ip=183.81.169.238:48476 version="SSH-2.0-Go" user="root" password="admin"
2024/06/24 06:51:35 &#91;conn] ip=183.81.169.238:39250
2024/06/24 06:51:37 &#91;auth] ip=183.81.169.238:39250 version="SSH-2.0-Go" user="root" password="123456"
2024/06/24 06:51:38 &#91;conn] ip=183.81.169.238:39276
2024/06/24 06:51:40 &#91;auth] ip=183.81.169.238:39276 version="SSH-2.0-Go" user="root" password="123123"
2024/06/24 06:51:40 &#91;conn] ip=183.81.169.238:39294
2024/06/24 06:51:42 &#91;auth] ip=183.81.169.238:39294 version="SSH-2.0-Go" user="root" password="test"
2024/06/24 06:51:43 &#91;conn] ip=183.81.169.238:39316
2024/06/24 06:51:45 &#91;auth] ip=183.81.169.238:39316 version="SSH-2.0-Go" user="root" password="123456789"
2024/06/24 06:51:45 &#91;conn] ip=183.81.169.238:35108
2024/06/24 06:51:47 &#91;auth] ip=183.81.169.238:35108 version="SSH-2.0-Go" user="root" password="12345"
2024/06/24 06:51:48 &#91;conn] ip=183.81.169.238:35114
2024/06/24 06:51:50 &#91;auth] ip=183.81.169.238:35114 version="SSH-2.0-Go" user="root" password="password"
2024/06/24 06:51:50 &#91;conn] ip=183.81.169.238:35130
2024/06/24 06:51:52 &#91;auth] ip=183.81.169.238:35130 version="SSH-2.0-Go" user="root" password="12345678"
2024/06/24 06:51:52 &#91;conn] ip=183.81.169.238:35146
2024/06/24 06:51:54 &#91;auth] ip=183.81.169.238:35146 version="SSH-2.0-Go" user="root" password="111111"
2024/06/24 06:51:55 &#91;conn] ip=183.81.169.238:58490
2024/06/24 06:51:57 &#91;auth] ip=183.81.169.238:58490 version="SSH-2.0-Go" user="root" password="1234567890"
2024/06/24 06:51:57 &#91;conn] ip=183.81.169.238:58528
2024/06/24 06:51:59 &#91;auth] ip=183.81.169.238:58528 version="SSH-2.0-Go" user="root" password="1234"
2024/06/24 06:52:00 &#91;conn] ip=183.81.169.238:58572
2024/06/24 06:52:02 &#91;auth] ip=183.81.169.238:58572 version="SSH-2.0-Go" user="root" password="password123"
2024/06/24 06:52:02 &#91;conn] ip=183.81.169.238:58588
2024/06/24 06:52:04 &#91;auth] ip=183.81.169.238:58588 version="SSH-2.0-Go" user="root" password="ubuntu"
2024/06/24 06:52:05 &#91;conn] ip=183.81.169.238:37198
2024/06/24 06:52:07 &#91;auth] ip=183.81.169.238:37198 version="SSH-2.0-Go" user="Antminer" password="root"
2024/06/24 06:52:07 &#91;conn] ip=183.81.169.238:37214
2024/06/24 06:52:09 &#91;auth] ip=183.81.169.238:37214 version="SSH-2.0-Go" user="Antminer" password="admin"
2024/06/24 06:52:10 &#91;conn] ip=183.81.169.238:37238
2024/06/24 06:52:11 &#91;auth] ip=183.81.169.238:37238 version="SSH-2.0-Go" user="root" password="innot1t2"
2024/06/24 06:52:12 &#91;conn] ip=183.81.169.238:37258
2024/06/24 06:52:14 &#91;auth] ip=183.81.169.238:37258 version="SSH-2.0-Go" user="root" password="t1t2t3a5"
2024/06/24 06:52:14 &#91;conn] ip=183.81.169.238:55658
2024/06/24 06:52:16 &#91;auth] ip=183.81.169.238:55658 version="SSH-2.0-Go" user="root" password="blacksheepwall"
2024/06/24 06:52:17 &#91;conn] ip=183.81.169.238:55670
2024/06/24 06:52:19 &#91;auth] ip=183.81.169.238:55670 version="SSH-2.0-Go" user="root" password="envision"
2024/06/24 06:52:19 &#91;conn] ip=183.81.169.238:55708
2024/06/24 06:52:21 &#91;auth] ip=183.81.169.238:55708 version="SSH-2.0-Go" user="root" password="bwcon"
2024/06/24 06:52:22 &#91;conn] ip=183.81.169.238:55776
2024/06/24 06:52:23 &#91;auth] ip=183.81.169.238:55776 version="SSH-2.0-Go" user="admin" password="root"
2024/06/24 06:52:24 &#91;conn] ip=183.81.169.238:46646
2024/06/24 06:52:26 &#91;auth] ip=183.81.169.238:46646 version="SSH-2.0-Go" user="baikal" password="baikal"
2024/06/24 06:52:26 &#91;conn] ip=180.101.88.197:44620
2024/06/24 06:52:27 &#91;conn] ip=180.101.88.197:44620 err="ssh: disconnect, reason 11: "
2024/06/24 06:53:35 &#91;conn] ip=218.92.0.76:50610
2024/06/24 06:53:36 &#91;conn] ip=218.92.0.76:50610 err="ssh: disconnect, reason 11: "
2024/06/24 07:02:28 &#91;conn] ip=218.92.0.27:64676
2024/06/24 07:02:30 &#91;conn] ip=218.92.0.27:64676 err="ssh: disconnect, reason 11: "
2024/06/24 07:10:05 &#91;conn] ip=218.92.0.76:57601
2024/06/24 07:10:07 &#91;conn] ip=218.92.0.76:57601 err="ssh: disconnect, reason 11: "
2024/06/24 07:14:05 &#91;conn] ip=193.201.9.156:63056
2024/06/24 07:14:05 &#91;auth] ip=193.201.9.156:63056 version="SSH-2.0-Go" user="ubnt" password="ubnt"
2024/06/24 07:14:05 &#91;conn] ip=193.201.9.156:63056 err="read tcp 10.10.10.107:2222->193.201.9.156:63056: read: connection reset by peer"
2024/06/24 07:24:53 &#91;conn] ip=218.92.0.31:25485
2024/06/24 07:24:54 &#91;conn] ip=218.92.0.31:25485 err="ssh: disconnect, reason 11: "
2024/06/24 07:24:54 &#91;conn] ip=218.92.0.112:39270
2024/06/24 07:24:56 &#91;conn] ip=218.92.0.112:39270 err="ssh: disconnect, reason 11: "
2024/06/24 07:26:42 &#91;conn] ip=218.92.0.34:59993
2024/06/24 07:35:46 &#91;conn] ip=218.92.0.34:59993 err="read tcp 10.10.10.107:2222->218.92.0.34:59993: read: connection reset by peer"
2024/06/24 07:41:28 &#91;conn] ip=218.92.0.107:62285
2024/06/24 07:41:31 &#91;conn] ip=218.92.0.107:62285 err="ssh: disconnect, reason 11: "
2024/06/24 07:43:27 &#91;conn] ip=218.92.0.29:34556
2024/06/24 07:43:28 &#91;conn] ip=218.92.0.29:34556 err="ssh: disconnect, reason 11: "
2024/06/24 07:44:15 &#91;conn] ip=218.92.0.118:37047
2024/06/24 07:44:22 &#91;conn] ip=218.92.0.118:37047 err="ssh: disconnect, reason 11: "
2024/06/24 07:56:10 &#91;conn] ip=157.245.98.245:6116
2024/06/24 07:56:11 &#91;conn] ip=157.245.98.245:6116 err="ssh: unexpected message type 20 (expected 21)"
2024/06/24 07:57:57 &#91;conn] ip=218.92.0.112:28326
2024/06/24 07:57:58 &#91;conn] ip=218.92.0.112:28326 err="ssh: disconnect, reason 11: "
2024/06/24 08:00:01 &#91;conn] ip=218.92.0.24:24948
2024/06/24 08:00:02 &#91;conn] ip=218.92.0.24:24948 err="ssh: disconnect, reason 11: "
2024/06/24 08:06:19 &#91;conn] ip=193.201.9.156:46865
2024/06/24 08:06:20 &#91;auth] ip=193.201.9.156:46865 version="SSH-2.0-Go" user="root" password="xc3511"
2024/06/24 08:06:20 &#91;conn] ip=193.201.9.156:46865 err="read tcp 10.10.10.107:2222->193.201.9.156:46865: read: connection reset by peer"
2024/06/24 08:14:26 &#91;conn] ip=180.101.88.197:48347
2024/06/24 08:14:28 &#91;conn] ip=180.101.88.197:48347 err="ssh: disconnect, reason 11: "
2024/06/24 08:16:28 &#91;conn] ip=218.92.0.56:18064
2024/06/24 08:16:32 &#91;conn] ip=218.92.0.56:18064 err="ssh: disconnect, reason 11: "
2024/06/24 08:30:55 &#91;conn] ip=180.101.88.196:40495
2024/06/24 08:30:57 &#91;conn] ip=180.101.88.196:40495 err="ssh: disconnect, reason 11: "
2024/06/24 08:32:20 &#91;conn] ip=85.209.11.227:15493
2024/06/24 08:32:21 &#91;auth] ip=85.209.11.227:15493 version="SSH-2.0-Go" user="telecomadmin" password="admintelecom"
2024/06/24 08:32:21 &#91;conn] ip=85.209.11.227:15493 err="read tcp 10.10.10.107:2222->85.209.11.227:15493: read: connection reset by peer"
2024/06/24 08:33:19 &#91;conn] ip=218.92.0.34:59804
2024/06/24 08:33:21 &#91;conn] ip=218.92.0.34:59804 err="ssh: disconnect, reason 11: "
2024/06/24 08:41:00 &#91;conn] ip=218.92.0.27:45567
2024/06/24 08:41:02 &#91;conn] ip=218.92.0.27:45567 err="ssh: disconnect, reason 11: "
2024/06/24 08:47:15 &#91;conn] ip=180.101.88.196:17032
2024/06/24 08:47:16 &#91;conn] ip=180.101.88.196:17032 err="ssh: disconnect, reason 11: "
2024/06/24 08:49:51 &#91;conn] ip=218.92.0.29:26360
2024/06/24 08:49:57 &#91;conn] ip=218.92.0.29:26360 err="ssh: disconnect, reason 11: "
2024/06/24 08:58:27 &#91;conn] ip=193.201.9.156:49525
2024/06/24 08:58:28 &#91;auth] ip=193.201.9.156:49525 version="SSH-2.0-Go" user="admin" password="1234"
2024/06/24 08:58:28 &#91;conn] ip=193.201.9.156:49525 err="read tcp 10.10.10.107:2222->193.201.9.156:49525: read: connection reset by peer"
2024/06/24 08:58:44 &#91;conn] ip=218.92.0.31:11835
2024/06/24 08:58:46 &#91;conn] ip=218.92.0.31:11835 err="ssh: disconnect, reason 11: "
2024/06/24 09:03:38 &#91;conn] ip=218.92.0.107:57758
2024/06/24 09:03:40 &#91;conn] ip=218.92.0.107:57758 err="ssh: disconnect, reason 11: "
2024/06/24 09:07:36 &#91;conn] ip=218.92.0.56:21354
2024/06/24 09:07:39 &#91;conn] ip=218.92.0.56:21354 err="ssh: disconnect, reason 11: "
</code></pre>



<p>Those are mostly connections and disconnections.  They probably connected, realized it was fake and disconnected.  There are a couple that tried to execute some commands though:</p>



<pre class="wp-block-code"><code>:~$ sudo grep head /var/log/fakessh/fakessh.log 
2024/06/23 15:48:02 &#91;shell] ip=184.160.233.163:45735 duration=0s bytes=15 head="ls 2>/dev/null\n"
2024/06/24 03:55:11 &#91;shell] ip=14.46.116.243:43656 duration=20s bytes=0 head=""
</code></pre>



<p>Fun fact: Cloudflare&#8217;s Bot Fight Mode uses a form of tarpitting:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Once enabled, when we detect a bad bot, we will do three things: (1) we’re going to disincentivize the bot maker economically by tarpitting them, including requiring them to solve a computationally intensive challenge that will require more of their bot’s CPU; (2) for <a href="https://blog.cloudflare.com/bandwidth-alliance/">Bandwidth Alliance partners</a>, we’re going to hand the IP of the bot to the partner and get the bot kicked offline; and (3) we’re going to plant trees to make up for the bot’s carbon cost.</p>
<cite><a href="https://blog.cloudflare.com/cleaning-up-bad-bots">https://blog.cloudflare.com/cleaning-up-bad-bots</a></cite></blockquote>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
