CVE-2018-4019, CVE-2018-4020, CVE-2018-4021
Three exploitable command injection vulnerabilities exists in the way Netgate pfSense CE 2.4.4-RELEASE processes the parameters of a specific POST request. The attacker can exploit this and gain the ability to execute arbitrary commands on the system. An attacker needs to be able to send authenticated POST requests to the administration web interface in order to abuse these vulnerabilities.
Netgate pfSense CE 2.4.4-RELEASE
7.2 - CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
PfSense is a popular open-source firewall and router distribution based on the FreeBSD operating system.
When processing requests to /system_advanced_misc.php
, the firewall does not properly sanitize the certain POST parameters.
powerd_normal_mode
POST parameterThe firewall does not properly sanitize powerd_normal_mode
POST parameter:
<?php
if ($_POST) {
unset($input_errors);
$pconfig = $_POST;
if ($_POST['powerd_enable'] == "yes") {
$config['system']['powerd_enable'] = true;
else
unset($config['system']['powerd_enable']);
$config['system']['powerd_normal_mode'] = $_POST['powerd_normal_mode'];
activate_powerd();
As you can see above, system_advanced_misc.php
will set $config['system']['powerd_enable']
to true if $_POST['powerd_enable']
is set to yes
.
It will also set the $config['system']['powerd_normal_mode']
to the value of the POST parameter powerd_normal_mode
.
It will then call activate_powerd()
:
function activate_powerd() {
global $config, $g;
if (is_process_running("powerd")) {
exec("/usr/bin/killall powerd");
if (isset($config['system']['powerd_enable'])) {
$ac_mode = "hadp";
if (!empty($config['system']['powerd_ac_mode'])) {
$ac_mode = $config['system']['powerd_ac_mode'];
$battery_mode = "hadp";
if (!empty($config['system']['powerd_battery_mode'])) {
$battery_mode = $config['system']['powerd_battery_mode'];
$normal_mode = "hadp";
if (!empty($config['system']['powerd_normal_mode'])) {
$normal_mode = $config['system']['powerd_normal_mode'];
mwexec("/usr/sbin/powerd -b $battery_mode -a $ac_mode -n $normal_mode");
As you can see above, activate_powerd()
will set $normal_mode
to the value in $config['system']['powerd_normal_mode']
if $config['system']['powerd_enable']
is set to true.
It will then concatenate $normal_mode
(which came from the POST parameter powerd_normal_mode
) into a system shell command and execute it with mwexec()
:
/* wrapper for exec()
Executes in background or foreground.
For background execution, returns PID of background process to allow calling code control */
function mwexec($command, $nologentry = false, $clearsigmask = false, $background = false) {
global $g;
$retval = 0;
$outputarray = array();
exec("$command 2>&1", $outputarray, $retval);
return $retval;
Thus, command injection is possible in the powerd_normal_mode
parameter.
powerd_ac_mode
POST parameterSimilarly, firewall does not properly sanitize powerd_ac_mode
POST parameter:
<?php
if ($_POST) {
unset($input_errors);
$pconfig = $_POST;
if ($_POST['powerd_enable'] == "yes") {
$config['system']['powerd_enable'] = true;
else {
unset($config['system']['powerd_enable']);
$config['system']['powerd_ac_mode'] = $_POST['powerd_ac_mode'];
activate_powerd();
As you can see above, system_advanced_misc.php
will set $config['system']['powerd_enable']
to true if $_POST['powerd_enable']
is set to yes
. It will also set the $config['system']['powerd_ac_mode']
to the value of the POST parameter powerd_ac_mode
. It will then call activate_powerd()
. Activate_powerd()
will set $ac_mode
to the value in $config['system']['powerd_ac_mode']
if $config['system']['powerd_enable']
is set to true. It will then concatenate $ac_mode
(which came from the POST parameter powerd_ac_mode
) into a system shell command and execute it with mwexec()
. Thus, command injection is possible in the powerd_ac_mode
parameter.
powerd_battery_mode
POST parameterSame is true for powerd_battery_mode
POST parameter:
<?php
if ($_POST) {
unset($input_errors);
$pconfig = $_POST;
if ($_POST['powerd_enable'] == "yes") {
$config['system']['powerd_enable'] = true;
else {
unset($config['system']['powerd_enable']);
$config['system']['powerd_battery_mode'] = $_POST['powerd_battery_mode'];
activate\_powerd();
As you can see above, system_advanced_misc.php
will set $config['system']['powerd_enable']
to true if $_POST['powerd_enable']
is set to yes
. It will also set the $config['system']['powerd_battery_mode']
to the value of the POST parameter powerd_battery_mode
. It will then call activate_powerd()
. activate_powerd()
will set $battery_mode
to the value in $config['system']['powerd_battery_mode']
if $config['system']['powerd_enable']
is set to true. It will then concatenate $battery_mode
(which came from the POST parameter powerd_battery_mode
) into a system shell command and execute it with mwexec()
. Thus, command injection is possible in the powerd_battery_mode
parameter.
2018-10-23 - Vendor Disclosure
2018-12-03 - Public Release
Discovered by Brandon Stultz of Cisco Talos.