By Isiah Jones VP, Global ICS Security Service Delivery & Brian Foster Sr ICS Cybersecurity Engineer
Within the industrial control systems (ICS), automation, operational technology (OT), cyber-physical systems (CPS), industrial internet of things (IIoT) and instrumentation communities many of the devices with some form of computing and logical capabilities rely on 5 primary programming languages specific to programmable logic controllers (PLCs) that are defined in IEC 61131-3 as Sequential Function Chart (SFC), Ladder Diagram aka Ladder Logic (LD), Function Block Diagram (FBD), Instruction List (IL) and Structure Text (ST). In the IT community OWASP, NIST, SANS, CMMI, ISC2 and EC-Council, among others, have already created secure coding and secure development guidelines, best practices, testing tools and tips for higher level languages such as C, C++, Java, Python, JSON, HTML, XML, SQL and others. Some could argue that Structure Text includes several of these high-level languages. However, there has not been much focus by international standards organizations or industry experts on implementing security within the other 4 primary PLC focused languages in ICS. As a result, we wanted to share some of our recommendations for each of the IEC 61131-3 PLC languages in a 5-part blog series and aggregated white paper. In part 1 of our series we focused on Sequential Function Chart (SFC), part 2 focused on Ladder Diagram or Ladder Logic (LD), part 3 focused on Function Block Diagram (FBD) and in part 4 we focused on Instruction List (IL). Here in part 5 we will finish off the series with Structure Text (ST).
If you are used to standard higher-level computer programming languages than you will already understand Structure Text (ST). ST is generally a C based programming language, but you can use languages such as python as well to create code for structure text. ST in some programming environments ST has built in objects that you can call the same way you would in LD or FBD. In some environments you can have ST called within function blocks and steps within SFC as well. With ST comes some of the more traditional programming attack surface such as buffer threats, input validation, logic threats and code processing overhead.
Within ST we believe the below recommended practices would improve the secure design and usage of ST within ICS devices by adding security, safety and resilience supportive concepts within the ST logic for all devices and operations that operate using ST. These recommended practices are in no particular order and this is not an all-inclusive list.
- Keep operational PLCs in run mode. This prohibits changes to the logic. It is often only changeable with physical access to the PLC. While this cannot prevent flaws in the code from being exploited it will stop the changing of the code by anyone who does not have physical access to the PLC.
- Keep all logic well documented and commented. This makes identifying rouge code easier, but also helps with day to day troubleshooting. The next person to work on the logic should always be able to understand what the last person did.
- Implement a code reuse library of fuzzed and regression tested clean code. This is especially important for creating reusable functions, classes, methods, variables, data dictionaries etc that can be leveraged on new projects.
- Implement OWASP, NIST and CMMI secure coding practices such as escaping unnecessary characters, buffer management, session management, lifecycle design principles etc. Ensure these principles are also documented and tested by a separate person than the person who wrote the original code.
- Leverage the prebuilt functions and tag types in the programming platform of your choice such as RSLogix 5000. This enforces a consistent programming format rather than each developer creating their own from scratch such as one shots, timers, counters, PID etc
- Create documented programming standards to ensure third parties and internal programmers follow same formats, code reuse library repository of tags, functions, variable nomenclature etc.
- Create custom alarming, notification and input validation and alerting program files that capture unwanted, unexpected and unauthorized inputs, outputs, logic modifications etc. Have your main program call or point to the custom alarms, notification and events program.
- Ensure you include thorough acceptance testing and user testing in your project timeline. This should include changes to code and integration of multiple languages such as calls between ST, LD, FBD, SFC, IL etc.
- Create and enforce a check-in and check-out of code process. Leverage such features in products such as Rockwell Automation’s FactoryTalk suite integration with RSLogix.
- Be sure to keep ST as simple as possible. Do not create more code and attack surface than necessary to execute tasks. Leverage built in objects and functions as much as possible rather than creating all custom ST when not necessary. Use the built in C syntax and libraries within the programming tools you are using that are compatible with the PLC, RTU, programmable relay etc. as much as possible before deviating to create your own custom code to perform the same actions.
We know there are many more possible best practices and recommendations that experienced individuals within the community can come up with. We wanted to be part of increasing the conversation for the creation of some formalized and well documented best practices guidelines for each of the 5 IEC 61131-3 PLC languages. Now that we are at the end of this series we will work to consolidate this 5-part series into a future PLC programming whitepaper for the community. We hope the community enjoyed this series and continue to encourage others to contribute as well.