WEBVTT

00:01.100 --> 00:05.840
Hi, I'm Jake LaBelle, and my talk today is going to be on finding surrogate chains on a mainframe.

00:07.120 --> 00:08.280
So, who am I?

00:08.280 --> 00:10.680
I'm a security consultant at F-Secure.

00:11.760 --> 00:14.680
Technically associate, but sounds a bit shit, so...

00:15.820 --> 00:19.960
I've been on a couple mainframe jobs, so I'm not an expert by any means.

00:20.020 --> 00:25.200
I'm currently streaming from Basingstoke, UK, which is in Vegas, but what can you do?

00:25.440 --> 00:29.400
And I was going to put a picture here, but just look to the right, and yep, there I am.

00:31.380 --> 00:40.360
So, before I go into my tool that I've created, I'll just do a quick high-level introduction to ZOS, which is the operating system that you find on most mainframes.

00:41.400 --> 00:49.260
One of the major differences between Linux, Windows, and ZOS is that ZOS has datasets.

00:49.440 --> 01:06.980
So, for example, here it's user01.rexlib, and one thing to know about it is it's a flat file system, so there's no folders, but normally how it works is that you'll have your high-level qualifier which is normally the owner first, so user01, and then .something,

01:06.980 --> 01:09.100
.something, blah, blah, blah.

01:09.460 --> 01:12.360
And you have apostrophes around datasets.

01:12.360 --> 01:14.700
This indicates that it's an absolute path.

01:14.700 --> 01:21.280
In all of my Gator program, I have apostrophes around every single dataset because it's just easier.

01:21.680 --> 01:30.300
You can also have partitioned datasets, where user01.rexlib is the dataset, but then you can have multiple members in that dataset.

01:30.300 --> 01:32.580
So, for example, in this one it would be hello.

01:32.960 --> 01:41.940
And the picture below is just a picture of DSList, which shows all the datasets of a high-level qualifier of IBM user.

01:44.620 --> 01:51.120
So, my program is mostly written in Rex, which is a scripting language like Python.

01:51.460 --> 01:54.900
It has a couple slightly unique functions, though.

01:54.900 --> 01:59.720
So, one of them is address, which lets you run a program in another program.

01:59.720 --> 02:16.740
So, this is running listDSD in TSO, and the output of that you can store using something called outtrap, which you will then put all the output of that TSO command into a stem variable, which is basically an array.

02:17.880 --> 02:22.500
So, another language that's used is the JCL, which is a job control language.

02:22.500 --> 02:30.540
It's a batch job, though, so when you submit a JCL, the JCL is then run at some point by the mainframe.

02:30.760 --> 02:37.660
And on the first line of every JCL you have the job card, which has the title of the job and a couple of other parameters.

02:37.660 --> 02:45.760
So, for example, this will notify the user after it's run, and it will also store it in the spool.

02:47.600 --> 02:55.040
So, in my program, all of the JCLs that I have are embedded inside Rex scripts.

02:55.360 --> 03:00.580
And so, this one, for example, it will queue all of the lines of the JCL.

03:00.580 --> 03:04.100
It will then use outtrap to concatenate those lines and then submit them.

03:04.140 --> 03:12.960
The reason why I use this in a Rex script is because you can then parse arguments easier, and you can then have a more dynamic JCL.

03:14.700 --> 03:23.000
So, one of the major subsystems on ZOS is OMVS, and it's a Unix subsystem.

03:23.000 --> 03:27.500
And it's kind of like the WSL Windows subsystem for Linux.

03:27.500 --> 03:33.160
However, there's no segregation between the two parts.

03:33.180 --> 03:40.320
So , there's no segregation between TSO and OMVS, TSO being the main part of where you log into the mainframe.

03:40.320 --> 03:45.600
So, on TSO, you can run OMVS commands, and on OMVS, you can run TSO commands.

03:45.600 --> 03:49.120
So, if you have access to one, you basically have access to the other.

03:49.700 --> 03:58.440
And the security of OMVS, so for example, what would be slash etc slash sudoers, is managed by RACF.

03:58.560 --> 04:03.040
And RACF is Resource Access Control Facility.

04:03.040 --> 04:17.180
And this can handle different types of resources, so for example, datasets, surrogates, or as mentioned before, the OMVS resources.

04:17.180 --> 04:20.320
So, for example, superuser would be in there.

04:21.840 --> 04:29.380
So, each resource has an owner, and they have alter access, so basically complete access to the resource.

04:29.380 --> 04:37.780
You can also set a UACC, which is how much access that just any random user has to the resource.

04:37.780 --> 04:40.520
You can also permit other users to have access.

04:40.520 --> 04:42.980
So, there's four different types of access you can give.

04:42.980 --> 04:49.460
It's execute, read, update, and alter, and they do what they sound like they do.

04:49.940 --> 04:57.100
One other special attribute you can give to a user is special.

04:57.100 --> 05:06.460
Special means that you basically have alter access to every single resource, which you can think of as being like having roots.

