Hardening Mikrotik RouterOS

https://wiki.mikrotik.com/wiki/Manual:Securing_Your_Router

Things to harden

  • Delete default admin user
  • Disable unused services and whitelist IP’s
  • Secure SSH
  • DNS

Delete default admin user

Before deleting the default admin user, create your own user account.

/user/add name=MyUsername group=full password=mylongsecurepassword

Note: running /user/add will prompt you for the rest of the options.

Delete the default admin user with

/user remove admin

We want to delete the default admin user for two reasons. 1. There is no default password for this user. 2. It is a default username which means it will be targeted for brute force attacks.

Consider using the /users/groups for more granular control.

Disable unused services

In the following, we disabled all services except SSH and Winbox. We also limit access to those services only from private “RFC 1918” IP addresses. Customize as needed.

/ip service
set telnet disabled=yes
set ftp disabled=yes
set www disabled=yes
set www-ssl tls-version=only-1.2
set ssh address="set winbox address="192.168.0.0/16,172.16.0.0/12,10.0.0.0/8"
set api disabled=yes
set winbox address="set winbox address="192.168.0.0/16,172.16.0.0/12,10.0.0.0/8"
set api-ssl disabled=yes tls-version=only-1.2

for www-ssl and api-ssl, tls-version is not a required argument, but you may consider using it if you need the API or Webfig.

Secure SSH

/ip/ssh/set strong-crypto=yes allow-none-crypto=no always-allow-password-login=no host-key-size=4096

And regenerate the SSH host key. It will prompt for a [y/N], hit y to regenerate.

/ip/ssh/regenerate-host-key 

DNS

Unless your device is being used as a DNS resolver, it is best to disable the “Allow Remote Request”

ip dns/set allow-remote-requests=no

If you do need it enabled, then be sure to add some firewall rules to keep your router from being used in amplification attacks.

add action=drop chain=input dst-port=53 in-interface-list=WAN protocol=udp

You can configure interface lists in /interface/list or Interface -> Interface List in the gui

Or you can change to in-interface and specify the WAN interface directly. You could also set it to !LAN if you have a LAN interface list set up.

MikroTik RouterOS Privilege Escalation Exploit CVE-2023-37099

Mikrotik Recently patched CVE-2023-37099 which was a way someone with an admin account, could escalate to a “super admin”, or jail break a router.

It appears the technique has been around for about a year.

Affected versions: < 6.49.7

The good news is that someone would already have to have an account to elevate permissions. If your routers have been using strong passwords or SSH public/private keys and have internet management disabled, then you are probably fine.

https://github.com/MarginResearch/FOISted

https://vulncheck.com/blog/mikrotik-foisted-revisited

Simple OSPF between Mikrotik Routers

https://help.mikrotik.com/docs/display/ROS/OSPF

Setting up OSPF between Mikrotik routers is not too difficult. The following commands should work with RouterOS version 7+. Run these commands on each Mikrotik changing out the router-id.

Create a Loop-back interface

First it would be a good idea to create an loopback interface that will stay up. We’ll use this address as the router-id. This should be unique per router.

/interface/bridge/add name=loopback
/ip/address/add address=1.2.3.4 interface=loopback

Now lets setup OSPF.

Create OSPF Instance

First we’ll create the instance. Use the address from the above loopback address. Technically you can use whatever id you want as long as it is a 32 bit “address” and is unique.

/routing/ospf/instance/add name=default router-id=1.2.3.4

IMPORTANT NOTE: If this router is also the default gateway, you’ll need to specify the “originate-default=always” option to share the default gateway over OSPF to the other routers. You don’t have to do this if you don’t want to share the default route.

Create OSPF Area

Now we can create an OSPF area. For a simple OSPF setup, we’ll just use the default 0.0.0.0 area.

routing/ospf/area/ add name=default area-id=0.0.0.0 instance=default

Create Instance

Now we can add an instance. This is responsible for what networks get shared with OSPF. If you want to do all the addresses on the router, then use 0.0.0.0/0. If you only want to do specific networks, run an entry for every network, changing 0.0.0.0/0 to the network of interest.

/routing/ospf/interface-template/add networks=0.0.0.0/0 area=default

Wrapping Up

After that we can check to make sure things worked.

/routing/ospf/neighbor/print

You should see at a neighbor. It can take a little bit for the neighbors to show up.

