Form Maker's Fatal Flaw: When Drag & Drop Drags You Down

Uncovering a Remote Code Execution Vulnerability in WordPress' Form Maker Plugin

Cory Marsh
Cory Marsh
Share:
Cory Marsh has over 20 years Internet security experience. He is a lead developer on the BitFire project and regularly releases PHP security and programming videos on BitFire's you tube channel.
...
form-maker, 60,000 sites hacked
Arbitrary File Upload Unauthenticated Exploit Code Available

If you're part of the 60,000 WordPress blogs using the Form Maker by 10Web plugin, you might want to sit down for this. I'm going to delve into a potentially game-changing vulnerability that could open up your entire web server to remote code execution. Yes, you read that right: remote code execution. This isn't about bypassing weak passwords or executing simple XSS; we're talking about the capacity for full server control.

View CVE Report: CVE-2023-XXXX

View On WordPress.org: form-maker

View On Trac: plugins.trac.wordpress.org


Form Maker by 10Web – Mobile-Friendly Drag & Drop Contact Form Builder

"Form Maker is the leading drag & drop plugin for building forms of any complexity in just a few clicks. ooking for the perfect form plugin that’ll save you time and effort? Is matching your website design with your forms difficult? Finding it hard to build lengthy and advanced forms?"

-- form-maker
  • Intuitive Interface
  • Mobile-Friendly and Responsive
  • Field Types
...
...
...

If you are going to allow file uploads, authenticate first. If you are authenticating uploads, make sure they aren't PHP files. Form Maker did neither...


BitFire's 0-day protection of CVE-2023-XXXX vulnerability

The Anatomy of the Flaw

The security lapse lies in a function amusingly named save_db(), which comes into play when you're saving a form. This function is supposed to handle the input types, one of which is 'type_signature.' It is this 'type_signature' case where things go south, as the function fails to validate file types sufficiently. Now, for anyone familiar with web security, improper file validation is like leaving your car unlocked with the keys in the ignition.

What Does This Mean Practically?

In the absence of adequate file type validation, an attacker could upload arbitrary files to the server. Now, if you're thinking 'So what? It's just a file,' allow me to disillusion you. With insufficient file extension checking, PHP files can be uploaded, paving the way for remote code execution. In layman's terms, this allows a cybercriminal to potentially run commands on your server. It's the equivalent of giving them the master key to your digital kingdom.

Versions up to, and including, 1.5.19

If your plugin version reads any number up to 1.5.19, you're at risk. A proactive approach to security is not about if an attacker will exploit this vulnerability but when. The phrase 'actively being exploited' is frequently thrown around in the cybersecurity world, but in this context, it's not hyperbole.

What Next?

Firstly, if you're using Form Maker by 10Web, update it. Now. If for some reason you can't, disconnect it until you can. Cybersecurity is not a game of luck; it's a game of strategy and timing. Make your move before an attacker makes theirs.

What's equally concerning is that this is not an isolated issue. Plug-and-play solutions like WordPress plugins are increasingly becoming the soft underbelly of web security. While they offer unparalleled convenience, they also offer a wide attack surface for those looking to exploit these exact kinds of vulnerabilities.

So the next time you're browsing through the WordPress plugin repository, remember that the biggest threats in cybersecurity often start as the smallest oversights. Keep your systems updated, and be sure your site is runing a RASP firewall.

Removed Code
/frontend/models/form_maker.php
<?php $base64_data = str_replace( ' ', '+', $base64_data ); $base64_data = base64_decode($base64_data); $file_name = 'signature-'. WDW_FM_Library(self::PLUGIN)->generateRandomStrOrNum(10, true) . '.' . $type; $file_path = $upload_dir['basedir'] . '/' . $destination . '/signatures/' . $file_name; if ( !empty($base64_data) ) { $save_signature_file = file_put_contents($file_path, $base64_data); if ( $save_signature_file ) { $value = str_replace($upload_dir['basedir'], $upload_dir['baseurl'], $file_path); } }
Replaced Code
generateRandomStrOrNum(10, true) . '.' . $type; $file_path = $upload_dir['basedir'] . '/' . $destination . '/signatures/' . $file_name; if (!empty($base64_data)) { $save_signature_file = file_put_contents($file_path, $base64_data); if ($save_signature_file) { $info = getimagesize($file_path); if ( isset($info['mime']) && ($info['mime'] == 'image/png' || $info['mime'] == 'image/jpg') ) { $value = str_replace($upload_dir['basedir'], $upload_dir['baseurl'], $file_path); } else { unlink($file_path); } } } }