Security Advisory: Unauthenticated Configuration Export in Multiple WAGO Products

date: Jan 16, 2023
author: ONEKEY and CERTAINITY joint research team
 

As shown in our previous security advisory for the Asus M25 NAS from our research cooperation with ONEKEY, we recently introduced a “zero-day identification” module that performs static code analysis on proprietary applications found within firmware uploaded to ONEKEY’s platform. 

This module reported two potential issues within a WAGO Series PFC100  configuration API: a path traversal and a command injection vulnerability. The command injection turned out to be a false positive (we strengthened our analysis capabilities since then) but it got us to investigate a specific PHP file where we identified that the authentication and authorization code blocks were commented. 

We verified that it could lead to an unauthenticated configuration export using an emulated device and reported both this issue and the path traversal to WAGO. 

Unauthenticated Configuration Export

Affected vendor & product

Series WAGO PFC100 (750-81xx/xxx-xxx)

Series WAGO PFC200 (750-82xx/xxx-xxx)

WAGO Compact Controller CC100 (751-9301)

WAGO Edge Controller (752-8303/8000-002)

Series WAGO Touch Panel 600 Standard Line (762-4xxx)

Series WAGO Touch Panel 600 Advanced Line (762-5xxx)

Series WAGO Touch Panel 600 Marine Line (762-6xxx)

Vendor Advisory

https://cert.vde.com/de/advisories/VDE-2022-054/

Vulnerable version

Firmware versions >= 16 and <= 22.

Fixed version

We recommend all affected users to install FW22 Patch 1 or higher.

CVE IDs

CVE-2022-3738

Impact (CVSS)

4.3 (medium) (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N)

Credit

Q. Kaiser, ONEKEY Research Lab
Research supported by Certainity


Summary

The configuration API of the web-based management interface (WBM) of WAGOs programmable logic controller (PLC) does not require authentication and offers the download of files in a specific folder. This folder typically contains backups created since the last reboot, which might hold sensitive data.

Impact

A successful exploit could allow the attacker to download a copy of the running firmware or the VPN configuration. Both these files would hold sensitive information such as user credentials or cryptographic material. 

Note that to be able to download the files, they must have been generated by a legitimate user since the last reboot.

Description

The WAGO web admin interface is written in PHP and has a page allowing for VPN configuration or firmware export found at /var/www/wbm/php/file_transfer/offer_download.php. Within this file, lines 30 to 46 are commented using a multi-line comment. This effectively disables the authentication and authorization checks that were supposed to be performed on those lines.

<?php include_once"wbm_lib.inc.php"; include_once __DIR__.'/wbm_lib.inc.php'; include_once __DIR__.'/file_transfer.inc.php'; include_once __DIR__.'/../authentication/session_lifetime.inc.php'; use transfer\FileTransfer; // define constants /* define("DOWNLOAD_DIR", "/tmp"); define("UPLOAD_DIR", "/tmp"); */ define("DOWNLOAD_FILENAME_FRAGMENT", "firmware_backup"); // Offer backup download file. Function takes the first file in download directory (there should be only one), // transfers it to browser and deletes the file afterwards. function OfferDownload() { $status = SUCCESS; $errorText = ""; $transfer; // optional, of type FileTransfer /* // check for correct session and reset session timeout $status = Session_HandleSessionLifeTime($_GET["csrf_id"],false); if(SUCCESS != $status) { $errorText = Session_GetErrorTxt($status); } else if(!isset($_SESSION["username"]) || USER_ADMIN != $_SESSION["username"]) { $status = ACCESS_NOT_ALLOWED; $errorText = "Access not allowed."; } // check if folder is given else */ { if(!isset($_GET["download_dir"]))

Authenticated Path Traversal (Bonus)

WAGO does not consider the authenticated path traversal to be a vulnerability since it can only be triggered by a user with administrative privileges. A user with these privileges can simply create a backup of the running firmware and download it, making the path traversal and possibility to download arbitrary files useless. We fully agree with that assessment, but still wanted to show how it was found.

The path traversal was reported as affecting download.php. As we can see in the screenshot below, the $downloadPath value is used by a fopen call.

Graphical user interface, text, application

Description automatically generated

This $downloadPath is directly obtained from the GET parameter “download”:

$downloadPath = ''; if (isset($_GET['download'])) {     $downloadPath = $_GET['download'];     // check file exists     if(!file_exists($downloadPath))     {         die_with_response(200, [             'error' => new WBMError(ERROR_GROUP_FILE_TRANSFER, ERROR_CODE_DOWNLOAD_FILE_DOES_NOT_EXIST, 'File does not exist')         ]); }     // check access rights     if(!is_readable($downloadPath))     {        die_with_response(200, [            'error' => new WBMError(ERROR_GROUP_FILE_TRANSFER, ERROR_CODE_DOWNLOAD_FILE_NOT_READABLE, 'File is not readable')        ]);     } }

The file content is then returned to the user:

$file = fopen($downloadPath, 'r'); if(!$file) {     die_with_response(200, [         'error' => new WBMError(ERROR_GROUP_FILE_TRANSFER, ERROR_CODE_DOWNLOAD_FILE_NOT_READABLE, 'File is not readable')     ]); } // put fitting filetype to header header("Content-Type: application/octet-stream"); // send header with proposal of fitting filename header(sprintf("Content-Disposition: attachment; filename=\"%s\"", basename($downloadPath))); // send file size header('Content-Length: '.filesize($downloadPath)); // before sending the file content, add a cookie to tell the frontend that the download will be started setcookie("download($downloadPath)", 'started', 0, '/'); flush(); // read and send file chunkwise while (!feof($file)) {     print fread($file, 1024*1024); // read 1MiB...     flush(); // ... and send to browser } fclose($file);

Key Takeaways

Having the possibility to automatically identify unknown high-risk and critical vulnerabilities is a powerful capability have – a super-power both for operators and manufacturers of IACS. Operators get a chance to efficiently validate vendor claims on a low-effort basis and security manufacturers can fix such vulnerabilities before even shipping devices to their clients. While it is important to be as confident as possible about potential vulnerabilities, sometimes something that just looks like a vulnerability turns out to reveal a vulnerable area of the application.

Timeline

2022-10-17 – Sent coordinated disclosure request to psirt@wago.com 

2022-10-17 – Answer from WAGO PSIRT (Product Security Incident Response Team), establishment of secure communication channel. 

2022-10-21 – First feedback from WAGO PSIRT on reproduction. 

2022-10-21 – Second feedback from WAGO PSIRT on authenticated path traversal. 

2022-11-10 – WAGO PSIRT provides us with CVE (Common Vulnerabilities and Exposures) ID and CVSS (Common Vulnerability Scoring System) score, start coordination with CERT@VDE 

2022-12-08 – WAGO PSIRT shares draft advisory with us and CERT@VDE 

2023-01-12– CERT@VDE releases WAGO advisory

2023-01-16 – ONEKEY & CERTAINITY releases its advisory