8 minute read
This article is the first in a series of four posts I am writing on language-based vulnerabilities. As this series is language-based, I figured I would start it off kind of easy and go with a language I have had some experience with in both development and destruction. That language is PHP.
I, like many who entered the world of hands-on security research in the early-to-mid 2000s, eventually found myself at home on capture-the-flag (CTF) hack challenge sites like hackthissite, hellboundhackers, and the many, many more that followed. The basic idea of each of these sites was to create a series of somewhat realistic sandboxed or simulated website challenges that security enthusiasts like myself could use to improve our coding skills and learn security by practicing hacking and programming techniques at the same time…legally.
The above websites—both of which are still online today—were heavily influenced by the PHP language, which still enjoys some popularity today as both a professional programming language taught in Universities, and is used as a breakthrough language for beginners to learn programming. The reason? I would say PHP’s easy syntax—which is somewhere in between Perl and C—is easy to learn and its logic is great for security enthusiasts to enjoy the forbidden pleasure of cracking software because it does no more or less than you tell it to.
Nowadays, things are a bit different. Vulnerable virtual machines (VMs) released on websites like Vulnhub offer realistic scenarios that the old simulated challenge websites just can’t replicate. Not to mention—as someone who has used both the old-school challenge sites and the newer LiveCD-based challenges—popping a VM, then escalating privileges to root is more gratifying than pouring all your energy into beating one myopic challenge, then advancing to the next. But, I digress. PHP seemed like it was everywhere back then and I guess it could be argued it still is somewhat everywhere—especially if you look into the top five largest content management systems (CMS) in existence today. As of 2017 WordPress holds the largest market share for CMS by far, with about 59 percent of the market. Its two runners up, Drupal and Joomla–are also PHP based web content management systems.
There has been quite a bit written about PHP vulnerabilities and I don’t really intend to revisit what we already know in great depth, but I feel this topic does need to be revisited from time to time because with the majority of CMS being written in PHP and the amount of security training many PHP programmers have, the same question always pops up: “Why so many vulnerabilities, man?!”
Great question. I often wonder the same myself. I guess it could be a “Too many chefs in the kitchen” scenario or it also could be that those writing plugins are not vetted enough (hardly at all really) for skill. Another reason I hear often is the age-old sacrifice of security for functionality. My personal guess is it’s all of these things and probably more, but in any event, (luckily) I am not really here to answer this question.
So, without further ado—here are some modern and not-so-modern PHP vulnerabilities and, of course, how and why they exist.
PHP History and Vulnerabilities
PHP, which stands for Hypertext Preprocessor is a server-side language that was designed by a Danish-Canadian programmer named Rasmus Lerdorf, who—in his mid-to-late twenties—authored the first two versions and also contributed to later versions. Using cvedetails, we can see that in the year 2000 PHP was stricken with two critical exploits—both resulting in command injection. The first CVE, CVE-2000-0967 is a format string vulnerability, which actually is an attack on the C language PHP is written in. Format string attacks enable attackers to work directly on memory addresses, allowing them to read and manipulate memory addresses—usually leading to code execution. We will speak more of format string vulnerabilities when we talk about the C language.
The second vulnerability is CVE-2000-0059, which leads us into the first class of vulnerabilities we will be discussing: command execution vulnerabilities. First, the vulnerability itself is listed as a PHP 3.0.13 safe-mode failure. PHP safe-mode was introduced to help mitigate some of the security issues that are introduced in shared server scenarios. Shared hosting was first introduced as a low-cost way to host your website on a server that hosts other websites on the same server. This is the opposite of a dedicated server, where you have complete control of a host, usually a virtual private server (VPS). Hosts on shared servers usually get FTP access or limited SSH access to a specific domain folder on the shared server. The security ramification that exists to this day on shared servers is the fact that you’re sharing a server with people whose intention you don’t know, people who sign up sometimes with evil intentions-to break the domain security—just to poke around and see if they can break out of their currently restricted directory into yours. This caused many people to run their sites in PHP safe-mode, which disallowed PHP access to system commands. Unfortunately, popen(), which is a method used to execute commands was overlooked and was used in the above exploit.
Most, if not all, PHP vulnerabilities come down to improper sanitization techniques, and command execution is no different. The reality is programmers have to understand that any piece of data that a user has the ability to touch or modify must be sanitized. PHP has multiple functions that are able to interact with the operating system it runs on and execute commands. Some of these functions are shell_exec(), popen(), system(), exec(), backtick operator or `command`, passthru(), eval(), and popen()’s more improved family of process control functions like proc_open(), proc_get_status(), etc. Other functions like the evaluate flag use preg_replace() can also lead to remote code execution in certain situations where older versions of PHP are running, but it has been removed (Deprecated in PHP 5.5, removed in PHP 7) in current versions.
Now, I can see how the preg_replace() bug caused a problem, but in actuality command execution—like many modern web vulnerabilities—should not really exist. As a matter of fact, two functions were introduced to help mitigate the wave of command execution vulnerabilities in PHP4 called escapeshellcmd(), which can be used to escape shell metacharacters and escapeshellarg(), which can be used to escape or sanitize strings used as shell arguments. For example—and I’m going to make the examples as simple as possible—this is a very basic script that is vulnerable to command injection. Its original use is to run a Nameserver lookup (nslookup) on any given host or IP that is fed to its “host” parameter.
And when we pass www.google.com to the host parameter it works as it should by returning the Google nameserver.
The problem is what happens when we pass it unexpected info in one of three ways. We have a few options. Since we’re using a Linux server, we have to stick to the rules of /bin/sh or /bin/bash and use metacharacters to execute a command. We can do this by terminating the expected command with a semicolon and starting our own command like in example one. We can pass it expected data and—when finished—end the command with a semi-colon and build our own command like example two, or by feeding it a bogus command and using a logical OR statement or two pipes. All three methods will result in a success command injection.
- http://vulnserver.com/php/cmd.php?host=;ps aux
We can fix this easily, as mentioned earlier, by just adding the escapeshellarg() function to sanitize the command input. PCRE and preg_match could be used for further validation, but that goes beyond the scope of what we’re discussing.
With our new example, we can throw any of the above example exploits at it and they will be treated as one string, making it close to impossible to break out of the current command context:
Breaking out of the Syntax
Breaking out of the current command syntax is what every attacker is attempting when it comes to almost, if not all forms of code injection. The hacker has to find a way to halt, append, pipe, or insert a syntactically correct piece of code to achieve the goal of code execution. And this requires an understanding of the functionality involved, so many hackers will try to guess what the code looks like on the backend by probing the application and watching how it reacts to unexpected input. Breaking out of the syntax is going to be the primary focus of our next vulnerability, which like many aren’t entirely the fault of PHP and can exist in other languages we will be focusing on in the coming weeks.
It’s a continuous problem in PHP though—almost an epidemic. And although it’s another vulnerability that probably should no longer exist, it does. And not only does it exist, it probably isn’t going anywhere anytime soon. This vulnerability has the ability to wake any system administrator up in the middle of the night everywhere. It is, of course, SQL injection.