You can also check the routes on the router.

/ip/route/print

OSPF has a default distance of 110, so checking the routes is a quick way to verify the routes are getting updated. Do note that if you have a static route in with a lower distance, that will take precedence over OSPF.

Mikrotik DHCP Server Lease Script Variables

The following variables are usable inside of the DHCP-Server script tab.

  • leaseBound – set to “1” if bound, otherwise set to “0”
  • leaseServerName – dhcp server name
  • leaseActMAC – active mac address
  • leaseActIP – active IP address
  • lease-hostname – client hostname
  • lease-options – array of received options

The DHCP server script runs every time there is a new lease, or a lease expires. Doesn’t look to run when static leases renew.

DHCP Server Scripts

https://wiki.mikrotik.com/wiki/Manual:IP/DHCP_Server#General

Mikrotik Script – Send Webhook when Power Fails on PSU

The goal for this script is to alert us if a remote site looses power. We can do this using a Mikrotik that has two PSUs. One is plugged into battery backup and the other in the non battery plug.

In this example, we are using PSU2 “number 8” We can find the number using

/system/health/print

We can now create a new scheduler entry with the following. Change out the number 8 to your PSU number, and change the webhook to your Teams webhook.

:local curState [system/health/get value-name=value  number=8]
:local name [/system/identity/get value-name=name]
:local webhook "https://teams.webhook.microsoft.com/webhook/more"

if ($curState != $lastState) do={
if ($curState = "ok") do={
/tool fetch http-method=post http-header-field="Content-Type: application/json" http-data="{\"text\": \"$name : Power is on.\"}" url="$webhook"
}
if ($curState != "ok") do={
/tool fetch http-method=post http-header-field="Content-Type: application/json" http-data="{\"text\": \"$name : Power is off.  On battery backup\"}" url="$webhook"
}
:global lastState $curState
}

Set to the appropriate interval (i.e. 5 minutes). The script will only alert once when the power state changes. This minimizes receiving an alert every 5 minutes while the power is off.

Mikrotik DHCP Scripts

The purpose of these scripts is to update the local DHCP lease table with a remote IP Address Management (IPAM) system.

Scheduler Script

This little script is added to the scheduler and goes through the entire DHCP lease table and uploads each MAC address and IP address pair to a website.

Change out the top three variables. May also need to change out the URL depending on how the website receives data.

:local url "upload.incredigeek.com"
:local username "myapiuser"
:local password "passwordforapiuserwebsite"

/ip/dhcp-server/lease/
:foreach i in=[find] do={ :put ([get $i address]." ".[get $i mac-address])
:local ipaddress ([get $i address])
:local macaddress ([get $i mac-address])
/tool fetch url="https://$url/api/v1/network/ipam/dynamic_ip_assignment?ip_address=$ipaddress&mac_address=$macaddress&expired=0" mode=https keep-result=no user=$username password=$password
:delay 1s;
}

DHCP Script

This script is to be used on the DHCP server script. Can add it by going to DHCP Server -> DHCP -> Double Click Server -> Script

Any time a new DHCP lease is obtained, this script is fired. Note that some of the variables like $leaseBound are specific to the script being used by the “DHCP server”

Also helpful to note that the script only runs if a new lease is obtained, or a lease expires and it disappears from the leases page. A DHCP renew does not trigger the script.

:local username "myapiuser"
:global password "myapipassword"
:global url "upload.incredigeek.com"

# The maximum retries
:local max 60
:local attempts 0
:local success 0
:do {
  :set attempts ($attempts+1);
  :if ($leaseBound = 0) do {
    :do {
      /tool fetch url="https://$url/api/v1/network/ipam/dynamic_ip_assignment?ip_address=$leaseActIP&mac_address=$leaseActMAC&expired=1" mode=https keep-result=no user=$username password=$password
      :set success 1;
    } on-error={
      :log error "DHCP FAILED to send unassignment to $url on attempt $attempts out of $max for $leaseActMAC / $leaseActIP";
      :delay 10s;
    }
  } else {
    :delay 1s;
    # see note below
    :local remoteID [/ip dhcp-server lease get [find where address=$leaseActIP] agent-remote-id];
    :do {
      /tool fetch url="https://$url/api/v1/network/ipam/dynamic_ip_assignment?ip_address=$leaseActIP&mac_address=$leaseActMAC&expired=0" mode=https keep-result=no user=$username password=$password
      :set success 1;
    } on-error={
      :log error "DHCP FAILED to send assignment to $url on attempt $attempts out of $max for $leaseActMAC / $leaseActIP";
      :delay 10s;
    }
  }
  :if ($success) do {
    :log info "DHCP lease message successfully sent $leaseActMAC / $leaseActIP to $url";
    :set attempts $max;  # break out of the do..while loop
  }
} while ( $attempts < $max )
}

