Finding the Callable Services

The posts here won’t initially be in a start-from-the-beginning order.   However, as I get more of them up,  they will contain all the steps to help you set up your Z environment to begin building exploits and shellcode.

This post is about finding the addresses of what IBM refers to as the Assembler Callable Services (or sometimes USS Callable Services).  These addresses can be thought of loosely analogous to the Procedure Linkage Table / Global Offset Table duo used in Linux to find addresses of common functions from position independent code.   If mainframe programs are written in a higher level language such as High-Level Assembler (HLASM) or C, these functions can be called and the linker will take care of this for you at runtime.   Since our shellcode needs to be able to mimic this, we will find these addresses ourselves, using examples provided by IBM.

First off, what are these services?   From their documentation, “These services are interfaces between the z/OS operating system and standard (POSIX or Single UNIX Specification) programming functions that require operating system services.”  In other words, these are the common functions needed to build shell code in the Unix System Services environment.   Things like:  exec,  setting up a socket listener, setting up an outbound socket, reading from a socket, opening, writing, reading and closing a file, and many more are all part of the Callable Services Routines (CSR).

The examples in Appendix A of the first manual linked below, show the assembler commands to do this lookup.

Example from Appendix A:  Assembler Callable Services
Example from Appendix A: Assembler Callable Services

The offset mentioned in the last Load line above is a number pulled from a table in the same document, that is specific to the function needed.  For instance, the offset for the BPX1EXC function (basically exec) is 228.   Most people beginning exploit development on System Z won’t be familiar with HLASM or IBM System Z machine code (opcodes) right away, so the code snippets I use here are written in C, but do the same function.

#include <stdio.h>

int main(int argc, char ** argv){
unsigned char *loc;
(loc) = (unsigned char *)0;

memcpy(&(loc),(loc+16),sizeof(loc));
printf("Base CVR Address:\t%#010x\n",loc);

memcpy(&(loc),(loc+544),sizeof(loc));
printf("Base CSRTABLE Address:\t%#010x\n",loc);

memcpy(&(loc),(loc+24),sizeof(loc));
printf("Base CSR SLOT Address:\t%#010x\n",loc);

memcpy(&(loc),(loc+228),sizeof(loc));
printf("Base BPX1EXC Address:\t%#010x\n",loc);
return 0;
}

The program above can be compiled using a simple “cc -o pgm pgm.c” and run within USS.   A JCL version is included at the end of this post.   The output from running the program will look something like this (the addresses will likely vary on your system):

Ouput from above program

Line by line at a high level here is what’s happening:

The initial address is the address of the Communications Vector Table (CVT).  According to IBM’s manual this address is always stored at 0x10, and contains (depending on the offset) locations of many system data structures.  The address stored at location 0x10 is increased by 544 and the resultant location is where the next address is read.   This location yields the base of the Callable Service Routine table (CSRTABLE) – containing many system-wide CSRs.   The services we are looking for (another nested-level deep) is in the slot within this table.

This location is again found by taking the address stored in the previously calculated memory location, adding 24 this time (as stated in the manual clip above), and reading yet another address from the resulting location.   This one (0x1532998 in our example) is the base of the table for the routines we want (all of the UNIX services provided).  Once we have it, we can look up in the table (Appendix A of the PDF linked to below) the routine needed.   For our example, offset 228 is added to the address in that location and the final address of the BPX1EXC function is found to be at 0x15333a4.

That address can be used, assuming all the registers are set correctly with parameters, environment variables and arguments – to call the function and execute a command.   This is thoroughly documented in the manual (in the usual way-too-much-information style I’ve grown used to) – but I’ll break it down in a future post.

The manual for all the services can be found in PDF format on IBM’s website here.

Another interesting IBM read on the services here.

JCL for the same C program used above.

In a future post I’ll look at calling one of these commands, using the dbx debugger, how to pull shellcode out of your compiled C program on system Z and test it, and explore the idea of a “return to libc” style attack on this platform.