05:07.320 --> 05:13.380
One of the main classes in ZOS is surrogate, and there's a couple different types of these.

05:13.380 --> 05:26.060
So, we have star.submit, so for example, userid.submit, so user01.submit would mean if you had read access to this, you could submit a JCL as user01.

05:26.060 --> 05:35.320
There's also bpx.serve.userid, so for example, bpx.serve.user02 means you can run a su command as that user.

05:35.800 --> 05:42.900
There's also dfh.start.userid, and this just means you can run a Kix transaction as that user.

05:42.900 --> 05:56.840
I don't use dfh.start in my program, but maybe in the future.

05:58.980 --> 06:03.740
So, one thing that you'll find on mainframes are surrogate chains.

06:03.740 --> 06:10.340
The reason why these occur is because there's lots of users, and no one knows what all of them are for.

06:10.340 --> 06:20.760
So, for example, I was added as a user on a pentest job, and 20 years later, someone's probably going to ask, who is this Jake character, and why does he have access to these things?

06:20.760 --> 06:25.860
No one's going to know, and no one's going to delete it, because maybe it'll break something.

06:26.120 --> 06:30.120
And that also turns to the other thing, where mainframes have been running for decades.

06:30.280 --> 06:37.820
It's one of their major selling factor, so the person who added me is probably going to be long gone before the next person even looks at me.

06:37.820 --> 06:50.560
So, a surrogate chain is where, for example, user01 has read access to a surrogate class on user2, and user2 has read access to a surrogate on user3.

06:51.080 --> 06:57.060
So, in this case, user01 practically has access to everything that user3 has.

06:57.460 --> 07:03.880
And the way you can list what access, what surrogates you have, you can run a command rlist surrogate star.

07:03.880 --> 07:13.760
However, RACF has a thing where you can only see the protections on a RACF that you have at least read for.

07:13.760 --> 07:23.040
So, in this case, user01 would not be able to see that user2 has a read on a surrogate on user3.

07:23.280 --> 07:28.240
The other problem is that star.submit is a batch job.

07:28.240 --> 07:46.420
So, let's say you wanted to run a REC script that ran the JCL from user1 as a surrogate on user2, and then wanted to, from user2, run a JCL to user3.

07:46.420 --> 07:51.920
You can't just run that in one program because it's using a JCL, which, again, is a batch job.

07:51.920 --> 07:56.240
So, what you could do is you could manually submit reverse shells one at a time.

07:56.240 --> 08:03.140
So, you'd, as user1, find out that you had a user2 surrogate, then you would submit a reverse shell for user2.

08:03.140 --> 08:08.580
Then, once you're as user2, you'd list all your surrogates again, and then you'd submit a reverse shell for user3.

08:08.700 --> 08:14.600
However, this takes a long time, and there's a lot of users, so this might not even be feasible.

08:15.680 --> 08:20.200
Another thing you could do is you could just use a user which has read access to all the resources.

08:20.200 --> 08:23.960
So, for example, a special account or an auditor account.

08:24.580 --> 08:29.740
Auditor doesn't really... they don't really have read access to these, but they basically do.

08:31.900 --> 08:36.340
Then, you could also then use this to find all the surrogate chains.

08:36.340 --> 08:39.780
The only problem with this is that you're not going to get a special account.

08:39.780 --> 08:46.620
You're definitely not going to get a special account on a pen test, and you probably won't get an auditor account on a pen test either.

08:47.900 --> 08:49.340
So, I created a tool.

08:49.340 --> 08:57.160
Here's the GitHub link to it, and it allows you to find and exploit surrogate chains.

08:57.380 --> 08:59.820
So, the first thing you do with the tool is you run begin.reqs.

08:59.820 --> 09:01.620
It gets all the output datasets ready.

09:01.620 --> 09:09.700
It gets the Unix file ready, and it adds the current user that you're running it from to the path, and it starts geo.reqs.

09:10.520 --> 09:18.920
geo.reqs gets the path that it currently is at, so when you first run it, it would just be the original user.

09:19.000 --> 09:25.380
If it's special, if your user that you have is special, it will just stop, because if you have special, you've already won.

09:25.700 --> 09:28.920
It will then run plugins.reqs, which I'll explain later.

09:29.080 --> 09:35.020
It will list all the surrogates that you have read access to, and then it checks that those surrogates haven't been visited yet.

09:35.020 --> 09:41.560
The reason why I had to add this is because I didn't want to have to deal with cycles, and this was the quickest and easiest way to deal with that.

09:41.660 --> 09:48.980
So, you won't actually get the whole, I guess, surrogate network, but you will get a chain through them.

09:50.160 --> 09:59.120
If it sees that it's a star.submit resource, it will run subm.reqs, and if it sees that it's a bpx.sub.star resource, it will run unixm.reqs.

09:59.120 --> 10:07.340
So, subm.reqs just submits a JCL as the surrogate user, which then runs gator.reqs, so then it will continue it on.