Send Post Webhook Message to Teams from Mikrotik RouterOS

The following is the correct syntax needed to send a message to Microsoft Teams from a Mikrotik router. You will need a valid Teams webhook to send to.

Change “Test Message” out for your message. You should receive a “status: finished” response.

/tool fetch http-method=post http-header-field="Content-Type: application/json" http-data="{\"text\": \"Test Message\"}" url=https://domain.webhook.office.com/webhook/long/string

https://help.mikrotik.com/docs/display/ROS/Fetch

Hardening SSH on Mikrotik Routers

Here are the commands you’ll need to harden SSH on your Mikrotik Routers. It looks like it still can use SSH-RSA, but it does get rid of most of the weaker crytpo algorithms.

/ip/ssh/set strong-crypto=yes allow-none-crypto=no always-allow-password-login=no host-key-size=4096

We’ll want to regenerate the Host Key now that the settings have been changed.

/ip/ssh/regenerate-host-key

It will prompt to enter [y/N] to confirm that you actually want to regenerate the host key. Hit y

After your done, you can use something like ssh-audit to check your equipment.
https://www.ssh-audit.com/

Further hardening information is available at the following link.
https://wiki.mikrotik.com/wiki/Manual:Securing_Your_Router

Bulk Update SNMP v3 Settings for Devices in LibreNMS

With support for DES being dropped, you may be faced with having to upgrade device settings to AES. In this post we’ll explore changing the settings in LibreNMS for all Mikrotik devices and then touch on making changes to a group of Mikrotik devices.

Upgrading SNMP Settings for Devices in LibreNMS

In LibreNMS, we can go to Device -> Device Settings (Gear on the right hand side) -> SNMP, to set the SNMP settings for that device.

Since this would get rather boring to change on multiple devices, and these settings are all in a MySQL database, we can skip using the mouse and use a few MySQL commands to update multiple devices at once.

Log into the LibreNMS server over ssh and then connect to the MySQL database

mysql -u librenms -p librenms

First we can get a list of all the devices (Mikrotik routers in this example) and show the hostname with the SNMP authentication and cryptography algorithms.

select hostname,authalgo,cryptoalgo from devices where os="routeros";

Now if we want to update the cryptography settings for all of our Mikorotik devices, we can do the following.

update devices cryptoalgo set cryptoalgo="AES"  where os="routeros";

This will set all of the devices to use AES for the cryptography algorithm.

We can also change the authentication algorithm to SHA with this

update devices authalgo set authalgo="SHA"  where os="routeros";
LibreNMS update device SNMP settings

Bulk updating of Network Devices

The bottom “script” can be used for changing SNMP settings on multiple Mikrotik devices.

Create a mikrotik.lst file with all the IP addresses of all the devices you need to update. Can you use the above MySQL commands to get a list from LibreNMS.

Change the following options in the script

  • routerpassword to the Mikrotik password
  • admin to your username
  • encryptionpassword to your SNMP encryption password
  • authpassword to your authentication password
  • addresses=192.168.0.0/16 to the list of IP addresses that should be able to access SNMP info on the mikrotik device. AKA your LibreNMS server.
  • SNMPname to your SNMP username
for ip in `cat mikrotik.lst` 
do 
echo $ip 
timeout 15 sshpass -p 'routerpassword' ssh -o StrictHostKeyChecking=no admin@${ip} -p1022 '/snmp community set addresses=192.168.0.0/16 authentication-protocol=SHA1 authentication-password=authpassword encryption-protocol=AES encryption-password=encryptionpassword security=private read-access=yes write-access=no SNMPname'
done

Copy and paste the above “code” in a shell script file.

nano mikrotik.sh
chmod +x mikrotik.sh 
./mikrotik.sh

The script should run and update all the SNMP settings on all the devices in mikrotik.lst