Monday, April 20, 2015

Drupageddon: SQL Injection, Database Abstraction and Hundreds of Thousands of Web Sites

http://www.linuxjournal.com/content/drupageddon-sql-injection-database-abstraction-and-hundreds-thousands-web-sites

Drupal is a very widely used open-source content management system. It initially was released in 2001, and recent statistics show Drupal as the third-most popular content management system, with just less than 800,000 Web sites utilizing Drupal as a content management system.
Drupal is written in PHP, and it is architected to use a database back end to store Web site content and settings, whether a full-fledged database management system (such as MySQL) or an embedded DBMS (such as SQLite). In recent versions, Drupal has provided a database abstraction layer in order to facilitate the use of any of a number of database management systems to support a given Drupal installation. Database abstraction layers provide a consistent programming interface that can be used to communicate with a variety of database systems without development of code specific to a given database management system.
Due to vulnerabilities in the database abstraction layer introduced in version 7 of Drupal, Drupal 7 prior to version 7.32 was vulnerable to an SQL injection attack. This article provides an introduction to SQL injection attacks, an examination of the Drupageddon vulnerability specifically and an explanation of a number of potential defenses against SQL injection attacks.

SQL Injection

SQL injection is an attack methodology in which malicious SQL code is included in user input, leading to the execution of said SQL code as part of SQL statements used by an application. SQL injection attacks can lead to privilege bypass and/or escalation, disclosure of confidential information and corruption of database information, among other effects.
Command injection attacks, such as SQL injection, routinely place at or near the top of the OWASP (Open Web Application Security Project) Top Ten List of Web application security risks. SQL injection attacks are likely the most well-known type of command injection attacks, but injection attacks can occur any time data is supplied to an interpreter by an application. The recent Bash vulnerability known as Shellshock is an example of a command injection attack that is not related to SQL injection.

SQL Injection Example

An example SQL injection attack starts with code utilizing an SQL statement, such as:

$db_statement = "SELECT COUNT(1) FROM `users` WHERE 
 ↪`username` = '$username' AND `password` ='$password'";
In an SQL injection attack against code such as this, the attacker supplies input, such as the following, to the application:

$username = "badUser";
$password = "' OR '1'='1";
Using this example, the SQL statement executed becomes the following:

SELECT COUNT (1) FROM `users` WHERE `username`='badUser' 
 ↪AND `password`='' OR '1'='1';
In the above example, this results in returning a count of all rows in the "users" table, regardless of the user name or password supplied, since the conditional '1'='1' always returns as true. If the query shown in this example is used for authentication purposes, the example SQL injection attack has just bypassed the authentication process for the application in question.
SQL injection attacks, and other command injection attacks in general, represent a significant risk for Web applications. Exploitation of SQL injection vulnerabilities is relatively easy for an attacker to perform, and both the attack itself and searches for vulnerable code are easily automated. Additionally, the impact of SQL injection attacks is quite often very severe, as is seen in the authentication example above, as well as in the specific example of Drupageddon.

Drupageddon

The Drupageddon vulnerability officially was discovered by SektionEins GmbH while the company was performing a security audit for a customer that was utilizing Drupal as a content management system. SektionEins GmbH reported the vulnerability to Drupal developers on September 16, 2014. The vulnerability was disclosed publicly by Drupal on October 15, 2014, using the Drupal advisory identifier DRUPAL-SA-CORE-2014-005 and the CVE identifier CVE-2014-3704. The public disclosure included a description of the vulnerability, as well as recommendations for vulnerability mitigation. The primary recommendation for mitigation of this vulnerability was an immediate upgrade to Drupal version 7.32. For administrators of Web sites that could not be upgraded to Drupal version 7.32 immediately, a patch was provided to resolve the SQL injection vulnerability.
SektionEins nicknamed this vulnerability Drupageddon due to the potential impact of exploitation of this vulnerability upon Drupal-based Web sites. (Note: in a number of instances in the press, this vulnerability was referred to as "Drupalgeddon", which is inaccurate. The term "Drupalgeddon" refers to a diagnostic tool intended to be used in order to diagnose Drupal instances that may have been compromised due to the Drupageddon vulnerability.)
Successful exploitation of this attack could result in execution of arbitrary PHP commands, privilege escalation, installation of system backdoors and other exploits. Additionally, exploitation of this vulnerability did not require any sort of successful authentication to the target Drupal instance(s) prior to exploitation.
It was estimated that within several hours of the announcement of the Drupageddon vulnerability, active and automated exploits for this vulnerability were being utilized by attackers to compromise Drupal-based Web sites.
On October 29, 2014, the Drupal Security Team released advisory identifier DRUPAL-PSA-2014-003. This advisory informed administrators of Drupal-based Web sites that all Drupal-based Web sites utilizing vulnerable versions of Drupal should be considered compromised if they were not patched/upgraded before 2300 UTC on October 15, 2014 (seven hours following the initial announcement of the vulnerability in SA-CORE-2014-005).
In the case of the Drupageddon vulnerability, the database abstraction layer provided by Drupal included a function called expandArguments that was used in order to expand arrays that provide arguments to SQL queries utilized in supporting the Drupal installation. Due to the way this function was written, supplying an array with keys (rather than an array with no keys) as input to the function could be used in order to perform an SQL injection attack.
A potential (non-malicious) use of the expandArguments function would be as follows:

