Talos Vulnerability Report

TALOS-2019-0948

WAGO PFC200 Cloud Connectivity Multiple Command Injection Vulnerabilities

March 9, 2020
CVE Number

CVE-2019-5155

Summary

An exploitable command injection vulnerability exists in the cloud connectivity feature of WAGO PFC200. An attacker can inject operating system commands into any of the parameter values contained in the firmware update command.

Tested Versions

WAGO PFC200 Firmware version 03.02.02(14) WAGO PFC200 Firmware version 03.01.07(13) WAGO PFC200 Firmware version 03.00.39(12)

Product URLs

https://www.wago.com/us/pfc200

CVSSv3 Score

7.2 - CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)

Details

The WAGO PFC200 Controller is one of WAGO’s programmable automation controllers that boasts 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 Cloud Connectivity service of the WAGO PFC200 Controller allows for bi-directional communication with a variety of cloud providers including the Wago Cloud application, Microsoft Azure, IBM Cloud, AWS and SAP IoT Services. The Cloud Connectivity service enables the device to send telemetry data to the cloud and act on commands received from the cloud provider.

The Cloud Connectivity service supports Remote Firmware update through the Wago Cloud Azure IoT Hub application. When initiating a Firmware Update, the cloud sends a Firmware Update command which contains parameters that are used to configure URL’s and timeout values for the firmware update process. Each of the parameter values within the firmware update command is vulnerable to os command injection. The injected commands will run as the iot user. Web administrator privileges are required to configure the Cloud Connectivity service.

The code below shows each parameter value being extracted from the Firmware Update command stored in R10. The function sub_29900 is responsible for extracting the parameter data out of the json command.

