Security Risk: Dangerous
Exploitation Level: Easy/Remote
DREAD Score: 6/10
Vulnerability: SQL Injection
Patched Version: 220.127.116.11
Vulnerability Disclosure Timeline:
- August 11th 9:35 am, 2016 – Initial report to the Ninja Forms team
- August 11th 2:49 pm, 2016 – Public release of version 18.104.22.168, fixing the vulnerability
Are You at Risk?
The attack vector used to exploit this vulnerability requires the attacker to have an account on the victim’s site. It doesn’t matter what the account privileges are – for example, a subscriber could exploit this issue. The issue occurs because the plugin doesn’t escape parameters provided by its shortcodes before concatenating it to an SQL query.
A malicious individual using this bug could (among other things) leak the site’s usernames and hashed passwords. In certain configurations, it can also leak WordPress secret keys.
SQL injections tend to be trickier to find in popular plugins now than they used to be, partly due to the increasing popularity of prepared statements like $wpdb->prepare(). That’s why when we stumbled upon the following snippet of code, we thought it could be interesting to investigate a bit further:
As you can see, the $meta_value variable (which contains the content of $form_id) is concatenated to the SQL query without being escaped first.
We found the function being used in a couple of places with direct user input as its first argument. While this would have been an SQL injection by itself in other PHP applications, it’s not the case with WordPress as it automatically escapes $_GET, $_POST and $_REQUEST when booting up. So we had to look a bit further to find some snippets that could be exploited. That’s when we found this snippet:
Basically speaking, it registers the shortcode ninja_forms_display_sub_number using the WordPress Shortcode API and sets its callback function to the one we see above. From there, $atts contains the list of parameters the shortcode contains in their raw, unescaped value. This means if a user wrote a post containing a shortcode like [ninja_forms_display_sub_number id=”123′ SQL INJECTION OCCURS HERE”], he could perform an SQL injection attack.
Now, it isn’t that much of a big vulnerability if it’s restricted to more privileged users, so we had to dig deeper to find out how we could use this attack with less privileged accounts.
That’s when we found this function in WordPress core. It’s accessible by sending a POST request to /wp-admin/admin-ajax.php using the parse-media-shortcode POST action parameter. As you may understand from the code, it allows any user to execute any shortcodes they want (using do_shortcode), as long as it’s not embedded. To access this snippet one would need to POST a request like:
Using this attack vector, the attacker would be able to exploit the vulnerability with low-privileged accounts, like subscribers.
Update as Soon as Possible
If you’re using a vulnerable version of this plugin, yes, update as soon as possible! In the event where you cannot do this, we strongly recommend leveraging the Sucuri Firewall or equivalent technology to have the vulnerability patched virtually.