Mainframe Bind Shell – Source Code

Key in any basic toolset for pentesting the mainframe platform is a selection of payloads that can be used to test vulnerabilities.

Below is a bind shell payload, written from scratch in mainframe assembler.  The shell can be connected to using netcat. The payload differs from its Intel counterparts, in that it contains its own EBCDIC to ASCII convertor.  Because of this, the standard exec(‘/bin/sh’,’sh’) could not be used.  Read on for more technical details.

Using the EXEC function causes us to lose control of the STDIN/OUT file descriptors, since we need to translate the character set, this will not work.

Instead I built it to use a FORK/PIPE combo of function so that each inbound byte (presuming 100% of the testing will be done from an ASCII based platform) is converted to EBCDIC and each outbound byte is converted to ASCII.

The full link to the program source code is at the bottom of the post, what follows is a detailed breakdown of the code.

  1. Below is the setup, pretty standard one that I use when developing quick code tests or full apps.  Essentially it just saves the callers registers, and sets up ours.

  1. Next loads all the addresses of the Assembler Callable Functions we use to execute this program.  They are all stored by name in a data segment beginning at FFUNC address.  This snippet replaces those names with the actual callable memory address.

  1. Below sets up the pipes (two of them) used to communicate between the parent proc and the child proc.  Each pipe has a read and a write file descriptor.  These will later be used to send bytes to our spawned shell and read the output to pass back to the client.

  1. Once the pipes are built, we fork a child process.  Initially the child process has its own copy of the same file descriptors (STDIN,STDOUT,STDERR, etc.) as the parent process.

  1. A key part of this whole program working is contained below in the line that is “CIB 2,0,7,@PREPPAR”  In this instruction we check the return value from the fork.  Once the fork is complete, the parent process gets the child’s PID (Process ID) as the return value from the fork.   The child PID (which picks up execution in the same program as the parent, just after the fork) gets a 0 as a return code.

Using this information, we can now code specifically for the child PID or the parent PID by testing the fork return code.

Just after the CIB instruction (we are executing instructions only in the child process here, the parent jumped to @PREPPAR.  The instructions that follow the CIB then, set up the child’s file descriptors (FD) like this:

  1. Pipes set up; now a shell can be exec’d.  This process will inherit the FDs we just create, it’s STDIN,OUT,ERR mapped to the parent PID via pipes.

  1. This section is where the parent PID jumps after the fork and CIB stmt in step 5 above.  Here we also groom our pipe FDs, closing the READ FD on the pipe that corresponds with the WRITE FD closed by the child initially.  Also, close the WRITE FD on the same pipe as the READ FD the child closed initially.  This is by far the most confusing part of the whole setup.

  1. Here are the Socket,Bind,Listen and Accept calls that are pretty standard, if you’ve done any socket work, this will look very familiar.  At the end of the accept call, the machine is listening on the port you specific and waiting for a connection from the client.

  1. After the initial connection is made, we are going set the Client socket FD and the FD used to read from the child process to non-blocking.  Doing so allows us to monitor both quickly, allowing near instantaneous response and long interactions.

  1. This is the main loop of the program.  Initially it perpetually reads from the client socket, waiting for input.  Once input is received, it converts that input byte by byte from ASCII to EBCDIC.  The EBCDIC bytes are then written to the child process via one of our pipes.  After a write, the child process is read until there is no more output waiting.

Bytes read from the child process (output from our shell) are converted back to ASCII and written to the client’s socket, then the loop carries on.

  1. These are the common functions called by the segments above: READ,WRITE,FCNTL,PIPE.   Notations are made in the full source code about any inputs / outputs to these functions.

  1. These two functions are customized ASCII to EBCDIC and vice versa.   They very simply use 2 lookup tables of 255 bytes each.   The E2A table are ASCII bytes ordered by EBCDIC index, the reverse for the other.   So to change the ASCII byte \x41 to EBCDIC \xc1, for instance, you’d look up the \x41st element in the A2E table and read the corresponding byte (\xc1).   The opposite table for the reverse conversion.

  1. This just cleans up and restores registers that were saved in step 1.

The full source has more notations, all the constants, error checking and handling, etc.    This code is my first go at this, it’s fully functional – but certainly it has some room for optimization and improvement.

If this interests you, come see my talk at this year’s Derbycon 5.0 Saturday at 5:30pm!

Link to the full source on zedsec390 github.