.text:0002FD64                 LDR             R1, =(unk_CCE6C - 0x2FD74)
.text:0002FD68                 MOV             R0, R10
.text:0002FD6C                 ADD             R1, PC, R1 ; points to string `FirmwareStorageAccount`
.text:0002FD70                 BL              sub_29900
.text:0002FD74                 ADD             R5, SP, #0xC68+var_3F8
.text:0002FD78                 LDR             R3, [SP,#0xC68+var_C54]
.text:0002FD7C                 ADD             R5, R5, #8
.text:0002FD80                 LDR             R1, =(unk_CCE6C - 0x2FD90)
.text:0002FD84                 MOV             R6, R0
.text:0002FD88                 ADD             R1, PC, R1
.text:0002FD8C                 MOV             R0, R5
.text:0002FD90                 LDR             R7, [R3]
.text:0002FD94                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_ 
.text:0002FD98                 ADD             R4, SP, #0xC68+var_BF0
.text:0002FD9C                 MOV             R2, R5
.text:0002FDA0                 MOV             R1, R7
.text:0002FDA4                 MOV             R0, R4
.text:0002FDA8                 BL              sub_4ED64
.text:0002FDAC                 LDR             R1, [SP,#0xC68+var_BF0]
.text:0002FDB0                 MOV             R0, R6
.text:0002FDB4                 ADD             R1, R1, #0x20 ; ' '
.text:0002FDB8                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_
.text:0002FDBC                 ADD             R0, R4, #4
.text:0002FDC0                 BL              sub_284C4
.text:0002FDC4                 MOV             R0, R5
.text:0002FDC8                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv
.text:0002FDCC                 LDR             R1, =(unk_CCE84 - 0x2FDDC)
.text:0002FDD0                 MOV             R0, R10
.text:0002FDD4                 ADD             R1, PC, R1 ; points to string `FirmwareStoragePath`
.text:0002FDD8                 BL              sub_29900
.text:0002FDDC                 LDR             R3, [SP,#0xC68+var_C54]
.text:0002FDE0                 ADD             R5, SP, #0xC68+var_408
.text:0002FDE4                 LDR             R1, =(unk_CCE84 - 0x2FDF8)
.text:0002FDE8                 MOV             R6, R0
.text:0002FDEC                 MOV             R0, R5
.text:0002FDF0                 ADD             R1, PC, R1 
.text:0002FDF4                 LDR             R7, [R3]
.text:0002FDF8                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_ 
.text:0002FDFC                 MOV             R2, R5
.text:0002FE00                 MOV             R1, R7
.text:0002FE04                 SUB             R0, R4, #8
.text:0002FE08                 BL              sub_4ED64
.text:0002FE0C                 LDR             R1, [SP,#0xC68+var_BF8]
.text:0002FE10                 MOV             R0, R6
.text:0002FE14                 ADD             R1, R1, #0x20 ; ' '
.text:0002FE18                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_ 
.text:0002FE1C                 SUB             R0, R4, #4
.text:0002FE20                 BL              sub_284C4
.text:0002FE24                 MOV             R0, R5
.text:0002FE28                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:0002FE2C                 LDR             R1, =(unk_CCE9C - 0x2FE3C)
.text:0002FE30                 MOV             R0, R10
.text:0002FE34                 ADD             R1, PC, R1 ; points to string `FirmwareControlFile`
.text:0002FE38                 BL              sub_29900
.text:0002FE3C                 ADD             R5, SP, #0xC68+var_428
.text:0002FE40                 LDR             R3, [SP,#0xC68+var_C54]
.text:0002FE44                 ADD             R5, R5, #8
.text:0002FE48                 LDR             R1, =(unk_CCE9C - 0x2FE58)
.text:0002FE4C                 MOV             R6, R0
.text:0002FE50                 ADD             R1, PC, R1
.text:0002FE54                 MOV             R0, R5
.text:0002FE58                 LDR             R7, [R3]
.text:0002FE5C                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_ 
.text:0002FE60                 ADD             R4, SP, #0xC68+var_C00
.text:0002FE64                 MOV             R2, R5
.text:0002FE68                 MOV             R1, R7
.text:0002FE6C                 MOV             R0, R4
.text:0002FE70                 BL              sub_4ED64
.text:0002FE74                 LDR             R1, [SP,#0xC68+var_C00]
.text:0002FE78                 MOV             R0, R6
.text:0002FE7C                 ADD             R1, R1, #0x20 ; ' '
.text:0002FE80                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_ 
.text:0002FE84                 ADD             R0, R4, #4
.text:0002FE88                 BL              sub_284C4
.text:0002FE8C                 MOV             R0, R5
.text:0002FE90                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:0002FE94                 LDR             R1, =(unk_CCEB4 - 0x2FEA4)
.text:0002FE98                 MOV             R0, R10
.text:0002FE9C                 ADD             R1, PC, R1 ; points to string `FirmwareStorageSAS`
.text:0002FEA0                 BL              sub_29900
.text:0002FEA4                 LDR             R3, [SP,#0xC68+var_C54]
.text:0002FEA8                 ADD             R5, SP, #0xC68+var_438
.text:0002FEAC                 LDR             R1, =(unk_CCEB4 - 0x2FEC0)
.text:0002FEB0                 MOV             R6, R0
.text:0002FEB4                 MOV             R0, R5
.text:0002FEB8                 ADD             R1, PC, R1
.text:0002FEBC                 LDR             R7, [R3]
.text:0002FEC0                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_ 
.text:0002FEC4                 MOV             R2, R5
.text:0002FEC8                 MOV             R1, R7
.text:0002FECC                 SUB             R0, R4, #8
.text:0002FED0                 BL              sub_4ED64
.text:0002FED4                 LDR             R1, [SP,#0xC68+var_C08]
.text:0002FED8                 MOV             R0, R6
.text:0002FEDC                 ADD             R1, R1, #0x20 ; ' '
.text:0002FEE0                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_ 
.text:0002FEE4                 SUB             R0, R4, #4
.text:0002FEE8                 BL              sub_284C4
.text:0002FEEC                 MOV             R0, R5
.text:0002FEF0                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:0002FEF4                 LDR             R1, =(unk_CCECC - 0x2FF04)
.text:0002FEF8                 MOV             R0, R10
.text:0002FEFC                 ADD             R1, PC, R1 ; points to string `TimeoutPrepared`
.text:0002FF00                 BL              sub_29900
.text:0002FF04                 ADD             R5, SP, #0xC68+var_458
.text:0002FF08                 LDR             R3, [SP,#0xC68+var_C54]
.text:0002FF0C                 ADD             R5, R5, #8
.text:0002FF10                 LDR             R1, =(unk_CCECC - 0x2FF20)
.text:0002FF14                 MOV             R6, R0
.text:0002FF18                 ADD             R1, PC, R1
.text:0002FF1C                 MOV             R0, R5
.text:0002FF20                 LDR             R7, [R3]
.text:0002FF24                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_ 
.text:0002FF28                 ADD             R4, SP, #0xC68+var_C10
.text:0002FF2C                 MOV             R2, R5
.text:0002FF30                 MOV             R1, R7
.text:0002FF34                 MOV             R0, R4
.text:0002FF38                 BL              sub_4ED64
.text:0002FF3C                 LDR             R1, [SP,#0xC68+var_C10]
.text:0002FF40                 MOV             R0, R6
.text:0002FF44                 ADD             R1, R1, #0x20 ; ' '
.text:0002FF48                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_assignERKS4_ 
.text:0002FF4C                 ADD             R0, R4, #4
.text:0002FF50                 BL              sub_284C4
.text:0002FF54                 MOV             R0, R5
.text:0002FF58                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:0002FF5C                 LDR             R1, =(unk_CCEE4 - 0x2FF6C)
.text:0002FF60                 MOV             R0, R10
.text:0002FF64                 ADD             R1, PC, R1 ; points to string `TimeoutUnconfirmed`
.text:0002FF68                 BL              sub_29900

The following code is looping through each of the parameter values that were previously extracted and building a string in the form -i "<keyname>=<user-supplied-value>". The result is stored in a basic_string var_C50 [1]

.text:0002FFBC                 ADD             R3, SP, #0xC68+var_358
.text:0002FFC0                 STR             R3, [SP,#0xC68+var_360]
.text:0002FFC4                 MOV             R3, #0
.text:0002FFC8                 STR             R3, [SP,#0xC68+var_35C]
.text:0002FFCC                 STRB            R3, [SP,#0xC68+var_358]
.text:0002FFD0                 LDR             R3, =(aI - 0x2FFE0) ; " -i \""
.text:0002FFD4                 LDR             R6, [SP,#0xC68+var_1D4]
.text:0002FFD8                 ADD             R3, PC, R3 ; " -i \""
.text:0002FFDC                 STR             R3, [SP,#0xC68+var_C48]
.text:0002FFE0                 LDR             R3, =(aId+4 - 0x2FFEC) ; "="
.text:0002FFE4                 ADD             R3, PC, R3 ; "="
.text:0002FFE8                 STR             R3, [SP,#0xC68+var_C44]
.text:0002FFEC                 LDR             R3, =(aI+4 - 0x2FFF8) ; "\""
.text:0002FFF0                 ADD             R3, PC, R3 ; "\""
.text:0002FFF4                 STR             R3, [SP,#0xC68+var_C40]
.text:0002FFF8
.text:0002FFF8 loc_2FFF8
.text:0002FFF8                 ADD             R3, SP, #0xC68+var_1E8
.text:0002FFFC                 ADD             R4, SP, #0xC68+var_188
.text:00030000                 ADD             R3, R3, #0xC
.text:00030004                 ADD             R4, R4, #8
.text:00030008                 CMP             R6, R3
.text:0003000C                 ADD             R3, SP, #0xC68+var_368
.text:00030010                 ADD             R3, R3, #8
.text:00030014                 STR             R3, [SP,#0xC68+var_C50]
.text:00030018                 BEQ             loc_300F8
.text:0003001C                 ADD             R5, SP, #0xC68+var_338
.text:00030020                 MOV             R1, R3
.text:00030024                 ADD             R5, R5, #8
.text:00030028                 MOV             R0, R5
.text:0003002C                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_ 
.text:00030030                 LDR             R1, [SP,#0xC68+var_C48]
.text:00030034                 MOV             R0, R5
.text:00030038                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc 
.text:0003003C                 B               loc_30044
.text:00030040 ; ---------------------------------------------------------------------------
.text:00030040                 B               loc_30284
.text:00030044 ; ---------------------------------------------------------------------------
.text:00030044
.text:00030044 loc_30044
.text:00030044                 ADD             R1, R6, #0x10
.text:00030048                 MOV             R0, R5
.text:0003004C                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendERKS4_ 
.text:00030050                 MOV             R1, R0
.text:00030054                 MOV             R0, R4
.text:00030058                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_ 
.text:0003005C                 LDR             R1, [SP,#0xC68+var_C44]
.text:00030060                 MOV             R0, R4
.text:00030064                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc 
.text:00030068                 ADD             R7, SP, #0xC68+var_198
.text:0003006C                 MOV             R1, R0
.text:00030070                 MOV             R0, R7
.text:00030074                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_ 
.text:00030078                 ADD             R1, R6, #0x28 ; '('
.text:0003007C                 MOV             R0, R7
.text:00030080                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendERKS4_ 
.text:00030084                 ADD             R8, SP, #0xC68+var_1B8
.text:00030088                 MOV             R1, R0
.text:0003008C                 ADD             R8, R8, #8
.text:00030090                 MOV             R0, R8
.text:00030094                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_ 
.text:00030098                 LDR             R1, [SP,#0xC68+var_C40]
.text:0003009C                 MOV             R0, R8
.text:000300A0                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc 
.text:000300A4                 ADD             R9, SP, #0xC68+var_1C8
.text:000300A8                 MOV             R1, R0
.text:000300AC                 MOV             R0, R9
.text:000300B0                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_ 
.text:000300B4                 MOV             R1, R9
.text:000300B8                 LDR             R0, [SP,#0xC68+var_C50] ; [1]
.text:000300BC                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEOS4_ 
.text:000300C0                 MOV             R0, R9
.text:000300C4                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:000300C8                 MOV             R0, R8
.text:000300CC                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:000300D0                 MOV             R0, R7
.text:000300D4                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:000300D8                 MOV             R0, R4
.text:000300DC                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:000300E0                 MOV             R0, R5
.text:000300E4                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv
.text:000300E8                 MOV             R0, R6
.text:000300EC                 BL              _ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base ; std::_Rb_tree_increment(std::_Rb_tree_node_base *)
.text:000300F0                 MOV             R6, R0
.text:000300F4                 B               loc_2FFF8

Finally, the full command is built up resulting in the following command being executed by system() [2] sudo fwupdate activate --keep-application -i "Command=506" -i "FirmwareControlFile=<user-supplied-value>" -i "FirmwareStorageAccount=<user-supplied-value>" -i "FirmwareStoragePath=<user-supplied-value>" -i "FirmwareStorageSAS=<user-supplied-value>" -i "SchemaVersion=1" -i "TimeoutPrepared=<user-supplied-value>" -i "TimeoutUnconfirmed=<user-supplied-value>" Using var_C50 that was built above [1]. Each of the <user-supplied-value> parameters is vulnerable to OS command injection via this command being run by system()

.text:00030128                 ADD             R1, PC, R1 ; "sudo "
.text:0003012C                 BL              sub_28044
.text:00030130                 LDR             R1, =(aActivateKeepAp - 0x30140) ; " activate --keep-application "
.text:00030134                 MOV             R0, R6
.text:00030138                 ADD             R1, PC, R1 ; " activate --keep-application "
.text:0003013C                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKc 
.text:00030140                 MOV             R1, R0
.text:00030144                 MOV             R0, R4
.text:00030148                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_
.text:0003014C                 LDR             R1, [SP,#0xC68+var_C50] [1]
.text:00030150                 MOV             R0, R4
.text:00030154                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendERKS4_ 
.text:00030158                 ADD             R5, SP, #0xC68+var_348
.text:0003015C                 MOV             R1, R0
.text:00030160                 MOV             R0, R5
.text:00030164                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_ 
.text:00030168                 MOV             R0, R4
.text:0003016C                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:00030170                 MOV             R0, R6
.text:00030174                 ADD             R6, SP, #0xC68+var_308
.text:00030178                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:0003017C                 ADD             R6, R6, #8
.text:00030180                 LDR             R1, =(aAgentcontrolFw - 0x30194) ; "AgentControl/FwUpdateConfigTool.cpp"
.text:00030184                 MOV             R2, R4
.text:00030188                 MOV             R3, #0x4A ; 'J'
.text:0003018C                 ADD             R1, PC, R1 ; "AgentControl/FwUpdateConfigTool.cpp"
.text:00030190                 MOV             R0, R6
.text:00030194                 STR             R3, [SP,#0xC68+var_180]
.text:00030198                 BL              sub_615EC
.text:0003019C                 LDR             R3, =(aExec - 0x301B4) ; "Exec: "
.text:000301A0                 MOV             R2, #0x20 ; ' '
.text:000301A4                 STR             R5, [SP,#0xC68+var_C68]
.text:000301A8                 MOV             R1, R6
.text:000301AC                 ADD             R3, PC, R3 ; "Exec: "
.text:000301B0                 MOV             R0, #0x40 ; '@'
.text:000301B4                 BL              sub_3C678
.text:000301B8                 MOV             R0, R6
.text:000301BC                 BL              _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv 
.text:000301C0                 LDR             R0, [SP,#0xC68+var_348] ; command
.text:000301C4                 BL              system [2]

Mitigation

This vulnerability could be mitigated by disabling the Cloud Connectivity feature via the Web-based management web application.

Timeline

2019-10-31 - Vendor Disclosure
2019-10-31 - Vendor acknowledged and passed to CERT@VDE for coordination/handling
2020-01-28 - Talos discussion with vendor; disclosure deadline extended
2020-03-09 - Public Release

Credit

Discovered by Kelly Leuschner of Cisco Talos.