CVE-2019-5134
An exploitable regular expression without anchors vulnerability exists in the Web-Based Management (WBM) authentication functionality of WAGO PFC100/200 controllers. A specially crafted authentication request can bypass regular expression filters, resulting in sensitive information disclosure.
WAGO PFC200 Firmware version 03.00.39(12) WAGO PFC200 Firmware version 03.01.07(13) WAGO PFC100 Firmware version 03.00.39(12)
Based on inspection of various firmware versions, this vulnerability appears to impact all versions from the current and going back to at least 10 and likely earlier.
https://www.wago.com/us/pfc200 https://www.wago.com/us/pfc100
5.3 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
CWE-777: Regular Expression without Anchors
The WAGO PFC100 and PFC200 devices are programmable automation controllers that boast high cybersecurity standards by including VPN, SSL and firewall software. WAGO controllers are used in many industries including automotive, rail, power engineering, manufacturing, and building management.
The application takes user input and, using regular expressions, attempts to locate and retrieve the relevant line in the /etc/lighttpd/lighttpd-htpasswd.user file (or /etc/shadow
if configured to use system authentication) for use in password validation.
The PasswordCorrect()
function from login.php
:
function PasswordCorrect($passwordFilename, $username = '', $password = '')
{
$pwCorrect = false;
//var_dump($username); var_dump($password);
// get password file and iterate over every line
$pwFileArray = file($passwordFilename);
foreach($pwFileArray as $lineNo => $pwFileLine)
{
//var_dump($pwFileLine);
// if username was found, filter password key
if(preg_match("/^".$username.":/", $pwFileLine))
{
$pwFileKey = str_replace($username.":", "", $pwFileLine);
$pwFileKey = str_replace("\n", "", $pwFileKey);
if (preg_match('/\$(?P<algo>\d)\$(?P<salt>[a-zA-Z0-9\.\/]{2,16})\$(?<hash>.*)/', $pwFileKey, $userInfo))
{
$algo = $userInfo["algo"];
$salt = $userInfo["salt"];
//$hash = $userInfo["hash"];
// evaluate key of password given by user and compare both
$userKey = crypt($password, "$".$algo."$".$salt);
//var_dump($pwFileKey); printf("\n"); var_dump($userKey); printf("\n");
if($pwFileKey == $userKey)
{
$pwCorrect = true;
}
}
}
}
return $pwCorrect;
}
A regex in an if statement checks for presence of the user input username:
preg_match("/^".$username.":/", $pwFileLine)
^
) looking for username ending with a colon
str_replace()
to:
$pwFileKey
set to something like: $6$nJ68diwYtzvoGdmO$riWD40K1ygPswo/bW0EhwGCNwpWw1mVaHKGXoiLU4vydECe2pXqpZAVkl0JM9GoibmyCGOTCp5Fk8hL8jGoFA0
preg_match('/\$(?P<algo>\d)\$(?P<salt>[a-zA-Z0-9\.\/]{2,16})\$(?<hash>.*)/', $pwFileKey, $userInfo)
$pwFilekey
var set above, save result in $userInfo
and use named subpattern (named capture groups) to set vars $algo
and $salt
$
$
dd if=/dev/urandom bs=1 count=12 2> /dev/null | base64 | tr + . | tr -d "\n"
$
//$hash = $userInfo["hash"]
) and therefore irrelevantIf both user input passes both regexes the results are sent to the php crypt()
function.
The string (?x)admin....
will match on admin:$6$
, allowing an attacker to test on each subsequent character by appending the tested character followed by a #
and then use the PHP crypt()
timing attack described in TALOS-2019-0924 to determine if the character is a match, thereby disclosing the full salt and password hash.
2019-10-28 - Vendor Disclosure
2019-10-31 - Vendor passed to CERT@VDE for coordination/handling
2019-12-16 - Disclosure deadline extended
2020-01-28 - Talos discussion about vulnerabilities with Vendor
2020-03-09 - Public Release
Discovered by Patrick DeSantis and Lilith [-_-]; of Cisco Talos.