Talos Vulnerability Report


WAGO PFC200 iocheckd service "I/O-Check" BC_ProductLabel remote code execution vulnerability

December 16, 2019
CVE Number



An exploitable stack buffer overflow vulnerability exists in the iocheckd service "I/O-Check" functionality of WAGO PFC 200. A specially crafted set of packets can cause a stack buffer overflow, resulting in code execution. An attacker can send unauthenticated packets to trigger this vulnerability.

Tested Versions

WAGO PFC200 Firmware version 03.01.07(13) WAGO PFC200 Firmware version 03.00.39(12) WAGO PFC100 Firmware version 03.00.39(12)

Product URLs

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

CVSSv3 Score

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


CWE-805: Buffer Access with Incorrect Length Value


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 WAGO PFC200 Controller communicates via both standard and custom protocols.

The iocheckd service "I/O-Check" implements a custom configuration protocol used by WAGO controllers. The iocheckd service "I/O-Check" functionality of WAGO PFC 200 uses an incorrect buffer length when copying system data into a stack buffer when generating a response to the BC_ProductLabel message. When any value is present for the system value QS-STRING, the stack buffer will be overflowed resulting in a crash. Additionally, an attacker can send an unauthenticated packet using the iocheckd protocol to overwrite the QS-STRING value enabling attacker controlled data to overflow this stack buffer. Since the attacker can control the data that is being copied onto the stack, this vulnerability results in remote code execution.

[Annotated Disassembly / Decompilation output]

Here the buffer is allocated on the stack, size 0x20

.text:0001D600 sub_1D600
.text:0001D600 s               = -0x38
.text:0001D600                 PUSH            {R4-R7,LR}
.text:0001D604                 SUB             SP, SP, #0x44
.text:0001D608                 MOV             R7, R0
.text:0001D60C                 ADD             R0, SP, #0x20 ; stack buffer that will be overflowed
.text:0001D610                 MOV             R4, R1
.text:0001D614                 BL              sub_13570 ; overflow occurs in this function - snippet below

Here the system value of QS-STRING is copied to the stack buffer - up to 0x40 bytes overflowing the buffer by 0x20 bytes

.text:00013590                 STR             R0, [R4] ; stack buffer anotated above, size 0x20
.text:00013594                 MOV             R0, #0x8A4
.text:00013598                 STRB            R3, [R4,#4]
.text:0001359C                 MOVT            R0, #2  ; r0 = 0x208a4 pointer to data containing 'QS-STRING'
.text:000135A0                 BL              sub_14B38 ; calls typelabel_SYSTEM_Get
.text:000135A4                 SUBS            R5, R0, #0
.text:000135A8                 BNE             loc_135CC
.text:000135AC                 LDR             R6, [SP,#4]
.text:000135B0                 MOV             R2, #0x40 ; strncpy length is 0x40 when the buffer is 0x20 on the stack
.text:000135B4                 MOV             R0, R4  ; dest
.text:000135B8                 MOV             R1, R6  ; src
.text:000135BC                 BL              strncpy

When the function epilogue is entered, the values for pc and r4-r7 are overwritten with the values from the attacker-controlled QS-STRING value

.text:0001D65C loc_1D65C                               ; CODE XREF: sub_1D600+BC↓j
.text:0001D65C                 STRB            R6, [R4,#4]
.text:0001D660                 ADD             R0, SP, #0x20 
.text:0001D664                 BL              strlen
.text:0001D668                 ADD             R3, SP, #0x20
.text:0001D66C                 MOV             R2, SP
.text:0001D670                 MOV             R1, #0x220E8
.text:0001D678                 STRB            R0, [R4,#5]
.text:0001D67C                 ADD             R0, R4, #6 
.text:0001D680                 BL              sprintf
.text:0001D684                 MOV             R3, #0
.text:0001D688                 MOV             R0, R5
.text:0001D68C                 STRB            R3, [R4,#2]
.text:0001D690                 STRB            R3, [R4,#3]
.text:0001D694                 ADD             SP, SP, #0x44 
.text:0001D698                 POP             {R4-R7,PC}

Crash Information

Program received signal SIGSEGV, Segmentation fault.
0x44444444 in ?? ()
(gdb) i r
r0             0xf      15
r1             0x8      8
r2             0xffffffff       4294967295
r3             0x0      0
r4             0x41414141       1094795585
r5             0x41414141       1094795585
r6             0x41414141       1094795585
r7             0x41414141       1094795585
r8             0x91c08  597000
r9             0xb6f7d4e0       3069695200
r10            0x0      0
r11            0x30005  196613
r12            0x220f0  139504
sp             0xbef83cb8       0xbef83cb8
lr             0x1d684  120452
pc             0x44444444       0x44444444
cpsr           0x10     16
fpscr          0x0      0
(gdb) bt
#0  0x44444444 in ?? ()
#1  0x0001d684 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)


This vulnerability could be mitigated by disabling the iocheckd service "I/O-Check" via the Web-based management web application.


2019-07-30 - Vendor disclosure
2019-09-06 - 30+ day follow up
2019-10-02 - 60+ day follow up; vendor acknowledged
2019-10-31 - Vendor passed to CERT@VDE for coordination; Talos extended public disclosure deadline
2019-12-16 - Public Release


Discovered by Kelly Leuschner of Cisco Talos