I was talking a while ago to Justin Engler, a friend who also happens to be a really talented web app and mobile app security researcher, about the popping-up of ICS management software for mobile devices. He theorized that mobile apps for ICS would be an interesting place to watch for bugs nearly three years ago. Dale’s recent ICSJWG Q&A over mobile device security gave me a little motivation to dig into some sample apps and see how the field actually looks. The results highlight some of the issues that your organization will run into if and when you decide to adopt mobile.
The focus of this post is not just application security. While there are a few specific vulnerable applications mentioned, I think that the big lessons should be ones of architecture and integration challenges. The current lot of ICS management apps pay little mind to securing access or preventing bad operation. Even an app with ‘secure’ on its product homepage may leave you wide open.
I decided to pick on Android simply because my only jailbroken iOS device at the moment is so terribly destroyed from years of abuse that installing new apps is a nonstarter. There also seems to be more interesting control systems apps for Android at the moment.
A quick survey of Google’s Play store for terms such as ‘SCADA’’, ‘PLC’, and ‘OPC’ turns up a few applications worth checking out. Unfortunately there are no apps that I could find which do what Dale prescribes: obtain safe, accurate, remote, ‘read-only’ access to control system data. Doing so will require a lot of backend work on your part.
Let’s take a look at two interesting vulnerable applications.
The first is called Watch*IT OPC. The architecture of this app requires installing the company’s OPC translator service onto your control network. The translator service, also called Watch*IT OPC is actually an OPC client. The translator presents a service that the Android application may then connect to. In this sense, Watch*IT OPC is actually a win. Assuming (and this is a big assumption, as I haven’t checked) that the translator service is well-written, it may provide read-only access to your process data. Their implementation example is pretty light on details, though: you probably want to deploy it in a way that pushes data outside of your control system perimeter. Their example implementation doesn’t mention this kind of detail. The vendor instead seems to expect that your mobile device will have VPN or other access right into your control system LAN.
The Android app itself has a few unfortunate problems. First and foremost, it is distributed on the Google Play store with debugging enabled. This is a problem with some Android apps, and one that can have dire consequences. When debugging is enabled, any application on your Android device may attach to this application and read or write the memory of the application. MWR labs has a nice writeup on the problem and how specifically to exploit it.
Fortunately, new apps that are uploaded to Google’s Play store are checked for debuggability. If the debuggable flag is set, the app is rejected from the Google marketplace. This should have happened years ago, and should probably be retroactively applied to all applications, but there are plenty of older applications in the store that still have the problem. Not all Android marketplaces will check for debuggable applications, of course, so if you are using a non-Google store even new applications may end up with this vulnerability.
The outcomes of this bug could be pretty bad. If the Watch*IT OPC transaltor service does allow control, an attacker could quickly use the Android application against you using the debugging interface. Even if the translator is written well, an attacker could at least prevent you from seeing alarms, or from knowing the actual status of your control system.
A second app is one specifically designed for interfacing with Siemens S7 controllers called S7Droid. The app is not written by Siemens, and uses the open-source libnodave project for communication with S7 PLCs. Interestingly the S7Droid app decided to use the C version of libnodave using Java Native Interface (JNI) calls to libnodave’s packet generation and parsing functions.
libnodave is a slightly buggy communication library, as the homepage very clearly warns you. There are several buffer overflow bugs in the code which may be triggered by a malicious person.
One such overflow is in the daveReadBytes() function:
int DECL2 daveReadBytes(daveConnection * dc,int area, int DBnum, int start,int len, void * buffer){
PDU p1,p2;
int res;
#ifdef DEBUG_CALLS
LOG7("daveReadBytes(dc:%p area:%s area number:%d start address:%d byte count:%d buffer:%p)\n",
dc, daveAreaName(area), DBnum, start,len, buffer);
FLUSH;
#endif
if (dc->iface->protocol==daveProtoAS511) {
return daveReadS5Bytes(dc, area, DBnum, start, len/*, buffer*/);
}
dc->AnswLen=0; // 03/12/05
dc->resultPointer=NULL;
dc->_resultPointer=NULL;
p1.header=dc->msgOut+dc->PDUstartO;
davePrepareReadRequest(dc, &p1);
daveAddVarToReadRequest(&p1, area, DBnum, start, len);
res=_daveExchange(dc, &p1);
if (res!=daveResOK) return res;
res=_daveSetupReceivedPDU(dc, &p2);
if (daveDebug & daveDebugPDU)
LOG3("_daveSetupReceivedPDU() returned: %d=%s\n", res,daveStrerror(res));
if (res!=daveResOK) return res;
res=_daveTestReadResult(&p2);
if (daveDebug & daveDebugPDU)
LOG3("_daveTestReadResult() returned: %d=%s\n", res,daveStrerror(res));
if (res!=daveResOK) return res;
if (p2.udlen==0) {
return daveResCPUNoData;
}
/*
copy to user buffer and setup internal buffer pointers:
*/
if (buffer!=NULL) memcpy(buffer,p2.udata,p2.udlen); // Buffer Overflow
dc->resultPointer=p2.udata;
dc->_resultPointer=p2.udata;
dc->AnswLen=p2.udlen;
return res;
}
In this function, the code emits a read command to the PLC, and processes the response from the PLC, storing the response into the target ‘buffer’.
The mistake occurs during the memcpy() operation (marked with a ‘Buffer Overflow’ comment above). While the user of the function passes in a buffer pointer (‘*buffer’) and expected response length (‘len’), the code does not verify that the response received was less than or equal to the expected size by validating ‘p2.udata’ and ‘p2.udlen’. This is a classic C programming mistake. The caller would likely expect that the function will only write up to ‘len’ bytes into ‘buffer’, but what the function does is completely out of the caller’s hands.
This bug could be triggered for example if an end user of the application opened the app in, say, a coffeeshop, and did not connect to their control system VPN. The application would attempt to communicate with the PLC on the coffeeshop network. An attacker could pretend to be the PLC, and could reply to a request with a response that exceeds the expected buffer size, resulting in a buffer overflow.
This bug is interesting because while the Android application itself is written in Java, it uses the C-language version of the nodave library using JNI calls. This means that the bug in libnodave could actually allow remote code execution inside the app. OWASP has a nice writeup on this kind of issue here.
There are many more such programming mistakes in the C version of the libnodave library, including numerous potential null pointer derefences and several other buffer overflows. Whether they can be triggered in this application is an exercise left to the reader.
There are two other Android applications for interfacing with S7 PLCs which also use libnodave, but both make use of the native Java version of the library: S7 PLC HMI Lite (also available in a commercial version) and S7Android. These versions won’t have the buffer overflow issues, though they may contain native Java bugs.
Using the two vulnerable apps mentioned in this post for critical infrastructure management should surely be out of the question.
Securing mobile device access to a control environment presents a whole new series of challenges. One is the BYOD aspect of mobile. In the first vulnerable application example, it could be incredibly dangerous if the same device also had a malicious version of, say, Flappy Birds installed on the device. In the second vulnerable example, we see how taking a mobile device outside of your ICS environment (keyword: ‘mobile’) introduces genuine software defects that would not otherwise be accessible, which may end up compromising the device.
In both cases, it is ‘bye-bye security perimeter.’ The challenge then becomes one of minimizing the possibility of damage. Time is fortunately still on the side of security; there aren’t very many mobile applications out there, and those that are are not very widely adopted. The trick in going down this path will surely be one of pushing data out of the control perimeter where a mobile device can digest it. Then, if changes are needed to the process control recipe, either phone in the change or make the long drive to the plant.
Image by ekilby