10:08.080 --> 10:11.240
Unixm.reqs is a JCL which just runs gator.

10:11.240 --> 10:26.340
It's moved into OMVS with begin.reqs to slash temp slash unixm, and then gator calls it with bpx batch, with which you run OMVS commands in TSO, and then you do su to that target user.

10:26.340 --> 10:31.640
So, plugins.reqs is a list of req scripts to run on each user.

10:34.380 --> 10:36.920
There's a number of enumeration scripts you can run.

10:36.920 --> 10:40.600
I have three that I have set up already.

10:40.740 --> 10:51.080
One of them just lists the user, so this will tell you if they have special, if they have operations, what groups they're connected to, those types of things.

10:52.780 --> 11:01.160
I also have one which will just list your access to all of the RACF databases.

11:01.160 --> 11:07.100
It's unlikely you'll have anything other than none for this, but, eh, might as well test.

11:07.100 --> 11:09.000
If you have read access, it's really good.

11:09.000 --> 11:13.640
It lets you unload the database so you can see all the things in the RACF database.

11:13.640 --> 11:14.940
Really useful.

11:14.940 --> 11:26.160
If you have update or alter, then you can just put yourself in as special, and I have a tool to just write yourself in, but, yeah, they're very unlikely, but if it does happen, hit the jackpot.

11:26.940 --> 11:33.160
The other one is it will search all of the APF libraries to see what access you have to those.

11:33.160 --> 11:38.040
You can think of APF libraries as kind of like setguid libraries in Unix.

11:38.040 --> 11:45.720
It's not really, but if you have update or alter, you can get special, and there's tools out there to do that.

11:46.700 --> 12:02.600
Oh, and also, if you have any other scripts you want to add, it's fairly easy to just, it's fairly extensible, just add your own REC script in, and, like, for example, if you have just a Linux script that you have that you can use, you can quickly add that to there.

12:03.820 --> 12:21.200
So, to test to see that the program was working properly, I, using an emulated ZOS, created a thousand users, then randomly assigned a couple operators and a couple special users, added a couple of surrogates of each type to each user, and then ran Gator,

12:21.200 --> 12:24.640
the test script to generate all of these users on GitHub as well.

12:24.640 --> 12:44.780
So, using the output of all the paths that were generated and also the list user command, so here you can see the large squares are operators and the big star is special, shows you all the paths to get to these users.

12:44.960 --> 12:50.900
If anyone can think of a better way to show a thousand nodes on a graph, then, yeah, that'd be helpful.

12:51.740 --> 13:14.500
I also created a shell macro, so from the user that you ran the Gator from, you can pick any user that's in the path, the surrogate chain, and it will run shell B, that user, it will then keep submitting a JCL, continuously passing on how far along in the target it is,

13:14.500 --> 13:22.480
how far along in the path to the target is, and at the end it will submit a catso shell, it's like an interpreter, here's the GitHub link to it by mainframed.

13:24.300 --> 13:32.300
I've also just created a bash script which will quickly upload all the rec scripts, it's just quick to set that up.

13:33.280 --> 13:39.660
And yeah, that's my tool, and I'll do a quick thing on if you want to get into mainframes yourself.

13:39.660 --> 13:50.260
So probably the easiest way is with TK4-, it's based on a 1980s mainframe, MVS 3.8J, it runs on a Raspberry Pi, which is pretty cool.

13:50.580 --> 13:54.140
Everything is open source and public domain, pretty cool again.

13:54.140 --> 14:03.500
Here's the link to download it, and there's a user guide to just get started, and yeah, here's a picture of it, again, pretty cool.

14:06.200 --> 14:16.400
And on there you can install two fairly important things, so you can get Kix, which is a Kix clone, and there's a Moshix guide, I've put the YouTube link to it.

14:16.400 --> 14:24.720
And Kix is like web servers, before web servers were cool, so you can test your COBOL scripting.

14:25.620 --> 14:37.240
And Rex is just a backported thing that lets you run rec scripts, again, here's the Moshix guide to get it installed.

14:37.240 --> 14:43.120
If you can't be bothered to get these installed, I have one with these already installed on my GitHub.

14:43.180 --> 14:45.080
TK4-base is what I called it.

14:45.860 --> 14:56.280
Another tool to get started on mainframes is Hercules, it's a QPublic license, it's a mainframe emulator, and it's what TK4 uses to run.

14:56.860 --> 15:08.120
Now there is an old version of ZOS version 1.10 online, but piracy is bad, so don't do that.

15:08.120 --> 15:19.060
But if you do end up getting a ZOS version, there's a GitHub link to mainframes labs, and they're pretty good to get started.

15:20.320 --> 15:27.960
And there's a Mattermost community that's fairly good to answer any questions.

15:27.960 --> 15:34.900
If you want to ask me any questions, my username is Tadasu, so drop me a message on there and I'll answer.

15:34.900 --> 15:39.180
And that's my talk done.

15:39.520 --> 15:40.900
Are there any questions?

