CVE-2019-5081
An exploitable heap 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 heap buffer overflow, potentially resulting in code execution. An attacker can send unauthenticated packets to trigger this vulnerability.
WAGO PFC200 Firmware version 03.01.07(13) WAGO PFC200 Firmware version 03.00.39(12) WAGO PFC100 Firmware version 03.00.39(12)
https://www.wago.com/us/pfc200 https://www.wago.com/us/pfc100
10.0 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H
CWE-120 - Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)
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 service protocol (port 6626) provided by the iocheckd service supports reading and writing key,value pairs to the EEPROM of the device. The ReadPCBManuNum message processing code calls strcpy with a fixed sized heap destination buffer, where the source data is the EEPROM value for WAGONRSTR. An attacker can send an unauthenticated packet to overwrite the WAGONRSTR value in EEPROM enabling attacker controlled data to overflow this heap buffer potentially resulting in arbitrary code execution.
[Annotated Disassembly / Decompilation output]
Here, the buffer is allocated on the heap, size 0x28:
.text:0001F520 MOV R1, #0x28
.text:0001F524 LDR R0, [R4]
.text:0001F528 MOV R5, R1
.text:0001F52C BL realloc
.text:0001F530 STR R0, [R4]
Here, R5 contains the EEPROM value for WAGONRSTR, R4 contains our heap buffer allocated above.
.text:0001FCA4 LDR R5, [SP] ; value for WAGONRSTR read from EEPROM
.text:0001FCA8 LDR R0, [R4] ; this is our heap buffer size 0x28
.text:0001FCAC MOV R1, R5
.text:0001FCB0 ADD R0, R0, #8
.text:0001FCB4 BL strcpy ; overflow heap buffer if length of WAGONRSTR value is > 0x28
These are the register values before the overflow. The heap pointer is actually -8 from r0: 0x424c8
r0 0x424d0 0x424d0 ; this is the destination buffer that will be overflowed
r1 0x42d00 0x42d00
r2 0x80000000 0x80000000
r3 0xc 0xc
r4 0xbefffbc4 0xbefffbc4
r5 0x42d00 0x42d00
r6 0x1fbf0 0x1fbf0
r7 0x0 0x0
r8 0x91c08 0x91c08
r9 0xb6ff44e0 0xb6ff44e0
r10 0x0 0x0
r11 0x30005 0x30005
r12 0x42d28 0x42d28
sp 0xbefffba8 0xbefffba8
lr 0xb6f83b30 0xb6f83b30
pc 0x1fcb4 0x1fcb4
cpsr 0x60010010 0x60010010
fpscr 0x0 0x0
Heap chunk adjacent to destination buffer before overflow:
0x424f0: 0x110005 0x39 0x7 0x630101 ; chunk: prev_size, size, data
Heap chunk adjacent to destination buffer after overflow:
0x424f0: 0x42424242 0x58585858 0x0 0x630101 ; chunk: prev_size, size, data
Backtrace isn’t helpful here so here are the registers in malloc_printerr just before abort(). The crash is when the destination buffer is freed.
$r0 : 0x2
$r1 : 0xb6be65fc → "*** Error in `%s': %s: 0x%s ***"
$r2 : 0xbefffea3 → "iocheckd"
$r3 : 0xb6be6738 → "free(): invalid next size (fast)"
$r4 : 0x2
$r5 : 0xbefffb74 → "000424c8"
$r6 : 0xb6be6738 → "free(): invalid next size (fast)"
$r7 : 0x000424f0 → "BBBBXXXX"
$r8 : 0x91c08
$r9 : 0x0
$r10 : 0x0
$r11 : 0x30005
$r12 : 0x0
$sp : 0xbefffb68 → 0xbefffb74 → "000424c8"
$lr : 0xb6b38a90 → add sp, sp, #24
$pc : 0xb6b32d30 → push {r1, r2, r3}
Backtrace
Program received signal SIGABRT, Aborted.
#0 0xb6af67a0 in raise () from target:/lib/libc.so.6
#1 0xb6af7b08 in abort () from target:/lib/libc.so.6
#2 0xb6b32fbc in ?? () from target:/lib/libc.so.6
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