The Bugs Behind the Vulnerabilities – Part 1
It’s common to hear about new vulnerabilities and exploits, some of which even get fancy names of their own, but sometimes the details of how they appear are buried under proof-of-concept code and impact scores.
This series of articles will demystify these hidden bugs by providing insight into the actual code issues that are at the bottom of most security vulnerabilities that impact systems everywhere.
We could go over distinct code bugs and errors in any order we like. But Mitre has published a list of the top 25 most dangerous bugs in 2022, and that is as good a list as any, so we’ll go over it – explaining how code issues lead to each of these bugs and pointing to some vulnerabilities that arise from having such code in an application.
In this first installment of this series, we will look at entries 25 to 21 in the 2022 Top 25 Most Dangerous Bugs, according to Mitre.
25 – Improper Control of Generation of Code (‘Code Injection’)
This is a common issue where a programmer does not provide sufficient defensive code in regards to user-fed inputs – that is, the software uses whatever input it receives without sanitizing it and then uses said input, as-is, to feed internal functionality.
At a very low level, specially crafted inputs can change the way the program operates in unforeseen ways, letting users have more control over the program, and in some cases the whole system, as a result.
This leads to situations where input is carefully constructed to introduce undesired side effects, like data corruption or unintended program flow changes.
A very common special case of this type of bug is “SQL injection”, which merits a category of its own further ahead in this series of articles, but is nothing more than a special case of code injection.
As an example, the use of “eval()” in PHP is often a code “smell” that points to a possible code injection situation if the value passed is not properly validated beforehand.
24 – Improper Restriction of XML External Entity Reference
XML files can contain references to external documents as part of their structure, but this can lead an application to load documents outside the intended scope. This can potentially result in path traversal problems, improper file accesses, or wrong data being taken as good by the application.
This applies to URIs (Unique Resource Identifiers) that point to other local files or even to files on the Internet by using file:// or http:// URIs.
In addition to allowing access to otherwise unreachable files, it can also be used to force the application to process inordinate amounts of data by feeding it unexpectedly large documents, slowing it down, or even making such applications unresponsive.
If the application does not guard against it, it becomes possible to exploit a system by crafting an XML file like:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <stockCheck> <productId>&xxe;</productId> </stockCheck>
And then observing the result.
[This example comes from https://portswigger.net/web-security/xxe.]
If the target server is able to access other internal systems that an attacker would normally not be able to access, then this bug could be leveraged as a stepping stone to obtain information from those systems.
Bug 23 – Uncontrolled Resource Consumption
All resources available to an application are limited: processing power, storage, network bandwidth, memory capacity, database connections, etc.
If the application can be tricked into abusing one or more of those resources, then it can exhaust them and make the application, or in some cases the whole system, appear unresponsive or outright unusable.
It can appear in code as compute-intensive functions not being guarded against repeated calls (while previous calls haven’t completed yet), or even functions that generate a disproportionate amount of data from very small inputs (for example, complex error messages from single character mistakes), which are both potential sources for this type of bug.
Another common manifestation of this bug is when an application does not dispose of resources it allocated, leading to out-of-memory errors or something similar.
This is a particularly egregious type of bug that is often hard to diagnose before an application reaches the production stage – or due to improper testing – and one that can potentially leave an application in a crashed, or even worse, unexpected state.
Most static code analysis tools will have checks in place to detect this type of situation, but as code can be written in many different ways, it is always possible to have such convoluted code that these analysis tools will be unable to detect it.
Bug 22 – Concurrent Execution Using Shared Resource with Improper Synchronization (“Race Condition”)
When multiple applications try to use the same resource, or even multiple threads inside the same application, some form of coordination has to take place to make sure that each one will have the access it needs for as long as it needs to have it.
If not, it can lead to situations where one application will start writing to a file at the same time as another application and in the end you either have a mix of the content that you were supposed to have in the file, only the content from one of the applications, or even just a blank file.
As this type of situation is very load dependent, it is also difficult to reproduce and identify adequately.
It can affect any type of resource, not just files. For example, it can impact in-memory data, networking, databases – so much so that many language-specific constructs have been added over time to address this situation with the ultimate goal of creating a type of access called “atomic”, which is guaranteed to happen completely or not at all, thus making sure no partial reads/writes occur.
Something as simple as increasing a variable value (x++) is actually prone to this type of issue, as the actual operation is broken down into multiple machine level operations (reading the original value of x, incrementing it, assigning the new value back to x). If x was a variable shared by multiple threads inside an application, then it could lead to bugs if multiple threads tried to increment it at the same time.
Language constructs like mutexes, semaphores, and other thread synchronization mechanisms were introduced specifically to address this type of problem. Based on the prevalence of vulnerabilities that comes from this class of bugs, the successful implementation of such constructs may be less than ideal.
Bug 21 – Server-Side Request Forgery (SSRF)
Servers can be tricked into sending responses to queries to other destinations different from the original requesters’ address.
As was described earlier, in bug #24, it is possible to have an application access other content by including URIs in specially crafted XML files. If those files reside in a third-party location, then the request will appear to come from the server processing the XML file rather than the attacker’s system. While not the only bug that falls under this category, it is a clear example of a server/application being tricked into starting a connection with a third-party system.
Any input that can contain a list of URIs that are not properly validated can be used as an SSRF mechanism.
For example, the M3U file format can include references to external files. If you had a video encoding web service that accepts an M3U file as the content list, it would be possible to include a reference to system files otherwise inaccessible and have those included as part of the output of the web service.