$query = "SELECT COUNT(1) FROM `users` WHERE `id` IN (:userids)"; 
$args = [ 'userids' => [ 1, 2, 3, ] ]; 
$db->expandArguments($query, $args);
This would result in the following SQL statement:

SELECT COUNT(1) FROM `users` WHERE `id` IN 
 ↪(:userids_0, :userids_1, :userids_2);
However, by supplying a carefully crafted argument array, an attacker could perform an SQL injection attack:

$query = "SELECT COUNT(1) FROM `users` WHERE `id` 
 ↪IN (:userids)";
$args = [ 'userids' => [ '0); DROP TABLE 
 ↪importantInformation; --' => 1 ], ];
$db->expandArguments($query, $args);
This would result in the following SQL statement:

SELECT COUNT (1) FROM `users` WHERE `id` IN (:userids_0); 
 ↪DROP TABLE importantInformation; --)
The -- marks the remainder of the line as an SQL comment, avoiding the syntax error due to the unmatched right parenthesis. The results of the execution of a malicious query such as this obviously could be catastrophic.

Recommendations

A number of strategies can be used to minimize the risk of SQL command injection attacks. These include input sanitization and whitelisting, use of parameterized queries and defense in depth.

Input Sanitization and Whitelisting:
One strategy that can be used for prevention of SQL injection attacks is the sanitization and whitelisting of user input. This strategy is implemented by analyzing both expected or valid input that will be provided by users as well as input that may be provided by attackers attempting to compromise your Web-based application. Following this initial analysis, sanitization code will need to be added in order to remove or escape any harmful/unwanted input by a user prior to use of said input in any database queries. In the case of the SQL injection example given earlier in this article, there are two potential sanitization and whitelisting processes that could be utilized.
In the SQL injection example given earlier, let's assume you previously have told users of the Web application that valid characters for user names are a–z, A–Z, 0–9 and ".". This would represent an excellent opportunity for the use of whitelist-based input validation. In this method of input validation, you would construct a whitelist of allowed characters for the user input and would allow only user input limited to those characters to be passed to the database for processing. In this case, you either would discard any characters provided by users as their user name aside from a–z, A–Z, 0–9 and ".", or you simply would refuse to perform any processing following user input that includes any characters that are not included in your whitelist of allowed characters. Using this example, an attack in which the following is provided as input for the username value:

$username = "x'; DROP TABLE importantInformation; 
 ↪SELECT * FROM users WHERE username = 'badUser'";
$password = "Test";
either would be refused or would be sanitized (if inappropriate characters are discarded) to the following:

$username = "xDROPTABLEimportantInformation
↪SELECTFROMusersWHEREusernamebadUser";
If sanitization is used in this example, this would result in the following SQL statement being executed:

SELECT COUNT(1) FROM `users` WHERE `username`=
↪'xDROPTABLEimportantInformationSELECTFROMusersWHEREusernamebadUser' 
 ↪AND `password`='Test';
Without sanitization, the following SQL statements would be executed:

SELECT COUNT(1) FROM users WHERE username='$username = 
 ↪"x'; DROP TABLE importantInformation; SELECT COUNT(1) 
 ↪FROM users WHERE username = 'badUser' AND password = Test';
This results in two SELECT statements being executed, and also results in the deletion of the importantInformation table.
(Note: this SQL example also represents other security problems in that passwords in the database appear to be stored in plain text. However, that is outside the scope of this article, and encryption of passwords would have no impact on vulnerability to SQL injection attacks.)
In the user authentication example, additional processing is needed in order to handle the password provided by the user, however. Assuming that you allow all keyboard characters in an effort to allow for as complex passwords as possible, you cannot simply refuse password input containing potentially dangerous characters. In this case, you will want to sanitize user input by escaping said input prior to query processing. In this example, the following input:

$username = "badUser";
$password = "' OR '1'='1";
would become escaped to the following:

$username = "badUser";
$password = "\' OR \'1\'=\'1";
This then would result in the following SQL statement being executed:

SELECT COUNT (1) FROM users WHERE username='badUser' 
 ↪AND password='\' OR \'1\'=\'1';
This version of the SQL statement would result in returning a count of the number of rows in the users table where the contents of the user name field is equal to the string "badUser", and the contents of the password field are equal to the literal string "' OR '1'='1" (that is, the attack has been blocked).
Use of Parameterized Queries
Another strategy for guarding against SQL injection is the use of parameterized queries. With parameterized queries, SQL statements are predefined and stored on the database server with placeholders representing the parameters that will be utilized in the query. When it comes time for the SQL statement(s) in question to be executed, relevant user input is added to the queries prior to execution, with any relevant escaping of user input being handled automatically by the database server.
In the user authentication example shown previously, the parameterized version of the query would resemble something like the following:

SELECT * FROM users WHERE username=?un? AND password=?pw?;
When it comes time for the SQL statement to be executed, the database management system performs any escaping needed for the parameter(s) in question, and the SQL statement then is executed with the escaped parameter(s) taking the place of the placeholders.
Defense in Depth:
At a very high level, the best plan for preventing SQL injection attacks is an overall strategy of defense in depth. This approach relies on deploying a number of different defense mechanisms simultaneously, with the overall strategy being that if an attacker is able to defeat one of the defense mechanisms, the other defense mechanisms still will be in place and still will be able to defend against/detect attempted attacks. In the example of Drupageddon, the following parallel defense strategies in addition to the previously mentioned defense strategies would have helped to minimize the risk of system compromise due to SQL injection.
  • System and Application Updates: Keeping systems and applications current with updates is one of the first lines of defense that should be implemented by individuals and organizations in order to prevent system and application compromises. In the case of Drupageddon, either upgrading to Drupal version 7.32 or installing the patch provided by Drupal developers would have mitigated against the Drupageddon vulnerability immediately. Although the Drupageddon vulnerability existed since 2011, there is no evidence of any significant exploitation of the vulnerability until after the public disclosure of Drupageddon by SektionEins.
  • Intrusion Detection Systems: Most current intrusion detection systems include functionality to detect attempted SQL injection attacks. These systems can provide early warnings of attempted SQL injection attacks, and if paired with intrusion prevention functionality, often can prevent the attacks from occurring.
  • Limitation of Database Privileges: Privileges of database users used for applications should be limited to as restrictive a set of privileges as possible that will allow for the performance of required database activities in order to support the functionality of the application. For instance, if the only database activities that are required for the application in question are reads from the database, consider limiting the database account used by the application to a read-only account. This will not prevent SQL injection attacks aimed at inappropriate access to information, but it will prevent SQL injection attacks that are intended to cause unauthorized changes to the database.
  • System and Application Monitoring: Although system and application logging and monitoring will not, in and of themselves, prevent an SQL injection attack from occurring, they will help in the process of detecting attempted attacks. Additionally, use of functionality like file integrity monitoring can help detect the results of system compromises due to SQL injection attacks.
  • Code Audits: Auditing of source code utilized in an application can help identify security vulnerabilities in the application in question. In fact, the Drupageddon vulnerability was discovered due to a source code audit that was performed against the Drupal code base. Source code audits typically should be performed by a party other than those responsible for the creation of the source code in question, as this provides a fresh perspective on the source code. Unfortunately, source code audits usually are very expensive and time-consuming.

Resources

Usage of Content Management Systems for Web Sites: http://w3techs.com/technologies/overview/content_management/all
Drupal Usage Statistics: http://trends.builtwith.com/cms/Drupal
OWASP Top Ten List: https://www.owasp.org/index.php/Top_10_2013-Top_10"
SA-CORE-2014-005 — Drupal Core — SQL Injection: https://www.drupal.org/SA-CORE-2014-005
Drupal Core — Highly Critical — Public Service announcement — PSA-2014-003: https://www.drupal.org/PSA-2014-003
Drupalgeddon: https://www.drupal.org/project/drupalgeddon
Advisory 01/2014: Drupal — Pre Auth SQL Injection Vulnerability: https://www.sektioneins.de/en/advisories/advisory-012014-drupal-pre-auth-sql-injection-vulnerability.html
Drupal 7.31 Pre Auth SQL Injection Vulnerability: https://www.sektioneins.de/en/blog/14-10-15-drupal-sql-injection-vulnerability.html
Drupal 7.32 Two Weeks Later — PoC: https://www.sektioneins.de/en/blog/14-11-03-drupal-sql-injection-vulnerability-PoC.html

Wednesday, April 8, 2015

Not So Dynamic Updates

http://www.linuxjournal.com/content/not-so-dynamic-updates

Typically when a network is under my control, I like my servers to have static IPs. Whether the IPs are truly static (hard-coded into network configuration files on the host) or whether I configure a DHCP server to make static assignments, it's far more convenient when you know a server always will have the same IP. Unfortunately, in the default Amazon EC2 environment, you don't have any say over your IP address. When you spawn a server in EC2, Amazon's DHCP server hands out a somewhat random IP address. The server will maintain that IP address even through reboots as long as the host isn't shut down. If you halt the machine, the next time it comes up, it likely will be on a different piece of hardware and will have a new IP.

dhclient Overrides

To deal with this unpredictable IP address situation, through the years, I've leaned heavily on dynamic DNS updates within my EC2 environments. When a host starts for the first time and gets configured, or any time the IP changes, the host will update internal DNS servers with the new IP. Generally this approach has worked well for me, but it has one complication. If I controlled the DHCP server, I would configure it with the IP addresses of my DNS servers. Since Amazon controls DHCP, I have to configure my hosts to override the DNS servers they get from DHCP with mine. I use the ISC DHCP client, so that means adding three lines to the /etc/dhcp/dhclient.conf file on a Debian-based system:

supersede domain-name "example.com";
supersede domain-search "dev.example.com", "example.com";
supersede domain-name-servers 10.34.56.78, 10.34.56.79;
With those options, once the network has been restarted (or the machine reboots), these settings will end up in my /etc/resolv.conf:

domain example.com
search dev.example.com. example.com
nameserver 10.34.56.78
nameserver 10.34.56.79
p I've even gone so far as to add a bash script under /etc/dhcp/dhclient-exit-hooks.d/ that fires off after I get a new lease. For fault tolerance, I have multiple puppetmasters, and if you were to perform a DNS query for the puppet hostname, you would get back multiple IPs. These exit hook scripts perform a DNS query to try to identify the puppetmaster that is closest to it and adds a little-known setting to resolv.conf called sortlist. The sortlist setting tells your resolver that in the case when a query returns multiple IPs to favor the specific IP or subnets in this line. So for instance, if the puppetmaster I want to use has an IP of 10.72.52.100, I would add the following line to my resolv.conf:

sortlist 10.72.52.100/255.255.255.255
The next time I query the hostname that returns multiple A records, it always will favor this IP first even though it returns multiple IPs. If you use ping, you can test this and see that it always pings the host you specify in sortlist, even if a dig or nslookup returns multiple IPs in random order. In the event that the first host goes down, if your client has proper support for multiple A records, it will fail over to the next host in the list.

dhclient Is Not So Dynamic

This method of wrangling a bit of order into such a dynamic environment as EC2 has worked well for me, overall. That said, it isn't without a few complications. The main challenge with a system like this is that the IPs of my DNS servers themselves might change. No problem, you might say. Since I control my dhclient.conf with a configuration management system, I can just push out the new dhclient.conf. The only problem with this approach is that dhclient does not offer any way that I have been able to find to reload the dhclient.conf configuration file without restarting dhclient itself (which means bouncing the network). See, if you controlled the DHCP server, you could update the DHCP server's DNS settings, and it would push out to clients when they ask for their next lease. In my case, a DNS server IP change meant generating a network blip throughout the entire environment.
I discovered this requirement the hard way. I had respawned a DNS server and pushed out the new IP to the dhclient.conf on all of my servers. As a belt-and-suspenders approach, I also made sure that the /etc/resolv.conf file was updated by my configuration management system to show the new IP. The change pushed out and everything looked great, so I shut down the DNS server. Shortly after that, disaster struck.
I started noticing that a host would have internal health checks time out; the host became sluggish and unresponsive, and long after my resolv.conf change should have made it to the host, it seemed it was updating the file again. When I examined the resolv.conf on faulty systems, I noticed it had the old IP scheme configured even though the DNS servers with that information were long gone. What I eventually realized was that even though I updated dhclient.conf, the dhclient script itself never grabbed those changes, so after a few hours when it renewed its lease, it overwrote resolv.conf with the old DNS IPs it had configured!

The Blip Heard Round the World

I realized that basically every host in this environment was going to renew its lease within the next few hours, so the network needed to be bounced on every single host to accept the new dhclient.conf. My team scrambled to stage the change on groups of servers at a time. The real problem was less that dhclient changes required a network blip, but more that the network blip was more like an outage that lasted a few seconds. We have database clusters that don't take kindly to the network being removed. At least, they view it (rightly so) as a failure on the host and immediately trigger failover and recovery of the database cluster. The hosts seemed to be taking way longer than they should to bounce their network, were triggering cluster failovers, and in some cases, required some manual intervention to fix things.
Fortunately for us, this issue affected only the development environment, but we needed to respawn DNS servers in production as well and definitely couldn't handle that kind of disruption there. I started researching the problem and after confirming that there was no way to update dhclient.conf without bouncing the network, I turned to why it took so long to restart the network. My dhclient-exit-hook script was the smoking gun. Inside the script, I slept for five seconds to make sure the network was up and then performed a dig request. This meant that when restarting the network, the DNS queries configured for the old IPs would time out and cause the host to pause before the network was up. The fix was for me to replace the sleep and dig query with a template containing a simple echo to append my sortlist entry to resolv.conf. My configuration management system would do the DNS query itself and update the template. With the new, faster script in place, I saw that my network restarts barely caused a network blip at all. Once I deployed that new exit hook, I was able to bounce the network on any host without any ill effects. The final proof was when I pushed changes to DNS server IPs in production with no issues.

Tuesday, April 7, 2015

How to Decompile a Video File Into Images with FFMPEG on Linux

http://www.maketecheasier.com/decompile-video-file-linux

Have you ever recorded a video clip and then wondered “How do I turn this entire thing into individual images?” If so, this guide is probably what you’re looking for. You see, there’s a tool out there called FFMPEG. It is a video tool and can be used for a multitude of things.
This includes decompiling videos. I’ve yet to come across a more efficient way to take a video file and turn it into a mass of still images. It’s a simple command line operation, one that might need to be tweaked and experimented with depending on what you want.
Before we can start the operation, you’ll need to have FFMPEG installed on your system. As this tool is quite popular, you should have no problem finding this software in your Linux distribution’s package repository. Search for ffmpeg.
Once that’s done, find the video file you are looking for to decompile and launch a terminal window. Inside the terminal window, enter this command:
ffmpeg -i videoname.filetype image%d.png
Launch a terminal window.
Note: it’s a good idea to move your video file into a separate folder away from all your other files. FFMPEG will turn your video into thousands of frames that you will need to sort through.
If this command looks confusing, it’s because it hasn’t been configured. For starters, you’ll need to change videoname.filetype to whatever your video file is called (like video.mp4, etc.).
Another thing you can change is the file type the frames will be saved as. The command has it set to the PNG image format. If you prefer something a little more memory conscious, consider changing this part of the command to image%d.jpg.
The FFMPEG tool will spit out thousands of image files.
Once you’ve tweaked your command to your liking, just run it. The FFMPEG tool will take your video and spit out thousands of image files, one for each second of the video. This might take a long time (depending on your Computer power as well as video length), so be patient.
Want to make a GIF animation out of the video you just decompiled? It’s very possible. All you really have to do is import some of your extracted frames into the Gimp image editor and create an animation. From there you can share your image with your friends. It’s a neat trick, really.
Import some of your extracted frames.
You can also import your frames as an image sequence in both OpenShot and Kdenlive. This sounds pointless on the surface, but it’s actually quite useful. For example: you have a video file in a less-than-stellar format. Why not just rip the audio, convert the video to frames then recompile them together in formats you actually like? The possibilities are endless!
FFMPEG is an awesome tool with a seemingly unending utility. I have troubling finding out exactly what this tool can’t do! Decompiling video frames is just one example of the many cool things that it can do!
Do you know any FFMPEG secrets? Post them in the comments below!