In April 23rd 2018, Mikrotik fixed a vulnerability “that allowed gaining access to an unsecured router”. myself and @yalpanian of BASU CERT reverse engineering lab tried to figure out what exactly got fixed, what was the problem in the first place and how severe was the impact of it.
UPDATE: full PoC is now available on Github.
According to the official website, MikroTik is a Latvian company which was founded in 1996 to develop routers and wireless ISP systems. MikroTik now provides hardware and software for Internet connectivity in most of the countries around the world.
RouterOS is the operating system of most Mikrotik devices. The vulnerability affects all versions of RouterOS from 6.29 (release date: 2015/28/05) to 6.42 (release date 2018/04/20)
First things first, we had to see which binaries was changed before and after the patching. RouterOS is written on top of Linux Kernel so a lot of kernel modules will be different in each version. What we did was downloading RouterOS 6.40.7 and 6.40.8 npk files and look through each file to find the differences. I just named them “after” and “before” on my laptop. I hashed every file inside those packages to see the difference, and long behold I found a few. As you can see, mproxy binary has changed. Which makes sense because mproxy binary handles all Winbox requests.
mproxy is a 63K binary with no (except for a simple NX section) security measurements. So this bug could’ve been anything memory related. we ran bindiff on the files and found some differences between the two versions, but there was a simple “if” statement which was added to the file.
So, how can we confirm this? We don’t have GDB and we don’t have a shell (yet). After some digging around, we found an interesting project “mikrotik-tools”. It shows an easy way to get a bash shell inside a RouterOS and copy additional binaries to its filesystem. So we added a new and big BusyBox in addition to a gdbserver to do the job for us. It was pretty easy on VM since all you need to do is mount RouterOS vmdk somewhere and add additional files. After that the RouterOS will boot and it’ll login with “devel” account with the same password as your admin account. In that telnet session, there’s no RouterOS shell, instead, it’s bash! easy :-)
After putting a breakpoint on the “list” string, we started digging around and finally got the string which bypasses the first condition without violating any rules. Since the code scans the strings 4 bytes at a time, we could place our dots between them so it couldn’t be discovered by the code.
now let’s get started on sending some packets across! First, we turn off secure communication between the Router and Winbox just because we can! When looking at the packets, we’ll see a tiny conversation between the Router and Winbox and then we’ll see the list file being sent to Winbox. This file includes all the necessary DLLs for Winbox to use in order to communicate with the Router. Interestingly, this approach has had more than a couple security flaws. Just think about it, you download an unknown DLL from a remote host and you run it under Winbox, a signed executable! But that’s for another blog post. Right now, we want to switch off this list with our crafted string. Here’s the original conversation:
So what’s so interesting about this conversation? If you look at it closely, you’ll see the highlighted packets are not the first in the conversation. First Winbox authenticates with the Router and then tries to get the list file. Pretty safe, right? We thought so too at first, especially since we repeated the same packets and got a “bad session id” result back from RouterOS. But we noticed something interesting. A single byte is changing each time we send the same request to the Router, and each time we sent that exact same byte over to the Router in our next request.. Session ID? YES! So we did our repeat attack with this tiny modification. We sent the request, waited for the Router to respond, switched that one byte by the byte received from the response, and then we sent the second request. and Voilà! We got our file!! We didn’t even need to authenticate! Just by sending the highlighted packets in the right order and switching the byte, the Router folds.
A general rule of thumb: don’t trust the client you shipped to users. Trust your own service to do proper validation :)
Now we can read ANY file from the Router! Which files are useful? In our previous talk on APA3 conference, we talked about just how insecure Mikrotik is, especially when it comes to handling credentials. In short, Mikrotik uses a very weak encoding (no hash and salt) to store passwords to an index file. So it’s entirely possible to download the credential database and extract every username and password stored inside it and that’s exactly what we did for this PoC.
After downloading the idx file, we used another great tool from mikrotik-tools to decrypt the username and password database and dump everything IN PLAIN TEXT !!!
Don’t use Mikrotik for start. Not only in poses a security concern for an organization, it will only put IT manager’s computer at great risk because of all the external DLLs it runs (for more info on that check out Slingshot malware). In addition to all this, having your passwords exposed in plain text might have an effect on your other devices. For example, SNMP passphrases are usually the same across multiple devices including Mikrotik. Or even admin password is shared across.