1 00:00:00,000 --> 00:00:02,584 JOE BIALEK: This talk is called PowerPwning: Post 2 00:00:02,584 --> 00:00:05,459 Exploitation by Overpowering PowerShell. 3 00:00:05,959 --> 00:00:08,709 So my name is Joe Bialek. 4 00:00:08,999 --> 00:00:12,999 I'm a security engineer at a large software company, 5 00:00:12,999 --> 00:00:16,626 or actually, devices and services company 6 00:00:16,626 --> 00:00:18,584 in Redmond. 7 00:00:19,125 --> 00:00:21,125 You can find me on Twitter and I have 8 00:00:21,125 --> 00:00:23,125 a blog and GitHub. 9 00:00:25,542 --> 00:00:26,999 All right. 10 00:00:26,999 --> 00:00:27,999 So if any of you don't know anything 11 00:00:27,999 --> 00:00:30,999 about PowerShell, it's pretty awesome. 12 00:00:30,999 --> 00:00:34,999 PowerShell gives you full access to the Win32 API and 13 00:00:34,999 --> 00:00:38,167 all the .Net libraries, and PowerShell has 14 00:00:38,167 --> 00:00:43,459 a remoting functionality which allows you to connect to other systems 15 00:00:43,459 --> 00:00:46,250 and run scripts on them. 16 00:00:46,751 --> 00:00:50,042 And these scripts that you run over PowerShell remoting never touch 17 00:00:50,042 --> 00:00:52,751 disks on the remote system. 18 00:00:53,501 --> 00:00:56,792 In addition to that, any scripts that you run are going 19 00:00:56,792 --> 00:00:59,501 to run inside either the PowerShell.exe process 20 00:00:59,501 --> 00:01:03,209 if you run it on the local computer or the WSM prov host process 21 00:01:03,209 --> 00:01:06,292 if you run it on a remote computer. 22 00:01:06,375 --> 00:01:09,542 So this is pretty nice, too, because you don't have 23 00:01:09,542 --> 00:01:12,459 to execute any suspicious or unsigned processes, 24 00:01:12,459 --> 00:01:16,584 which means that you can generally bypass antivirus and application 25 00:01:16,584 --> 00:01:20,876 whitelisting assuming that PowerShell is whitelisted. 26 00:01:23,834 --> 00:01:26,459 So that's all pretty great. 27 00:01:26,584 --> 00:01:29,167 But I have a lot of pen test tools that I use right now 28 00:01:29,167 --> 00:01:33,626 that are all written in unmanaged code, and I really don't feel like porting 29 00:01:33,626 --> 00:01:36,876 all of those tools over to PowerShell. 30 00:01:37,083 --> 00:01:39,459 But I really want to take advantage of PowerShell's forensic benefits 31 00:01:39,459 --> 00:01:42,792 because you can be really sneaky if you use PowerShell. 32 00:01:42,876 --> 00:01:46,501 So the solution that I came up with is to write 33 00:01:46,501 --> 00:01:51,417 a PowerShell script that will just reflectively load PEs, which 34 00:01:51,417 --> 00:01:58,125 is what an executable in EXE file or a DLL is, in the PowerShell process. 35 00:01:58,125 --> 00:01:59,334 And execute them. 36 00:01:59,542 --> 00:02:01,876 So that's what I'm going to be talking about. 37 00:02:04,999 --> 00:02:08,250 So for those of you who don't know how loading PEs 38 00:02:08,250 --> 00:02:11,959 works, this is all documented on MSDN. 39 00:02:13,209 --> 00:02:16,167 I'm not going to go super in detail. 40 00:02:16,167 --> 00:02:18,167 But I want to give you an idea of kind of what Windows 41 00:02:18,167 --> 00:02:21,834 is doing when create process or load library is called. 42 00:02:21,999 --> 00:02:25,834 So what's going to happen is, first, memory is going to be allocated 43 00:02:25,834 --> 00:02:28,209 inside a process for the PE. 44 00:02:28,959 --> 00:02:31,999 Next, you're going to copy the PE into that memory. 45 00:02:32,417 --> 00:02:34,334 Then you're going to do what's called performing 46 00:02:34,334 --> 00:02:35,999 base relocations. 47 00:02:36,375 --> 00:02:38,959 So inside of a PE file, there's going to be a whole bunch 48 00:02:38,959 --> 00:02:41,999 of memory addresses that are hard coded. 49 00:02:42,083 --> 00:02:46,999 And the PE file in its header is going to supply a base address. 50 00:02:46,999 --> 00:02:48,999 So it's going to tell windows, this is the memory address that I'd 51 00:02:48,999 --> 00:02:50,918 like to be loaded to. 52 00:02:51,083 --> 00:02:53,167 And if you don't load me to this memory address, 53 00:02:53,167 --> 00:02:56,417 then you need to go and change all of the hard coded memory 54 00:02:56,417 --> 00:03:01,125 addresses in the PE file so that they point to valid memory locations. 55 00:03:01,125 --> 00:03:03,501 So you're just patching up these addresses. 56 00:03:03,501 --> 00:03:06,083 Next, the PE file that you're loading is probably going 57 00:03:06,083 --> 00:03:09,999 to have dependencies on other DLLs, so you need to load those. 58 00:03:10,083 --> 00:03:12,167 And then the last thing that you're going to do 59 00:03:12,167 --> 00:03:15,125 is you're going to call the entry function. 60 00:03:15,375 --> 00:03:18,876 So for a DLL, this is the DLL main function which just lets 61 00:03:18,876 --> 00:03:22,083 the DLL know that it's been loaded. 62 00:03:22,292 --> 00:03:24,417 And for an EXE, it's going to be 63 00:03:24,417 --> 00:03:28,417 a function which does some initialization and then eventually 64 00:03:28,417 --> 00:03:31,999 will call like into main in C++ or C or the equivalent 65 00:03:31,999 --> 00:03:34,999 to other programming languages. 66 00:03:37,999 --> 00:03:41,876 Oh, and I wanted to note that when I say that I'm going 67 00:03:41,876 --> 00:03:46,209 to be reflectively loading PE files, what I mean by this is that 68 00:03:46,209 --> 00:03:49,125 instead of relying on Windows load library 69 00:03:49,125 --> 00:03:53,501 or create process to go through and do those steps that I just 70 00:03:53,501 --> 00:03:59,083 listed, instead, I'm going to do all of those steps in PowerShell. 71 00:03:59,209 --> 00:04:03,459 And what this will allow me to do is the Windows functions require that 72 00:04:03,459 --> 00:04:06,209 the PE file is stored on disc. 73 00:04:06,209 --> 00:04:09,626 So you can't call load library on something that's just in memory. 74 00:04:09,626 --> 00:04:10,959 It has to be a file on disc. 75 00:04:10,959 --> 00:04:12,999 But if I rewrite all those functions in PowerShell, 76 00:04:12,999 --> 00:04:16,083 then I don't have that same constraint. 77 00:04:16,167 --> 00:04:20,999 So I can just hard code the PE file in a byte array inside the script. 78 00:04:21,083 --> 00:04:22,626 So this is really nice. 79 00:04:22,626 --> 00:04:24,209 Now I don't need to write executables and DLLs 80 00:04:24,209 --> 00:04:26,709 to disc to execute them. 81 00:04:26,709 --> 00:04:28,999 They just needed to be encoded in a PowerShell script which can then 82 00:04:28,999 --> 00:04:31,209 be run on remote systems. 83 00:04:32,209 --> 00:04:33,417 Okay. 84 00:04:33,417 --> 00:04:37,083 So for DLLs in particular, loading a DLL reflectively 85 00:04:37,083 --> 00:04:42,626 is really not much different than loading a DLL using load library, 86 00:04:42,626 --> 00:04:48,209 in the sense that when you call a DLL using load library. 87 00:04:48,209 --> 00:04:50,459 I mean, at the end of the day, a DLL is still being loaded 88 00:04:50,459 --> 00:04:53,375 inside of a process that already exists. 89 00:04:53,375 --> 00:04:55,667 So reflectively loading it, the only change here really 90 00:04:55,667 --> 00:04:59,209 is that I didn't call the load library function. 91 00:04:59,209 --> 00:05:00,209 I just wrote my own. 92 00:05:00,209 --> 00:05:02,542 But other than that, everything is the same. 93 00:05:02,542 --> 00:05:05,834 A DLL is still being loaded into a process which already exists. 94 00:05:05,876 --> 00:05:08,375 So the first thing you're going to want to do is you're going to want 95 00:05:08,375 --> 00:05:10,167 to call a DLL function that you exported, 96 00:05:10,167 --> 00:05:12,334 and this will contain your pay loader, you know, 97 00:05:12,334 --> 00:05:14,709 the code you want to execute. 98 00:05:15,083 --> 00:05:19,709 Then a little caveat with doing this is that if your DLL or your EXE 99 00:05:19,709 --> 00:05:23,417 for that matter outputs data using standard out, so 100 00:05:23,417 --> 00:05:29,999 like if you use print F or CL in C++, PowerShell can't capture that output. 101 00:05:31,834 --> 00:05:34,167 If you run a script locally, it doesn't matter because the output 102 00:05:34,167 --> 00:05:36,584 is still just going to be sent through the console host window, 103 00:05:36,584 --> 00:05:38,959 so you're going to see the output. 104 00:05:38,999 --> 00:05:41,083 But if you're doing PowerShell remoting, 105 00:05:41,083 --> 00:05:45,250 the only way that you can see output is if PowerShell can capture that output 106 00:05:45,250 --> 00:05:48,709 and serialize it and send it back to the computer that you did 107 00:05:48,709 --> 00:05:50,999 the remoting call from. 108 00:05:51,334 --> 00:05:54,999 So if you want to be able to see the output, what you're going to need 109 00:05:54,999 --> 00:05:57,999 to do is make the DLL function that you're calling 110 00:05:57,999 --> 00:06:01,375 return you a character array or like a byte character array 111 00:06:01,375 --> 00:06:04,751 and PowerShell can then take that pointer and marshal it 112 00:06:04,751 --> 00:06:09,792 into managed memory and then it can serialize that and send it back. 113 00:06:09,792 --> 00:06:12,125 So it's just a small change that you need to make. 114 00:06:12,125 --> 00:06:15,292 And on my blog, I have a post showing how it takes 115 00:06:15,292 --> 00:06:18,292 about five minutes to change meme cats 116 00:06:18,292 --> 00:06:24,083 from outputting using standard out to outputting to a string that can be, 117 00:06:24,083 --> 00:06:27,959 you know, retrieved by PowerShell. 118 00:06:29,999 --> 00:06:35,334 So reflectively loading an EXE is a little more tricky. 119 00:06:35,459 --> 00:06:36,999 Because normally when an EXE is loaded, 120 00:06:36,999 --> 00:06:39,834 it's loaded using create process, and a new process 121 00:06:39,834 --> 00:06:42,834 is created specifically for that EXE. 122 00:06:42,834 --> 00:06:46,876 But what we're doing is loading an EXE inside of a process that already 123 00:06:46,876 --> 00:06:48,792 exists with PowerShell.exe running 124 00:06:48,792 --> 00:06:50,459 inside of it. 125 00:06:50,834 --> 00:06:53,292 So as an example, normally when an EXE exits, so 126 00:06:53,292 --> 00:06:58,459 the EXE that you reflectively loads that you reflectively loaded runs and quits, 127 00:06:58,459 --> 00:07:00,999 it's going to go and call exit process 128 00:07:00,999 --> 00:07:04,209 because it thinks everything is done. 129 00:07:04,626 --> 00:07:06,083 But the problem is that that's actually going to kill 130 00:07:06,083 --> 00:07:07,459 the PowerShell process because that's 131 00:07:07,459 --> 00:07:09,918 the process that's actually running. 132 00:07:10,167 --> 00:07:11,999 And that's not ideal because you probably want you 133 00:07:11,999 --> 00:07:15,083 probably wanted to see the output from the EXE that you just ran, and 134 00:07:15,083 --> 00:07:17,751 if PowerShell just dies, you can't. 135 00:07:17,751 --> 00:07:21,209 And so it turns out there's a pretty easy solution to this. 136 00:07:22,959 --> 00:07:27,626 Basically what I do is I call the EXE in its own thread. 137 00:07:27,918 --> 00:07:31,125 I call its entry function in a new thread, and then you overwrite 138 00:07:31,125 --> 00:07:34,999 the exit process function with shell code that just calls exit 139 00:07:34,999 --> 00:07:36,876 thread instead. 140 00:07:36,876 --> 00:07:38,751 And so the EXE will start up in its own thread, 141 00:07:38,751 --> 00:07:40,999 and then when it's done running, it will just nicely kill 142 00:07:40,999 --> 00:07:43,375 the thread that you provided for it. 143 00:07:43,375 --> 00:07:45,250 So it's a really clean solution. 144 00:07:45,459 --> 00:07:47,459 And just for reference purposes, I put assembly in here, 145 00:07:47,459 --> 00:07:50,542 but we don't actually need to talk about this. 146 00:07:52,501 --> 00:07:53,918 Okay. 147 00:07:53,918 --> 00:07:55,709 So the other problem that I had reflectively loading an EXE 148 00:07:55,709 --> 00:07:59,792 is that you're going to want to pass that command line arguments. 149 00:07:59,876 --> 00:08:02,417 But the command line arguments that it's going to retrieve are 150 00:08:02,417 --> 00:08:04,542 the command line arguments that PowerShell started 151 00:08:04,542 --> 00:08:07,999 with because you're running inside the PowerShell process. 152 00:08:07,999 --> 00:08:10,999 And so it turns out that, well, the first thing I wanted 153 00:08:10,999 --> 00:08:14,167 to do was just go inside the process environment block, 154 00:08:14,167 --> 00:08:17,999 the PEB, which is where the command line arguments are stored 155 00:08:17,999 --> 00:08:20,334 and just overwrite the string that stores 156 00:08:20,334 --> 00:08:22,999 the command line arguments. 157 00:08:22,999 --> 00:08:26,751 But that doesn't actually work, because the way that EXE normally 158 00:08:26,751 --> 00:08:30,876 retrieves its command line arguments is it makes a function call 159 00:08:30,876 --> 00:08:35,834 to get command line or underscore underscore get command line. 160 00:08:35,918 --> 00:08:39,167 And those are provided by two different DLLs. 161 00:08:39,250 --> 00:08:42,999 And when those DLLs are initially loaded, they actually cache a copy 162 00:08:42,999 --> 00:08:46,209 of the command line arguments, so if you just overwrite the PEB, 163 00:08:46,209 --> 00:08:49,083 you didn't overwrite the cache copy that's in the DLLs, 164 00:08:49,083 --> 00:08:51,751 and so you're still just going to end up getting 165 00:08:51,751 --> 00:08:55,083 the command line arguments that PowerShell was started with which 166 00:08:55,083 --> 00:08:56,792 is no good. 167 00:08:56,834 --> 00:08:59,751 So I had to create solutions for both of these functions. 168 00:09:00,959 --> 00:09:04,459 So patching get command line is super easy. 169 00:09:04,999 --> 00:09:07,626 Get command line is a function that takes no arguments, 170 00:09:07,626 --> 00:09:09,999 and it just returns you a string pointer 171 00:09:09,999 --> 00:09:13,751 to the command line arguments with no formatting or anything done, 172 00:09:13,751 --> 00:09:17,999 so all you need to do in PowerShell is just allocate a string on the heap, 173 00:09:17,999 --> 00:09:20,999 and then overwrite the function call get command line 174 00:09:20,999 --> 00:09:24,209 with shell code that just returns the string, the address 175 00:09:24,209 --> 00:09:26,959 to the string you allocated. 176 00:09:27,167 --> 00:09:29,167 So very, very simple. 177 00:09:29,626 --> 00:09:30,999 Right? 178 00:09:31,334 --> 00:09:34,999 The next function underscore underscore get command line 179 00:09:34,999 --> 00:09:38,999 is a little more complicated to overwrite. 180 00:09:39,083 --> 00:09:41,876 So I didn't want to do that, and the reason is it takes a number 181 00:09:41,876 --> 00:09:44,876 of parameters and get this function actually goes and parses 182 00:09:44,876 --> 00:09:48,292 out your command line arguments into ARGV and ARGC. 183 00:09:48,334 --> 00:09:50,626 I didn't want to go through the trouble of parsing stuff 184 00:09:50,626 --> 00:09:52,334 if I didn't need to. 185 00:09:52,375 --> 00:09:55,250 But what I found is that the DLL that this function 186 00:09:55,250 --> 00:09:58,167 is exported from also exports two variables, 187 00:09:58,167 --> 00:10:01,501 A command line and W command line. 188 00:10:01,626 --> 00:10:04,125 And these variables are just spring pointers. 189 00:10:04,125 --> 00:10:06,999 And so if you go and overwrite these variables and then you call 190 00:10:06,999 --> 00:10:09,459 the get command line function, it will parse 191 00:10:09,459 --> 00:10:12,626 the variables that you just overwrote. 192 00:10:12,918 --> 00:10:14,999 So that's an even easier solution than the previous one 193 00:10:14,999 --> 00:10:17,834 because you just replaced those string pointers with pointers 194 00:10:17,834 --> 00:10:20,042 to strings that you allocate. 195 00:10:23,876 --> 00:10:24,999 Okay. 196 00:10:25,584 --> 00:10:30,918 So what about remote reflective DLL injection? 197 00:10:31,042 --> 00:10:32,417 That's possible, too. 198 00:10:32,417 --> 00:10:36,709 It's a little more painful to do it in PowerShell compared to C or C++, 199 00:10:36,709 --> 00:10:40,459 which is what some of the current remote reflectors are 200 00:10:40,459 --> 00:10:42,125 written in. 201 00:10:42,584 --> 00:10:45,751 But it turns out, it's still very possible to do. 202 00:10:45,999 --> 00:10:50,125 So the general process that I used for this is I allocate memory in both 203 00:10:50,125 --> 00:10:53,999 the remote process and the current process. 204 00:10:54,417 --> 00:10:57,167 And then I load the DLL into the current process, 205 00:10:57,167 --> 00:10:59,542 so into PowerShell.exe. 206 00:11:00,999 --> 00:11:05,667 And I'm pretty much just using PowerShell.exe to stage this. 207 00:11:05,918 --> 00:11:09,876 So I want to get it ready before I write it into the remote process. 208 00:11:10,209 --> 00:11:13,999 And what that entails is I go and I look and see what DLLs 209 00:11:13,999 --> 00:11:16,792 does this DLL depend on. 210 00:11:16,792 --> 00:11:17,999 Just like I did before. 211 00:11:17,999 --> 00:11:18,999 Right? 212 00:11:18,999 --> 00:11:21,209 Except when I load those DLLs, I actually load them 213 00:11:21,209 --> 00:11:23,501 in the remote process. 214 00:11:23,751 --> 00:11:27,250 And I get the function addresses for everything in the remote process. 215 00:11:27,792 --> 00:11:30,999 And when you do your base relocations, similarly, you use 216 00:11:30,999 --> 00:11:34,167 the memory address for the memory you allocated 217 00:11:34,167 --> 00:11:37,542 in the remote process when you're doing your base 218 00:11:37,542 --> 00:11:40,083 relocation calculations. 219 00:11:40,999 --> 00:11:44,375 And once you've done all this, you end up with the DLL which 220 00:11:44,375 --> 00:11:48,751 is currently in the PowerShell process, but all of the memory addresses have 221 00:11:48,751 --> 00:11:50,918 been patched as if it was being loaded 222 00:11:50,918 --> 00:11:53,083 in the remote process. 223 00:11:53,083 --> 00:11:56,709 So all you need to do is take those bytes and write them 224 00:11:56,709 --> 00:12:01,709 into the remote process and the DLL is pretty much ready to go. 225 00:12:01,709 --> 00:12:04,751 You just give it its own thread and it will start executing. 226 00:12:08,834 --> 00:12:11,999 So I just have, once again, more assembly here just 227 00:12:11,999 --> 00:12:16,125 for reference purposes for the shell code that you actually write 228 00:12:16,125 --> 00:12:21,999 into the remote process to call get or load library and get prop address. 229 00:12:23,999 --> 00:12:26,751 (Applause) SPEAKER: First time? 230 00:12:28,751 --> 00:12:30,417 All right. 231 00:12:32,417 --> 00:12:33,999 Wait a second. 232 00:12:33,999 --> 00:12:35,334 How you go back to that code? 233 00:12:35,334 --> 00:12:36,334 All right. 234 00:12:36,334 --> 00:12:37,334 Here we go. 235 00:12:37,334 --> 00:12:38,542 Everybody take notes. 236 00:12:38,542 --> 00:12:39,542 You got this? 237 00:12:46,999 --> 00:12:50,083 I know none of you understand why we're here. 238 00:12:52,876 --> 00:12:55,083 You know, it slays me how many new speakers 239 00:12:55,083 --> 00:12:57,918 there are at DEF CON this year. 240 00:12:57,918 --> 00:12:58,542 I'm beginning to think they're just saying that 241 00:12:58,542 --> 00:13:00,083 to fuck with us. 242 00:13:05,250 --> 00:13:06,792 Thank you, sir. 243 00:13:08,083 --> 00:13:12,584 And did we you got one? 244 00:13:12,584 --> 00:13:13,751 Yes, what's your name? 245 00:13:13,751 --> 00:13:14,751 AUDIENCE: Rick. 246 00:13:14,751 --> 00:13:16,999 SPEAKER: Rick, we got Rick, new attendee. 247 00:13:16,999 --> 00:13:18,459 He's representing all of you. 248 00:13:18,459 --> 00:13:19,459 All right. 249 00:13:19,459 --> 00:13:20,501 Cheers, gentlemen! 250 00:13:30,083 --> 00:13:32,667 (Applause) SPEAKER: We'll see you soon. 251 00:13:34,751 --> 00:13:36,792 JOE BIALEK: Everybody got that code? 252 00:13:40,083 --> 00:13:42,167 Probably not the most interesting slide 253 00:13:42,167 --> 00:13:44,125 to leave up there. 254 00:13:44,125 --> 00:13:45,125 All right. 255 00:13:45,125 --> 00:13:46,959 So let's do some demos. 256 00:14:01,083 --> 00:14:02,292 Okay. 257 00:14:02,292 --> 00:14:04,083 So I have two VMs here. 258 00:14:04,083 --> 00:14:06,626 This one with the gray background is a domain controller, and it's going 259 00:14:06,626 --> 00:14:08,083 to be targeted. 260 00:14:08,417 --> 00:14:10,626 And then I have this demo client. 261 00:14:11,792 --> 00:14:14,292 See if I can resize these windows. 262 00:14:14,751 --> 00:14:16,083 There we go. 263 00:14:18,584 --> 00:14:19,999 There we go. 264 00:14:20,083 --> 00:14:22,083 All right. 265 00:14:22,292 --> 00:14:25,167 So just as an example of what you can do with this script, 266 00:14:25,167 --> 00:14:29,334 so I have this script here called invoke meme cat 64. 267 00:14:29,626 --> 00:14:32,292 All I did was just hard core the meme cat's binary 268 00:14:32,292 --> 00:14:38,167 into the reflective PEInjection script just so it's a little easier to use. 269 00:14:38,209 --> 00:14:42,999 So what I'm going to do here is you can supply computer name. 270 00:14:43,999 --> 00:14:48,083 And the computer name right here is DC1 which is my domain controller. 271 00:14:48,125 --> 00:14:51,292 Computer name is actually an array, though, so you can supply hundreds 272 00:14:51,292 --> 00:14:53,999 or thousands of computers to run this script against, 273 00:14:53,999 --> 00:14:56,792 and PowerShell will do it all for you automatically 274 00:14:56,792 --> 00:14:59,999 to the concurrency, blast this script off. 275 00:14:59,999 --> 00:15:02,083 So let's go ahead and run this. 276 00:15:02,501 --> 00:15:04,709 Hopefully it works because this is live. 277 00:15:07,125 --> 00:15:08,626 All right. 278 00:15:08,792 --> 00:15:10,334 And the output gets strung back. 279 00:15:10,334 --> 00:15:24,167 So what just happened (Applause) JOE BIALEK: All right. 280 00:15:24,167 --> 00:15:27,626 So it looks like the domain admin is running with the password 123. 281 00:15:27,834 --> 00:15:29,083 That's not very good. 282 00:15:29,999 --> 00:15:33,292 So anyway, what this allows you to do is we just ran meme cats 283 00:15:33,292 --> 00:15:35,876 on a remote system without ever touching disc 284 00:15:35,876 --> 00:15:39,125 on that remote system, without ever triggering any application 285 00:15:39,125 --> 00:15:42,999 whitelisting products, without triggering antivirus. 286 00:15:43,501 --> 00:15:45,250 As far as the domain controller is concerned, 287 00:15:45,250 --> 00:15:48,584 all that happened was someone made a remote PowerShell connection 288 00:15:48,584 --> 00:15:52,709 to the server and ran a script that we now have no record of. 289 00:15:52,751 --> 00:15:54,334 That's pretty awesome, I think. 290 00:15:55,375 --> 00:15:59,584 So this next script, this is called invoke ninja copy, and this 291 00:15:59,584 --> 00:16:01,584 is online, too. 292 00:16:02,083 --> 00:16:05,542 So a little while ago, I saw a blog post which someone who wrote 293 00:16:05,542 --> 00:16:07,584 a tool called SAMX. 294 00:16:07,999 --> 00:16:10,918 Basically, their observation was, by default, 295 00:16:10,918 --> 00:16:14,999 not even administrator can make can access certain files 296 00:16:14,999 --> 00:16:18,417 on a Windows system like the registry hive or 297 00:16:18,417 --> 00:16:24,959 the NTDS active directory database because LSASS has a lock on the file. 298 00:16:24,959 --> 00:16:28,667 So LSASS is the only process that is allowed to have the file open. 299 00:16:28,999 --> 00:16:30,999 However, if you know how to parse NTFS, 300 00:16:30,999 --> 00:16:34,584 an administrator can get a read handle to the C volume 301 00:16:34,584 --> 00:16:38,083 and then just read the NTFS structures on the C volume 302 00:16:38,083 --> 00:16:41,292 or D volume and scan to the exact position where 303 00:16:41,292 --> 00:16:44,167 the bytes that make up that file are located 304 00:16:44,167 --> 00:16:46,417 and read them off. 305 00:16:46,667 --> 00:16:48,918 So I thought that was pretty awesome. 306 00:16:49,083 --> 00:16:51,751 And I kind of wanted to write that in PowerShell. 307 00:16:51,751 --> 00:16:54,250 But then I realized that someone had already written 308 00:16:54,250 --> 00:16:58,999 an open source NTFS parser, NC++, and put it on code plex. 309 00:16:59,125 --> 00:17:02,542 So I figured maybe I should just use that and reflectively load it 310 00:17:02,542 --> 00:17:05,999 and save my time parsing NTFS on my own. 311 00:17:06,083 --> 00:17:07,250 And that's really the beauty of this script 312 00:17:07,250 --> 00:17:10,334 is that you can just take these tools that other people have written and then just 313 00:17:10,334 --> 00:17:13,999 turn them into PowerShell scripts that are super sneaky all of a sudden. 314 00:17:14,334 --> 00:17:17,083 And so that's what we're going to do here. 315 00:17:17,083 --> 00:17:20,501 So I'm actually I'll going to the domain controller really quick. 316 00:17:20,501 --> 00:17:21,501 All right. 317 00:17:21,501 --> 00:17:22,501 Gray backgrounds. 318 00:17:22,501 --> 00:17:24,083 We're on the domain controller. 319 00:17:24,083 --> 00:17:25,876 And here is the NTDS.DIT file. 320 00:17:25,876 --> 00:17:27,417 And I'm going to try to open it. 321 00:17:28,999 --> 00:17:31,417 Let's try to open it with Notepad, and we're going 322 00:17:31,417 --> 00:17:34,250 to get this error message saying the process cannot access 323 00:17:34,250 --> 00:17:37,999 the file because it is being used by another process. 324 00:17:37,999 --> 00:17:40,959 So even though I'm domain admin, I can't get this file. 325 00:17:40,959 --> 00:17:41,959 Bummer. 326 00:17:41,959 --> 00:17:42,999 I really wanted it. 327 00:17:44,709 --> 00:17:45,876 Okay. 328 00:17:45,876 --> 00:17:47,626 So let's go back to the demo client. 329 00:17:47,918 --> 00:17:51,501 And we're just going to go ahead and remote PowerShell 330 00:17:51,501 --> 00:17:55,334 into the domain controller, and I have here the file path 331 00:17:55,334 --> 00:17:59,167 to the NTDS file, and I'm going to copy it to the desktop 332 00:17:59,167 --> 00:18:01,334 of my attack box. 333 00:18:03,709 --> 00:18:06,792 And we'll go ahead and run this guy. 334 00:18:09,083 --> 00:18:13,999 You can see from the output here, it's just going to copy 5 megabytes 335 00:18:13,999 --> 00:18:18,834 at a time of this file directly from the desktop, and if I go ahead 336 00:18:18,834 --> 00:18:21,542 and open my desktop, we now have a copy 337 00:18:21,542 --> 00:18:25,626 of the NTDS active directory database file. 338 00:18:25,626 --> 00:18:32,999 And once again (Applause) JOE BIALEK: So once again, 339 00:18:32,999 --> 00:18:38,999 no suspicious processes were run. 340 00:18:38,999 --> 00:18:42,209 The only thing that ever touched disc well, nothing touched disc. 341 00:18:42,250 --> 00:18:44,334 This was all done in memory. 342 00:18:44,334 --> 00:18:46,999 And we stringed the file back over the wire. 343 00:18:46,999 --> 00:18:48,459 So that's pretty awesome. 344 00:18:48,459 --> 00:18:49,334 There's very little evidence left behind that 345 00:18:49,334 --> 00:18:51,918 an attacker ever did something here. 346 00:18:54,626 --> 00:18:58,417 And just for reference, it took me maybe a couple hours 347 00:18:58,417 --> 00:19:01,999 to turn the NTFS parser into a DLL that I could use 348 00:19:01,999 --> 00:19:05,918 with my script and, you know, good to go. 349 00:19:05,918 --> 00:19:08,375 So it's really, really fast to turn things into PowerShell, 350 00:19:08,375 --> 00:19:11,834 turn arbitrary programs into PowerShell scripts that are really 351 00:19:11,834 --> 00:19:13,542 hard to catch. 352 00:19:18,709 --> 00:19:19,999 Okay. 353 00:19:19,999 --> 00:19:23,292 So the obligatory detection and prevention slide. 354 00:19:23,999 --> 00:19:29,751 So there's not a whole lot to say here. 355 00:19:30,083 --> 00:19:32,083 PowerShell remoting requires administrator access, 356 00:19:32,083 --> 00:19:34,501 and it requires open ports. 357 00:19:34,626 --> 00:19:36,083 So if you don't want someone to do this, 358 00:19:36,083 --> 00:19:39,999 then don't let them have admin access on really sensitive servers of yours 359 00:19:39,999 --> 00:19:42,167 and don't let them have network connectivity 360 00:19:42,167 --> 00:19:45,083 to really sensitive servers of yours. 361 00:19:45,083 --> 00:19:47,667 Standard stuff like firewalls, limiting powerful accounts, right, 362 00:19:47,667 --> 00:19:49,999 like lock down your accounts. 363 00:19:49,999 --> 00:19:51,918 Make sure that I can't just remote PowerShell into every server 364 00:19:51,918 --> 00:19:53,584 from any server. 365 00:19:53,626 --> 00:19:55,959 And it helps defend against this. 366 00:19:55,999 --> 00:19:57,999 Of course, nobody does that. 367 00:19:57,999 --> 00:20:01,834 But or maybe some people do that. 368 00:20:01,834 --> 00:20:06,250 PowerShell also has PowerShell DT has pipeline logging which might help 369 00:20:06,250 --> 00:20:08,083 detect this. 370 00:20:08,083 --> 00:20:09,918 But it would be really easy for an attacker to turn it off or clear 371 00:20:09,918 --> 00:20:11,876 the logs if they wanted to. 372 00:20:12,375 --> 00:20:16,000 And there's also going to be a lot of noise if you actually use PowerShell. 373 00:20:16,501 --> 00:20:19,999 Constrained run spaces can help limit the power of PowerShell. 374 00:20:19,999 --> 00:20:21,042 So you can say, even though someone's allowed 375 00:20:21,042 --> 00:20:24,876 to remote PowerShell into the server, there's only specific commands they're 376 00:20:24,876 --> 00:20:26,501 allowed to run. 377 00:20:26,501 --> 00:20:28,999 So I don't have full access to the Win32 API. 378 00:20:28,999 --> 00:20:30,292 I only have access to these 50 command lits that are 379 00:20:30,292 --> 00:20:31,999 deemed to be safe. 380 00:20:32,999 --> 00:20:36,042 And another one is machine wide profile 381 00:20:36,042 --> 00:20:39,417 to log actions to transcript. 382 00:20:39,501 --> 00:20:42,999 Once again, super easy for an attacker to turn this off. 383 00:20:42,999 --> 00:20:44,959 But if an attacker doesn't know that you're doing this, 384 00:20:44,959 --> 00:20:48,417 then you might be able to record what they're doing. 385 00:20:50,999 --> 00:20:54,209 So closing thoughts, this is not a vulnerability. 386 00:20:54,501 --> 00:20:56,042 All of this is by design. 387 00:20:56,334 --> 00:20:58,459 PowerShell is a very powerful language. 388 00:20:58,459 --> 00:21:00,626 It has full access to the Win32 API. 389 00:21:00,626 --> 00:21:02,999 It has full access to the .Net libraries. 390 00:21:02,999 --> 00:21:05,918 So yes, it is able to do this. 391 00:21:05,959 --> 00:21:09,083 And pretty much any programming language can do this if it has access 392 00:21:09,083 --> 00:21:11,083 to the Win32 API. 393 00:21:11,167 --> 00:21:13,417 And if a programming language has remoting functionality, 394 00:21:13,417 --> 00:21:15,501 then you can use the remoting functionality 395 00:21:15,501 --> 00:21:18,292 of other programming languages as well. 396 00:21:18,999 --> 00:21:21,834 I think PowerShell is a great way to manage Windows systems, 397 00:21:21,834 --> 00:21:24,999 so I hope this talk doesn't scare you away from PowerShell all together, 398 00:21:24,999 --> 00:21:29,167 but I hope that it does encourage you to treat PowerShell sensitively. 399 00:21:29,167 --> 00:21:31,876 Make sure you configure it correctly. 400 00:21:31,999 --> 00:21:36,876 Don't expose PowerShell to all the servers in your environment. 401 00:21:37,501 --> 00:21:39,292 And hopefully, it also gives you awesome ideas 402 00:21:39,292 --> 00:21:40,667 on how to attack Windows networks 403 00:21:40,667 --> 00:21:42,999 because that's kind of why I'm here. 404 00:21:44,792 --> 00:21:48,083 Got some references to helpful documentation. 405 00:21:48,083 --> 00:21:49,999 Microsoft documents a lot about how PE loading 406 00:21:49,999 --> 00:21:52,209 and DLL loading works. 407 00:21:52,417 --> 00:21:55,125 Links to some other reflective loaders like metasploit has a reflective loader, 408 00:21:55,125 --> 00:21:56,751 for example. 409 00:21:56,959 --> 00:21:59,918 That's how it does migration and whatnot. 410 00:21:59,918 --> 00:22:02,667 And then some really good PowerShell related blogs. 411 00:22:02,667 --> 00:22:04,876 Exploit Monday especially is super good. 412 00:22:04,876 --> 00:22:05,999 Matt Graber has really great documentation on how 413 00:22:05,999 --> 00:22:08,751 to do awesome stuff in PowerShell. 414 00:22:09,999 --> 00:22:14,999 And just links, once again, to my blog, my Twitter and GitHub. 415 00:22:15,292 --> 00:22:17,083 And that's all I've got for you.