Malware Cleanup to Arbitrary File Upload in Gravity Forms

During our regular cleanup process we came across a reinfection case that caught our attention.

This particular environment didn’t have anything special or fancy, it was an updated WordPress installation and had 3 out-of-date plugins; that’s pretty reasonable.

After running through our processes and cleaning the environment we kept coming back to a reinfection; the attacker kept uploading nefarious files on the server.


This got us very curious and so we had to dig a little deeper.

The malicious files were being uploaded to ‘/wp-content/uploads/gravity_forms’ and ‘/wp-content/uploads’ on Feb 21st, but how?

While Forensics is not a default offering and the client was not using our Website Firewall (which would have prevented the reinfection), we do love a good challenge. So why not investigate when the cases are curious – such as this one. Fortunately, we had access to the logs and were able to find some interesting requests to those particular files.

With that in mind, we started looking for different variations of “_input_” and found a lot requests to those files.


We went back a few days in the logs to find what preceded those requests and where they could have come from.


In analyzing the files, we came across these requests to “?gf_page=upload”; that sounds interesting doesn’t it?

We searched for that string in the file system and found an instance within the WordPress plugin GravityForms (out-dated version 1.8.19).

Gravity Forms is a WordPress plugin used originally for contact forms, but in a more general sense, it allows site owners to create forms to collect information. Gravity Forms can be used for contact forms, WordPress post creation, calculators, employment applications and more.

Written in PHP, Gravity Forms uses many WordPress built-in functions and features to power its form builder. It also uses the same MySQL database system as WordPress, but stores all forms and entries in its own tables.

Gravity Forms is open source and GPL licensed. All of the code included is unencrypted, and easy to modify. We’ve added in tons of hooks and filters to be able to customize Gravity Forms to your hearts content.

Upon further investigation, we found “?gf_page=upload” inside common.php in line 3635.


It was very interesting, not in a good way though; there was no sanitization of that request.

For testing purposes, I requested “?gf_page=upload” to see what would happen and interestingly enough, we got this:


Which lead to searching where the message was being processed.


From checking the upload.php, we see that $_REQUEST[“form_id”] has to be set otherwise the upload fails.
Keep in mind that at this time, we already bypassed any protections that could prevent unauthorized users from accessing that resource.

I set the value of form_id to 1 and made another request in a crafted upload form and this time the error was a little bit different.


As I tried sending a test.php, we hit a function file_name_has_disallowed_extension() that didn’t allow such a file from being uploaded, but we’re stubborn, so let’s not give up.

From checking the declaration of those functions in common.php we found why this happened.

There’s a list of allowed extensions in get_disallowed_file_extensions() that the function file_name_has_disallowed_extension() checks against and php is there.


It basically means that we can’t upload .php files, right? Wrong and let’s see why.

Inside includes/upload.php, we see that we have total control over the filename that is being uploaded as well how the file is saved into the server. The lines 54 and 55 give us such power through simple HTTP requests.

We also see that if $field is empty, the execution dies (59,60), so we set a value 1 to field_id.


After changing the filename from test.php to test.jpg we got a very interesting response.


The file was uploaded to the server but its name is _input_1_, therefore we can’t do much with it.
It turns out that this is how the temp_filename is created:


Breaking that down, we have the following:

$form_unique_id	= We didn't set any value here
_input_			= Hardcoded
$field_id		= We set that 1 as mentioned above
_				= Harcoded
$file_name		= We control this data, therefore we can set .php here

Our $tmp_file_name is ready to go and we finally got what we were looking for! :)



From checking the changelog for gravity forms we see that the security fix was applied in the version (1.8.20) please update soonest:

Gravity Forms v1.8.20 is now available via automatic update and the customer downloads page. This is an important security and maintenance release.
We recommend all users update as soon as possible. It is important to always keep WordPress, plugins and themes up to date as a matter of best practice.

  • Fixed a security issue with the file upload field.

The versions 1.8.19 and lower might be affected by this vulnerability.

We always say that keeping all software updated is one of the most important steps you can take towards reducing the risks of infection and this post is a good example of why.

This is a dangerous vulnerability, you should update all of your websites using this plugin as soon as possible. If for any reason you cannot, we highly recommend you to have a look at our Website Firewall (WAF) product. It’s designed to help you stay ahead of vulnerabilities like the one described here, and many more.

Why Websites Get Hacked

I spend a good amount of time engaging with website owners across a broad spectrum of businesses. Interestingly enough, unless I’m talking large enterprise, there is a common question that often comes up: Why would anyone ever hack my w
Read More

Security Advisory – WP-Slimstat 3.9.5 and lower

The weak 'secret' token

Advisory for: WP-Slimstat Security Risk: Very high Exploitation level: Remote DREAD Score: 8/10 Vulnerability: Weak Cryptographic keys leading to SQL injections Patched Version: 3.9.6 WP-Slimstat's users should update as soon as possible! Duri
Read More

Vulnerability Disclosures – A Note To Developers

This post is entirely for developers. Feel free to read, but approach it with that in mind. There is no such thing as bug-free code. We all make mistakes and every piece of software will have issues that we did not anticipate. We ourselves find
Read More

Analysis of the Fancybox-For-WordPress Vulnerability

Sucuri - Fancybox-for-WordPress Code

We were alerted last week of a malware outbreak affecting WordPress sites using version 3.0.2 and lower of the fancybox-for-wordpress plugin. As announced, here are some of the details explaining how attackers could use this vulnerability to inject ma
Read More

The Dynamics of Passwords

Common Passwords [Source:]

How often do you think about the passwords you’re using? Not only for your website, but also for everything else you do on the internet on a daily basis? Are you re-using any of the same passwords to make it easier to remember them? We see it all
Read More

Analyzing Malicious Redirects in the IP.Board CMS

Although the majority of our posts describe WordPress and Joomla attacks (no wonder, given their market-share), there are still attacks that target smaller CMS’s and we help clean all kinds of sites. This post will be about conditional redirects in I
Read More

Zero-day in the Fancybox-for-WordPress Plugin

Update: We posted an analysis of the vulnerability following this post. Our research team was alerted to a possible malware outbreak affecting many WordPress websites. All the infections had a similar malicious iframe from "203koko" injected into
Read More

Advisory – Dangerous "nonce" leak in UpdraftPlus


Advisory for: UpdraftPlus Security Risk: High Exploitation level: Remote DREAD Score: 7/10 Vulnerability: Privilege Escalation Patched Version: 1.9.51 If you're a user of the UpdraftPlus plugin for WordPress, now is the time to update.
Read More

Creative Evasion Technique Against Website Firewalls

Sucuri - HTML Encoding Example

During one of our recent in-house Capture The Flag (CTF) events, I was playing with the idea of what could be done with Non-Breaking Spaces. I really wanted to win and surely there had to be a way through the existing evasion controls. This post
Read More