Back in August we wrote about a security bugfix for Mikrotik routers that was reverse engineered and turned into a working exploit.
Indeed, patches that fix security vulnerabilities often end up giving away enough about the vulnerability that both good guys and bad guys alike can weaponise it from first principles – all without having to figure out the vulnerability in the first place.
In the August 2018 case, dubbed CVE-2018-14847, a crook could trick an unpatched Microtik router into coughing up the contents of any file on the device, including the password file.
Worse still, the password file included plaintext passwords, with no salting, hashing or stretching, meaning that a security bypass bug could be parlayed into a credential compromise.
Unlike a dreaded “zero-day” exploit, however, which comes out before any patch and thus gives zero days during which you could have been ahead of the game, an exploit that only comes out because of a patch is, at least in theory, easily avoided.
If you’d patched your Mikrotik router promptly, the what-were-they-thinking proof-of-concept exploit created by researchers known as @n0p and @yalpanian would have been harmless against your device.
💡 LEARN MORE: How to store your users’ passwords safely ►
The perils of late patching
What we didn’t know back then was that security researchers at Tenable had responsibly disclosed another bunch of Mikrotik router bugs at about the same time.
These bugs were serious – indeed, one of them allows a attacker to run any program of their choosing, just by making a web request to the router.
This sort of hole is known, for rather obvious reasons, as an RCE, short for Remote Code Execution.
Tenable’s bugs, however, were what’s known as “authenticated vulnerabilities”, meaning that you had to be logged in first in order to be able to exploit them.
Security holes that require pre-authentication may seem harmless at first sight – after all, if you already have a username and password, or some other access token, that gives you access to a system…
…well, you’re already in, so it sounds as though breaking in again can be dismissed as an irrelevancy.
But even vulnerabilities open only to authenticated users can be very serious, because:
- They can often be abused for elevation of privilege, turning low-powered, read-only or guest accounts into superuser, all-powerful admin accounts.
- They can often be chained together with with unauthenticated vulnerabilities to get that low-powered, read-only or guest access in the first place.
The good news is that Mikrotik has already patched Tenable’s now-disclosed bugs, dubbed CVE-2018-1156, -1157, -1158 and -1159.
Make sure you have the latest Mikrotik firmware updates, which are: 6.40.9, 6.42.7 or 6.43, depending on whether you’re using the current, previous or pre-previous version.
If you’re a Mikrotik user, skipping the latest patch leaves you at risk, but if you still haven’t applied the previous patch, you’re in double trouble.
With both patches missing, you’re open to an unauthenticated password disclosure bug that could then be chained with the newer authenticated remote code execution bug.
In other words, instead of anyone being able to get some access, or some people being able to get full access, anyone could get full access by pivoting from CVE-2018-14847 to CVE-2018-1156, the RCE flaw.
A reminder to programmers
By the way, the RCE hole found by Tenable involved the misuse of a C function called
sprintf(), pronounced ESS-PRINT-EFF and short for “Formatted PRINT into a String”.
The word string is jargon for a memory buffer used for storing text such as prompts, log messages, usernames, error descriptions and so on.
The problem with
sprintf() is that it assumes there is enough memory available in the memory buffer you’re writing into for the message that the function will create.
Consider a fragment of C like this:
char *name; // A memory buffer already containing a name., e.g. 'DUCK' char buff; // Some space reserved for the message with the name in it sprintf(buff, "Hello %s", name);
This takes the text string referred to by the variable
name and inserts it at the point denoted by the special marker characters
%s in the second string. (Other markers such as
%f can be used to get neatly laid-out integer Digits and Floating point numbers, also known as decimals, respectively.)
You can see the problem here – there are only 16 characters allocated for
buff, so anyone who puts in a name that’s longer than nine characters will overflow the memory buffer.
Count five characters for
Hello, plus a space, plus nine characters for
name, plus the zero byte (the ASCII
NUL character) that C automatically adds to denote the end of a string, and you have 16 bytes. That’s already enough to fill up the 16-byte buffer, so any more than nine characters in the variable
name will provoke an overflow.
If you’re a C programmer, you shouldn’t be using
sprintf() any more – only use string functions that allow you to specify a maximum number of bytes to copy.
These functions typically have an
-n- in their name somewhere, short for “copy at most N bytes even if there are characters left uncopied or unprinted”, or an
-l- to mean “Limit the Length of the resulting string.”
char *name; // A memory buffer already containing a name., e.g. 'DUCK' char buff; // Some space reserved for the message with the name in it snprintf(buff, sizeof buff, "Hello %s",name)
The C operator
sizeof does what you might expect, and automatically works out how much memory space is available in
snprintf() function above copies at most
(sizeof buff)-1 bytes into
buff, always keeping one byte at the end spare, where it puts the
NUL character that ends off the string, so you never end up with unterminated text. In the special case that the size given to
snprintf() is zero, no bytes at all are written into
buff – the function simply does nothing.
As an aside, even though you can control the amount of data copied, and thereby prevent buffer overflows, just using “string counting” functions such as
snprintf() is not security enough.
As the Unix manual pages put it:
It may be a security concern for a string to be truncated [… T]he truncated string will not be as long as the original, [so] it may refer to a completely different resource and usage of the truncated resource could result in very incorrect behaviour.
Blindly relying on a filename from which the extension has been chopped off, for example, could have all sorts of unintended consequences.
Always check for incorrect or incomplete string operations as well as doing your best to prevent buffer overflows.
There’s not much point in suppressing one bug if, by doing so, you introduce another.
What to do?
- Patch early, patch often. One missed patch is bad; two missed patches are worse, and may end up turning two limited-risk vulnerabilities into a combined security hole that offers crooks an all-powerful, no-holds-barred exploit.
- Don’t use known-bad C functions in your code. Most C compilers will warn you about dangerous and deprecated functions when you build your program – heed their advice.