Bonus Vulnerability: More Backdoor Creation
But wait. There’s more!
There’s a way to create the backdoor without throwing an old exploit. There was a bug in package installation that allowed an attacker to create arbitrary directories on the system.
First you need to understand how Mikrotik’s npk packages are put together. For a nice graphic, I’ll refer you to Kirils Solovjovs’ github. Otherwise, I wrote a tool called ls_npk:
albinolobster@ubuntu:~/routeros/ls_npk/build$ ./ls_npk -f ~/packages/6.45.5/all_packages-x86-6.45.5/advanced-tools-6.45.5.npk total size: 295802 ———–
0: (1) part info, size = 36, offset = 8 -> advanced-tools
1: (24) channel, size = 6, offset = 2c
2: (16) architecture, size = 4, offset = 32
3: (2) part description, size = 51, offset = 36
4: (23) digest, size = 40, offset = 69
5: (3) dependencies, size = 34, offset = 91
6: (22) zero padding, size = 3869, offset = b3
7: (21) squashfs block, size = 114688, offset = fd0
8: (4) file container, size = 176931, offset = 1cfd0
9: (9) signature, size = 68, offset = 482f3
The individual sections aren’t important to this discussion. What is important is that a SHA-1 hash is computed over all the sections up to the signature section (9). The SHA-1 and a signature are stored in section 9, therefore ensuring the package is valid and secure.
Except for a few small mistakes. First, MikroTik fails to include the first 8 bytes of the file in the SHA-1. These bytes contain the file’s magic bytes (0xbad0f11e) and the total length of the file. Furthermore, RouterOS stops computing the package’s SHA-1 once it hits the signature section. Meaning, an attacker can append arbitrary data to an npk and it won’t invalidate the signature verification scheme.
When I realized this, I was really excited. I thought I was going to be able to add my own squashfs block (22) to the package. Alas, due to the way the logic is laid out, RouterOS won’t parse an attacker added squashfs block. But it will parse an appended “part info” field (1).
Part info is made up of three fields and some amount of padding:
- 16 bytes on name.
- 4 bytes of version
- 4 bytes of timestamp
Every time the router reboots it will parse this the npk package and use the “name” field to create a directory in /ram/pdb/.