1 00:00:01,100 --> 00:00:05,840 Hi, I'm Jake LaBelle, and my talk today is going to be on finding surrogate chains on a mainframe. 2 00:00:07,120 --> 00:00:08,280 So, who am I? 3 00:00:08,280 --> 00:00:10,680 I'm a security consultant at F-Secure. 4 00:00:11,760 --> 00:00:14,680 Technically associate, but sounds a bit shit, so... 5 00:00:15,820 --> 00:00:19,960 I've been on a couple mainframe jobs, so I'm not an expert by any means. 6 00:00:20,020 --> 00:00:25,200 I'm currently streaming from Basingstoke, UK, which is in Vegas, but what can you do? 7 00:00:25,440 --> 00:00:29,400 And I was going to put a picture here, but just look to the right, and yep, there I am. 8 00:00:31,380 --> 00: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. 9 00:00:41,400 --> 00:00:49,260 One of the major differences between Linux, Windows, and ZOS is that ZOS has datasets. 10 00:00:49,440 --> 00: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, 11 00:01:06,980 --> 00:01:09,100 .something, blah, blah, blah. 12 00:01:09,460 --> 00:01:12,360 And you have apostrophes around datasets. 13 00:01:12,360 --> 00:01:14,700 This indicates that it's an absolute path. 14 00:01:14,700 --> 00:01:21,280 In all of my Gator program, I have apostrophes around every single dataset because it's just easier. 15 00:01:21,680 --> 00: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. 16 00:01:30,300 --> 00:01:32,580 So, for example, in this one it would be hello. 17 00:01:32,960 --> 00: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. 18 00:01:44,620 --> 00:01:51,120 So, my program is mostly written in Rex, which is a scripting language like Python. 19 00:01:51,460 --> 00:01:54,900 It has a couple slightly unique functions, though. 20 00:01:54,900 --> 00:01:59,720 So, one of them is address, which lets you run a program in another program. 21 00:01:59,720 --> 00: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. 22 00:02:17,880 --> 00:02:22,500 So, another language that's used is the JCL, which is a job control language. 23 00:02:22,500 --> 00: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. 24 00:02:30,760 --> 00: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. 25 00:02:37,660 --> 00:02:45,760 So, for example, this will notify the user after it's run, and it will also store it in the spool. 26 00:02:47,600 --> 00:02:55,040 So, in my program, all of the JCLs that I have are embedded inside Rex scripts. 27 00:02:55,360 --> 00:03:00,580 And so, this one, for example, it will queue all of the lines of the JCL. 28 00:03:00,580 --> 00:03:04,100 It will then use outtrap to concatenate those lines and then submit them. 29 00:03:04,140 --> 00: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. 30 00:03:14,700 --> 00:03:23,000 So, one of the major subsystems on ZOS is OMVS, and it's a Unix subsystem. 31 00:03:23,000 --> 00:03:27,500 And it's kind of like the WSL Windows subsystem for Linux. 32 00:03:27,500 --> 00:03:33,160 However, there's no segregation between the two parts. 33 00:03:33,180 --> 00:03:40,320 So , there's no segregation between TSO and OMVS, TSO being the main part of where you log into the mainframe. 34 00:03:40,320 --> 00:03:45,600 So, on TSO, you can run OMVS commands, and on OMVS, you can run TSO commands. 35 00:03:45,600 --> 00:03:49,120 So, if you have access to one, you basically have access to the other. 36 00:03:49,700 --> 00:03:58,440 And the security of OMVS, so for example, what would be slash etc slash sudoers, is managed by RACF. 37 00:03:58,560 --> 00:04:03,040 And RACF is Resource Access Control Facility. 38 00:04:03,040 --> 00:04:17,180 And this can handle different types of resources, so for example, datasets, surrogates, or as mentioned before, the OMVS resources. 39 00:04:17,180 --> 00:04:20,320 So, for example, superuser would be in there. 40 00:04:21,840 --> 00:04:29,380 So, each resource has an owner, and they have alter access, so basically complete access to the resource. 41 00:04:29,380 --> 00:04:37,780 You can also set a UACC, which is how much access that just any random user has to the resource. 42 00:04:37,780 --> 00:04:40,520 You can also permit other users to have access. 43 00:04:40,520 --> 00:04:42,980 So, there's four different types of access you can give. 44 00:04:42,980 --> 00:04:49,460 It's execute, read, update, and alter, and they do what they sound like they do. 45 00:04:49,940 --> 00:04:57,100 One other special attribute you can give to a user is special. 46 00:04:57,100 --> 00: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. 47 00:05:07,320 --> 00:05:13,380 One of the main classes in ZOS is surrogate, and there's a couple different types of these. 48 00:05:13,380 --> 00: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. 49 00:05:26,060 --> 00: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. 50 00:05:35,800 --> 00:05:42,900 There's also dfh.start.userid, and this just means you can run a Kix transaction as that user. 51 00:05:42,900 --> 00:05:56,840 I don't use dfh.start in my program, but maybe in the future. 52 00:05:58,980 --> 00:06:03,740 So, one thing that you'll find on mainframes are surrogate chains. 53 00:06:03,740 --> 00: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. 54 00:06:10,340 --> 00: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? 55 00:06:20,760 --> 00:06:25,860 No one's going to know, and no one's going to delete it, because maybe it'll break something. 56 00:06:26,120 --> 00:06:30,120 And that also turns to the other thing, where mainframes have been running for decades. 57 00:06:30,280 --> 00: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. 58 00:06:37,820 --> 00: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. 59 00:06:51,080 --> 00:06:57,060 So, in this case, user01 practically has access to everything that user3 has. 60 00:06:57,460 --> 00:07:03,880 And the way you can list what access, what surrogates you have, you can run a command rlist surrogate star. 61 00:07:03,880 --> 00: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. 62 00:07:13,760 --> 00:07:23,040 So, in this case, user01 would not be able to see that user2 has a read on a surrogate on user3. 63 00:07:23,280 --> 00:07:28,240 The other problem is that star.submit is a batch job. 64 00:07:28,240 --> 00: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. 65 00:07:46,420 --> 00:07:51,920 You can't just run that in one program because it's using a JCL, which, again, is a batch job. 66 00:07:51,920 --> 00:07:56,240 So, what you could do is you could manually submit reverse shells one at a time. 67 00:07:56,240 --> 00: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. 68 00:08:03,140 --> 00: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. 69 00:08:08,700 --> 00:08:14,600 However, this takes a long time, and there's a lot of users, so this might not even be feasible. 70 00:08:15,680 --> 00:08:20,200 Another thing you could do is you could just use a user which has read access to all the resources. 71 00:08:20,200 --> 00:08:23,960 So, for example, a special account or an auditor account. 72 00:08:24,580 --> 00:08:29,740 Auditor doesn't really... they don't really have read access to these, but they basically do. 73 00:08:31,900 --> 00:08:36,340 Then, you could also then use this to find all the surrogate chains. 74 00:08:36,340 --> 00:08:39,780 The only problem with this is that you're not going to get a special account. 75 00:08:39,780 --> 00: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. 76 00:08:47,900 --> 00:08:49,340 So, I created a tool. 77 00:08:49,340 --> 00:08:57,160 Here's the GitHub link to it, and it allows you to find and exploit surrogate chains. 78 00:08:57,380 --> 00:08:59,820 So, the first thing you do with the tool is you run begin.reqs. 79 00:08:59,820 --> 00:09:01,620 It gets all the output datasets ready. 80 00:09:01,620 --> 00: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. 81 00:09:10,520 --> 00: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. 82 00:09:19,000 --> 00: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. 83 00:09:25,700 --> 00:09:28,920 It will then run plugins.reqs, which I'll explain later. 84 00:09:29,080 --> 00: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. 85 00:09:35,020 --> 00: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. 86 00:09:41,660 --> 00:09:48,980 So, you won't actually get the whole, I guess, surrogate network, but you will get a chain through them. 87 00:09:50,160 --> 00: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. 88 00:09:59,120 --> 00: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. 89 00:10:08,080 --> 00:10:11,240 Unixm.reqs is a JCL which just runs gator. 90 00:10:11,240 --> 00: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. 91 00:10:26,340 --> 00:10:31,640 So, plugins.reqs is a list of req scripts to run on each user. 92 00:10:34,380 --> 00:10:36,920 There's a number of enumeration scripts you can run. 93 00:10:36,920 --> 00:10:40,600 I have three that I have set up already. 94 00:10:40,740 --> 00: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. 95 00:10:52,780 --> 00:11:01,160 I also have one which will just list your access to all of the RACF databases. 96 00:11:01,160 --> 00:11:07,100 It's unlikely you'll have anything other than none for this, but, eh, might as well test. 97 00:11:07,100 --> 00:11:09,000 If you have read access, it's really good. 98 00:11:09,000 --> 00:11:13,640 It lets you unload the database so you can see all the things in the RACF database. 99 00:11:13,640 --> 00:11:14,940 Really useful. 100 00:11:14,940 --> 00: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. 101 00:11:26,940 --> 00:11:33,160 The other one is it will search all of the APF libraries to see what access you have to those. 102 00:11:33,160 --> 00:11:38,040 You can think of APF libraries as kind of like setguid libraries in Unix. 103 00:11:38,040 --> 00: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. 104 00:11:46,700 --> 00: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. 105 00:12:03,820 --> 00: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, 106 00:12:21,200 --> 00:12:24,640 the test script to generate all of these users on GitHub as well. 107 00:12:24,640 --> 00: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. 108 00:12:44,960 --> 00: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. 109 00:12:51,740 --> 00: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, 110 00:13:14,500 --> 00: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. 111 00:13:24,300 --> 00: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. 112 00:13:33,280 --> 00: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. 113 00:13:39,660 --> 00: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. 114 00:13:50,580 --> 00:13:54,140 Everything is open source and public domain, pretty cool again. 115 00:13:54,140 --> 00: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. 116 00:14:06,200 --> 00: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. 117 00:14:16,400 --> 00:14:24,720 And Kix is like web servers, before web servers were cool, so you can test your COBOL scripting. 118 00:14:25,620 --> 00: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. 119 00:14:37,240 --> 00:14:43,120 If you can't be bothered to get these installed, I have one with these already installed on my GitHub. 120 00:14:43,180 --> 00:14:45,080 TK4-base is what I called it. 121 00:14:45,860 --> 00: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. 122 00:14:56,860 --> 00:15:08,120 Now there is an old version of ZOS version 1.10 online, but piracy is bad, so don't do that. 123 00:15:08,120 --> 00: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. 124 00:15:20,320 --> 00:15:27,960 And there's a Mattermost community that's fairly good to answer any questions. 125 00:15:27,960 --> 00: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. 126 00:15:34,900 --> 00:15:39,180 And that's my talk done. 127 00:15:39,520 --> 00:15:40,900 Are there any questions?