1 00:00:00,240 --> 00:00:02,250 - Weaponizing Windows shellcodes, 2 00:00:02,250 --> 00:00:04,950 it's modern 32-bit shellcode. 3 00:00:04,950 --> 00:00:06,690 We have a lot of content to cover, 4 00:00:06,690 --> 00:00:09,750 so we are going to try to go a little bit more quickly 5 00:00:09,750 --> 00:00:11,013 than we would prefer. 6 00:00:11,880 --> 00:00:13,410 My co-speaker is Tarek. 7 00:00:13,410 --> 00:00:15,900 He is a former graduate assistant of mine, 8 00:00:15,900 --> 00:00:19,560 and he is currently an offensive security engineer 9 00:00:19,560 --> 00:00:23,523 at 23andme and he enjoys shellcoding. 10 00:00:25,350 --> 00:00:26,850 My name is Dr. Bramwell Brizendine. 11 00:00:26,850 --> 00:00:29,713 I am the former director of the VERONA Lab, 12 00:00:29,713 --> 00:00:33,420 and that deals with Exploitation Research. 13 00:00:33,420 --> 00:00:35,970 I'm also the creator of the JOP ROCKET, 14 00:00:35,970 --> 00:00:38,670 which deals with jump-oriented programming. 15 00:00:38,670 --> 00:00:40,470 And I am a current professor 16 00:00:40,470 --> 00:00:44,910 at the University of Alabama in Huntsville, 17 00:00:44,910 --> 00:00:47,553 and I have a PhD in Cyber Operations. 18 00:00:48,660 --> 00:00:51,120 So our talk really concerns Windows Shellcode, 19 00:00:51,120 --> 00:00:52,800 and typically the traditional way 20 00:00:52,800 --> 00:00:55,569 in which we invoke malicious functionality and shellcode 21 00:00:55,569 --> 00:00:58,050 is with what we call Windows APIs. 22 00:00:58,050 --> 00:01:01,702 And it's a very familiar process, we do some PEB walking 23 00:01:01,702 --> 00:01:04,653 and then we traverse the PE file format. 24 00:01:06,270 --> 00:01:09,098 Typically our shellcode will be utilized for exploitation 25 00:01:09,098 --> 00:01:11,583 as well as for malware. 26 00:01:12,900 --> 00:01:15,990 Our research deals with utilizing 27 00:01:15,990 --> 00:01:17,997 Windows syscalls and shellcode. 28 00:01:17,997 --> 00:01:19,890 And that's something that's very, very different 29 00:01:19,890 --> 00:01:23,910 from Linux syscalls, if you are at all familiar with that. 30 00:01:23,910 --> 00:01:27,390 So we're looking specifically at 32-bit shellcode 31 00:01:27,390 --> 00:01:29,580 running on WoW64. 32 00:01:29,580 --> 00:01:32,670 So WoW64 is a mechanism by which we can do 33 00:01:32,670 --> 00:01:37,410 32-bit applications on a 64-bit architecture. 34 00:01:37,410 --> 00:01:42,410 And our goal is to try to achieve 100% functionality 35 00:01:45,480 --> 00:01:48,248 through pure syscalls and it's something that has 36 00:01:48,248 --> 00:01:52,743 only very rarely been done in shellcode. 37 00:01:53,850 --> 00:01:58,320 A quick history on syscall usage in shellcode. 38 00:01:58,320 --> 00:02:00,510 So Eggunters are very well known. 39 00:02:00,510 --> 00:02:01,980 they've been around 15, 20 years, 40 00:02:01,980 --> 00:02:05,880 and traditionally we use an Egghunter to check 41 00:02:05,880 --> 00:02:07,470 and see if memory is valid, 42 00:02:07,470 --> 00:02:11,610 and then try to locate a tag such as STARFALL or WOOTWOOT. 43 00:02:11,610 --> 00:02:15,060 And typically that usage is just one syscall. 44 00:02:15,060 --> 00:02:16,950 Now the single exception to that, 45 00:02:16,950 --> 00:02:18,888 and we looked long and hard to try to find 46 00:02:18,888 --> 00:02:21,180 something that was more complex, 47 00:02:21,180 --> 00:02:25,950 was a syscall shellcode from 2005. 48 00:02:25,950 --> 00:02:29,640 And that utilized four syscalls as a mechanism 49 00:02:29,640 --> 00:02:31,950 to establish persistence. 50 00:02:31,950 --> 00:02:34,664 And it did that by using a hard-coded value 51 00:02:34,664 --> 00:02:37,923 for the syscall pushed into EAX. 52 00:02:39,060 --> 00:02:41,460 Now a problem with syscalls is a problem of portability. 53 00:02:41,460 --> 00:02:44,043 So syscalls traditionally, 54 00:02:45,000 --> 00:02:47,340 in a Windows environment at least, 55 00:02:47,340 --> 00:02:48,510 there's a great deal of variance. 56 00:02:48,510 --> 00:02:50,250 So Windows 10, for instance, 57 00:02:50,250 --> 00:02:53,310 there's more than 13 different OS builds of releases. 58 00:02:53,310 --> 00:02:56,520 And for each of these there are different syscall values 59 00:02:56,520 --> 00:02:58,080 for the same syscall. 60 00:02:58,080 --> 00:03:00,840 And that can make it extremely difficult to 61 00:03:00,840 --> 00:03:02,372 use a particular syscall, 62 00:03:02,372 --> 00:03:05,310 simply because we don't know the correct value. 63 00:03:05,310 --> 00:03:06,540 So it's not always reliable. 64 00:03:06,540 --> 00:03:08,220 And that's why people typically 65 00:03:08,220 --> 00:03:09,963 have not used that in shellcode. 66 00:03:13,465 --> 00:03:18,360 So a little quick history of Syscalls in the Modern Era. 67 00:03:18,360 --> 00:03:22,020 So there was a report by Hod Gavriel in 2018 68 00:03:22,020 --> 00:03:24,137 about a very sharp uptick 69 00:03:24,137 --> 00:03:27,690 in direct syscall usage and malware. 70 00:03:27,690 --> 00:03:30,326 And that included even dual loading of NTDLL, 71 00:03:30,326 --> 00:03:33,180 and also additionally used something 72 00:03:33,180 --> 00:03:37,500 that was kind of like a variation on Hell's Gate. 73 00:03:37,500 --> 00:03:38,880 It would look for the mov opcode, 74 00:03:38,880 --> 00:03:40,800 and then parse the syscall value. 75 00:03:40,800 --> 00:03:44,940 And so that then led directly to several syscall tools. 76 00:03:44,940 --> 00:03:48,000 The first being Dumpert which was a PoC tool 77 00:03:48,000 --> 00:03:50,760 that used precomputed syscall tables 78 00:03:50,760 --> 00:03:55,620 to determine the correct syscall values for the OS build. 79 00:03:55,620 --> 00:03:59,970 That was followed up very quickly by SysWhispers, 80 00:03:59,970 --> 00:04:02,640 and that generates a 64-bit header 81 00:04:02,640 --> 00:04:06,300 and assembler files that could be used to work 82 00:04:06,300 --> 00:04:10,920 in a Visual Studio project. 83 00:04:10,920 --> 00:04:13,590 So that's very well known and use as a 64-bit PEB 84 00:04:13,590 --> 00:04:15,393 to determine the OS build. 85 00:04:17,250 --> 00:04:19,050 Hell's Gate came about later on, 86 00:04:19,050 --> 00:04:22,713 and that was a way to dynamically determine the OS build, 87 00:04:24,287 --> 00:04:27,570 as opposed to using precomputed syscall values 88 00:04:27,570 --> 00:04:29,970 from existing syscall tables. 89 00:04:29,970 --> 00:04:31,740 It worked well for a period of time, 90 00:04:31,740 --> 00:04:33,856 but the problem is EDR is able to detect that 91 00:04:33,856 --> 00:04:36,910 and to overwrite searching critical parts 92 00:04:39,458 --> 00:04:41,190 of the syscall functions. 93 00:04:41,190 --> 00:04:43,950 Halo's gate is in refinement and response to that, 94 00:04:43,950 --> 00:04:47,389 that allows us to extrapolate and to figure out 95 00:04:47,389 --> 00:04:49,920 what a modified syscall is, 96 00:04:49,920 --> 00:04:52,710 by looking at the proceeding or the followings syscall, 97 00:04:52,710 --> 00:04:54,420 and adding a subtracting one. 98 00:04:54,420 --> 00:04:56,655 And that uses a technique developed by 99 00:04:56,655 --> 00:04:59,280 a guy called ElephantSe4l. 100 00:04:59,280 --> 00:05:00,720 He figured out the syscalls, 101 00:05:00,720 --> 00:05:02,558 if you sort by function addresses, 102 00:05:02,558 --> 00:05:06,930 then you can deduce the system or the syscall ID 103 00:05:06,930 --> 00:05:08,520 by incrementing by one. 104 00:05:08,520 --> 00:05:11,880 So he developed his tool FreshyCalls to implement that. 105 00:05:11,880 --> 00:05:14,287 About a month later, we had SysWhispers2, 106 00:05:14,287 --> 00:05:18,138 that integrated a similar technique. 107 00:05:18,138 --> 00:05:22,221 And so that is extremely well known, very famous tool. 108 00:05:22,221 --> 00:05:25,020 SysWhispers3 is a recent variation 109 00:05:25,020 --> 00:05:26,970 that has some additional functionality. 110 00:05:27,930 --> 00:05:32,100 So one of the kind of secret sauces of sorts for these 111 00:05:32,100 --> 00:05:34,770 is this idea that these syscalls 112 00:05:34,770 --> 00:05:37,173 are gonna be incrementing by one. 113 00:05:38,852 --> 00:05:40,830 So if that works then great. 114 00:05:40,830 --> 00:05:45,210 But the problem is that underlying assumption is now wrong. 115 00:05:45,210 --> 00:05:48,778 Because Microsoft has introduced mitigation. 116 00:05:48,778 --> 00:05:52,020 And I found this myself by creating some syscall tables 117 00:05:52,020 --> 00:05:55,890 for recent OS builds of Windows 10 and Windows 11. 118 00:05:55,890 --> 00:05:58,620 And what they've done is we can look at Windows 7. 119 00:05:58,620 --> 00:05:59,703 So Windows 7, 120 00:06:01,380 --> 00:06:05,880 3, 4, 5, 6, clearly incrementing by one. 121 00:06:05,880 --> 00:06:08,983 But we look at Windows 10 and we have 4, 5, 6, 7, 122 00:06:08,983 --> 00:06:12,521 but oh, look, low and behold somebody has inserted 123 00:06:12,521 --> 00:06:15,030 some other bites in front of that. 124 00:06:15,030 --> 00:06:19,350 So it's no longer incrementing by one, which is tragic. 125 00:06:19,350 --> 00:06:21,612 And it repeats itself dozens of times 126 00:06:21,612 --> 00:06:25,650 throughout modern OS builds. 127 00:06:25,650 --> 00:06:26,580 So what does it mean? 128 00:06:26,580 --> 00:06:28,620 Well, it means we gotta get a little bit more creative. 129 00:06:28,620 --> 00:06:31,441 So what you could do is you could dual load NTDLL. 130 00:06:31,441 --> 00:06:35,040 Then you could do a modified Hell's Gate on that. 131 00:06:35,040 --> 00:06:38,040 The problem though is that some EDR can detect 132 00:06:38,040 --> 00:06:39,483 Hell's Gate being loaded. 133 00:06:40,433 --> 00:06:43,330 But fundamentally it's important to bear in mind here 134 00:06:44,463 --> 00:06:46,953 that with modern OS builds, 135 00:06:48,660 --> 00:06:50,670 syscall values no longer increment by one. 136 00:06:50,670 --> 00:06:54,360 So any of the tools that utilize the sorting 137 00:06:54,360 --> 00:06:58,020 by address technique are no longer a 100% reliable. 138 00:06:58,020 --> 00:07:01,200 They may work 60, 70% of the time, 139 00:07:01,200 --> 00:07:02,910 but then they will fail at other times 140 00:07:02,910 --> 00:07:04,710 because some of them are just simply 141 00:07:04,710 --> 00:07:06,450 not incrementing by one. 142 00:07:06,450 --> 00:07:08,480 Also that affects FreshyCalls, 143 00:07:08,480 --> 00:07:12,813 it affects SysWhispers2, and Halo's Gate among others. 144 00:07:14,430 --> 00:07:17,280 So let's talk about Reverse Engineering Windows Syscalls. 145 00:07:17,280 --> 00:07:20,520 So we can look at Windows 7, WoW64, 146 00:07:20,520 --> 00:07:22,800 and this is inside NTDLL, 147 00:07:22,800 --> 00:07:25,740 so NTDLL function for NTAllocateVirtualMemory, 148 00:07:25,740 --> 00:07:28,463 and it's loading 15 into EAX. 149 00:07:28,463 --> 00:07:30,280 So 15 into EAX is the syscall value 150 00:07:31,422 --> 00:07:34,980 for NTAllocateVirtualMemory for one particular OS build. 151 00:07:34,980 --> 00:07:39,330 We then make a deference call to fs:c0. 152 00:07:39,330 --> 00:07:44,070 Fs:c0 points to a far jump, 153 00:07:44,070 --> 00:07:45,960 and that far jump has what's called 154 00:07:45,960 --> 00:07:47,670 a 33 selector in front of it. 155 00:07:47,670 --> 00:07:49,474 So that means it's going to transition 156 00:07:49,474 --> 00:07:52,950 from 32-bit mode to 64-bit mode. 157 00:07:52,950 --> 00:07:56,460 So we actually have 64-bit code, 158 00:07:56,460 --> 00:07:59,109 inserted into a 32-bit process. 159 00:07:59,109 --> 00:08:01,038 And this is something we couldn't directly follow 160 00:08:01,038 --> 00:08:03,390 in a debugger if you wanted to. 161 00:08:03,390 --> 00:08:06,363 So the fs:c0 is important to remember here. 162 00:08:07,320 --> 00:08:09,360 Windows 10 we've switched things up a bit. 163 00:08:09,360 --> 00:08:14,360 So now we have a NTDLL offset that will then point 164 00:08:16,110 --> 00:08:17,523 to our syscall, 165 00:08:20,280 --> 00:08:22,410 a function called WoW64 transition. 166 00:08:22,410 --> 00:08:24,340 And then that will lead us then to 167 00:08:25,502 --> 00:08:29,640 the far jump to transition from 32-bit to 64-bit mode. 168 00:08:29,640 --> 00:08:32,910 And then eventually to the real underlying syscall. 169 00:08:32,910 --> 00:08:35,497 The good news though, is we don't need to use that. 170 00:08:35,497 --> 00:08:39,496 We could instead just use the fs:c0 method, 171 00:08:39,496 --> 00:08:41,250 that still works, and in fact, 172 00:08:41,250 --> 00:08:45,093 it's actually easier to use in this version. 173 00:08:46,260 --> 00:08:50,520 Windows 11, well, at least from the user mode perspective, 174 00:08:50,520 --> 00:08:53,070 it's virtually identical, some different function names 175 00:08:53,070 --> 00:08:54,930 but it's pretty much doing the same thing. 176 00:08:54,930 --> 00:08:56,010 And guess what? 177 00:08:56,010 --> 00:09:00,300 The Windows 7 backwards compatibility method of invoking it 178 00:09:00,300 --> 00:09:03,870 with the fs:c0, that also works too. 179 00:09:03,870 --> 00:09:05,250 So let's figure out how we can build 180 00:09:05,250 --> 00:09:07,440 some syscall shellcode. 181 00:09:07,440 --> 00:09:10,440 So we need to determine first the OS release, 182 00:09:10,440 --> 00:09:13,170 because if we don't have the correct OS build, 183 00:09:13,170 --> 00:09:15,450 then everything else that we do will fail. 184 00:09:15,450 --> 00:09:19,200 'Cause we'll be calling the incorrect functions or syscalls. 185 00:09:19,200 --> 00:09:21,114 So we can figure this out through introspection. 186 00:09:21,114 --> 00:09:24,300 And we can do that by a process called walking the PEB, 187 00:09:24,300 --> 00:09:26,940 we get that from fs:[0x30]. 188 00:09:26,940 --> 00:09:28,843 And then in this case, we're going to go to 189 00:09:28,843 --> 00:09:33,843 the OS build number, which will be at offset 0xAC. 190 00:09:34,200 --> 00:09:36,468 And then that can allow us to determine conclusively 191 00:09:36,468 --> 00:09:39,123 the OS build will give us a hex value. 192 00:09:40,500 --> 00:09:41,880 We don't actually need to determine 193 00:09:41,880 --> 00:09:43,770 the OS major version or minor version, 194 00:09:43,770 --> 00:09:48,450 we can if we like, but if we're using Windows 10 and 11, 195 00:09:48,450 --> 00:09:52,500 or Windows 7, separately, then it's just not necessary, 196 00:09:52,500 --> 00:09:54,810 'cause the OS build itself is unique. 197 00:09:54,810 --> 00:09:56,640 However, if we are combining them, 198 00:09:56,640 --> 00:09:58,530 meaning we're using Windows 10 and 11, 199 00:09:58,530 --> 00:09:59,970 as well as Windows 7, 200 00:09:59,970 --> 00:10:01,980 then we do absolutely need to determine 201 00:10:01,980 --> 00:10:03,513 the OS major version. 202 00:10:04,560 --> 00:10:05,785 So turning it into shellcode, 203 00:10:05,785 --> 00:10:09,030 we just simply get the offset of the PEB. 204 00:10:09,030 --> 00:10:11,790 So fs:[0x30], the process environment block. 205 00:10:11,790 --> 00:10:14,040 And then we can do the offset AC, 206 00:10:14,040 --> 00:10:16,350 which will then enable us to get the less build, 207 00:10:16,350 --> 00:10:18,180 which in this case is 21h2. 208 00:10:18,180 --> 00:10:21,153 It's the latest version of Windows 10. 209 00:10:22,440 --> 00:10:24,180 So when we actually call the syscall, 210 00:10:24,180 --> 00:10:26,430 we need to create a small little function, 211 00:10:26,430 --> 00:10:29,550 and this is a function that'll be part of the assembly. 212 00:10:29,550 --> 00:10:31,774 So Windows 7 method is a little bit more convoluted. 213 00:10:31,774 --> 00:10:35,310 The Windows 10 and 11 is more succinct,. 214 00:10:35,310 --> 00:10:37,290 If we're combining both of them, 215 00:10:37,290 --> 00:10:39,420 then we need to programmatically determine 216 00:10:39,420 --> 00:10:40,890 which we are going to use. 217 00:10:40,890 --> 00:10:42,727 And we can do that fairly simply, 218 00:10:42,727 --> 00:10:45,123 by looking at the OS major version. 219 00:10:46,230 --> 00:10:48,480 So we're what we are doing here is we're using 220 00:10:48,480 --> 00:10:50,280 what we call just call Syscall Initializer. 221 00:10:50,280 --> 00:10:53,370 So we will capture the OS build, 222 00:10:53,370 --> 00:10:55,830 and then we will determine, 223 00:10:55,830 --> 00:10:57,210 we'll create some space on the stack 224 00:10:57,210 --> 00:10:58,575 for what we call a syscall array. 225 00:10:58,575 --> 00:11:02,250 And then we check to see which version it is. 226 00:11:02,250 --> 00:11:05,463 We then load the appropriate values for that 227 00:11:05,463 --> 00:11:07,890 into our syscall array. 228 00:11:07,890 --> 00:11:10,020 And then we can then deference the elements 229 00:11:10,020 --> 00:11:12,120 from the syscall array through EDI. 230 00:11:12,120 --> 00:11:16,860 So EDI will be a persistent pointer to the syscall array. 231 00:11:16,860 --> 00:11:19,170 And if we're combining 10 and 11, 232 00:11:19,170 --> 00:11:21,450 then we also will check the OS major version. 233 00:11:21,450 --> 00:11:23,630 And that will be located at edi-4. 234 00:11:25,620 --> 00:11:27,780 And so once we complete that process, 235 00:11:27,780 --> 00:11:29,490 then we will have the syscall array. 236 00:11:29,490 --> 00:11:32,634 And then that will allow us to deference it from EDI. 237 00:11:32,634 --> 00:11:35,190 So edi+0x4, +0x8, +0xc, 238 00:11:35,190 --> 00:11:38,790 can enable us to access those values at runtime 239 00:11:38,790 --> 00:11:41,193 that will correspond to the correct OS build. 240 00:11:42,180 --> 00:11:44,670 So there's an example of how we can do that. 241 00:11:44,670 --> 00:11:48,216 So no hard coded values, just simply dereferencing EDI. 242 00:11:48,216 --> 00:11:52,320 And so by doing this, then we will have the correct values, 243 00:11:52,320 --> 00:11:54,543 whether it's Windows 7, 10, or 11. 244 00:11:55,830 --> 00:11:57,240 The pointer to the syscall array 245 00:11:57,240 --> 00:11:58,560 is something we need to maintain. 246 00:11:58,560 --> 00:12:01,380 So we'll push EDI onto the stack 247 00:12:01,380 --> 00:12:03,180 before pushing our parameters. 248 00:12:03,180 --> 00:12:06,090 We'll do our syscall, and then we'll do a stack cleanup, 249 00:12:06,090 --> 00:12:08,367 and then we'll pop the pointer back into EDI. 250 00:12:08,367 --> 00:12:10,740 And so therefore we can maintain the integrity 251 00:12:10,740 --> 00:12:14,520 of the syscall array pointer. 252 00:12:14,520 --> 00:12:15,720 So one tool that I made, 253 00:12:15,720 --> 00:12:17,580 and this is kind of a bonus thing, 254 00:12:17,580 --> 00:12:18,540 'cause we didn't advertise it, 255 00:12:18,540 --> 00:12:20,310 Is it's called ShellWasp, 256 00:12:20,310 --> 00:12:24,240 and it's available on our GitHub, Bw3ll ShellWasp. 257 00:12:24,240 --> 00:12:26,168 And it'll also be in the slides you can download. 258 00:12:26,168 --> 00:12:29,160 And so this automates building a template 259 00:12:29,160 --> 00:12:30,541 for syscall shellcode, 260 00:12:30,541 --> 00:12:35,370 and it supports nearly all user-mode syscalls, 261 00:12:35,370 --> 00:12:37,530 addresses the portability problem, 262 00:12:37,530 --> 00:12:39,156 builds out the syscall array, 263 00:12:39,156 --> 00:12:44,156 and it's very simple to utilize and select syscalls, 264 00:12:45,150 --> 00:12:46,890 you can do that through the user interface 265 00:12:46,890 --> 00:12:47,910 through a config file. 266 00:12:47,910 --> 00:12:48,996 You can rearrange it. 267 00:12:48,996 --> 00:12:53,043 You can select the desired OS releases as well. 268 00:12:55,350 --> 00:12:56,940 And then the final results here 269 00:12:56,940 --> 00:13:00,870 is we can see that it does indeed create a template. 270 00:13:00,870 --> 00:13:03,030 So these are initialized as 0s, 271 00:13:03,030 --> 00:13:05,400 and that's kind of your job to go through 272 00:13:05,400 --> 00:13:07,020 and to figure out the values to put on them. 273 00:13:07,020 --> 00:13:08,371 It's something that Tarek will be talking about 274 00:13:08,371 --> 00:13:11,160 very shortly here. 275 00:13:11,160 --> 00:13:14,370 But that also provides the parameter names and types 276 00:13:14,370 --> 00:13:18,240 and it takes care of managing the syscall array 277 00:13:18,240 --> 00:13:20,070 and all of that, so, 278 00:13:20,070 --> 00:13:21,660 if you're doing something very complex, 279 00:13:21,660 --> 00:13:23,670 all of that is taken care of for you. 280 00:13:23,670 --> 00:13:26,130 And without further ado, we will then introduce Tarek 281 00:13:26,130 --> 00:13:28,803 who is going to give us an excellent example. 282 00:13:34,080 --> 00:13:36,000 - Hello everyone. 283 00:13:36,000 --> 00:13:38,820 So here, I'm gonna be talking about 284 00:13:38,820 --> 00:13:42,243 Process Injection Shellcode using system codes. 285 00:13:43,830 --> 00:13:45,870 So here I have a list of all the APIs 286 00:13:45,870 --> 00:13:48,420 I'm going to use here this show code, 287 00:13:48,420 --> 00:13:50,190 and we are going to start with the first one, 288 00:13:50,190 --> 00:13:51,890 which is NtQuerySystemInformation. 289 00:13:54,067 --> 00:13:55,611 So the purpose of this API is to 290 00:13:55,611 --> 00:13:58,770 give all the necessary information 291 00:13:58,770 --> 00:14:01,620 about the running processes in the background. 292 00:14:01,620 --> 00:14:04,710 So the reason we do this is we need to get the process ID, 293 00:14:04,710 --> 00:14:07,350 or the process number of the targeted process 294 00:14:07,350 --> 00:14:10,593 that we are using to inject our shellcode into. 295 00:14:11,610 --> 00:14:15,420 So this API has a system information class, 296 00:14:15,420 --> 00:14:18,450 and it has many other classes, 297 00:14:18,450 --> 00:14:21,060 but the system information class is telling the API 298 00:14:21,060 --> 00:14:24,630 what kind of information you need from the operating system. 299 00:14:24,630 --> 00:14:26,880 So here I'm using system process information 300 00:14:26,880 --> 00:14:30,720 which is equivalent to 0x5, the value in hex. 301 00:14:30,720 --> 00:14:32,400 So this is telling the operating system 302 00:14:32,400 --> 00:14:35,130 we're only interested in information 303 00:14:35,130 --> 00:14:36,813 about running processes. 304 00:14:37,890 --> 00:14:40,608 Once we get that, so we can parse through each process, 305 00:14:40,608 --> 00:14:43,893 and we can get the process name and the process ID. 306 00:14:45,349 --> 00:14:47,940 So this is what the system process information 307 00:14:47,940 --> 00:14:49,860 structure looks like. 308 00:14:49,860 --> 00:14:52,410 The first element is called NextEntryOffset 309 00:14:52,410 --> 00:14:54,723 which is pointing to the next process. 310 00:14:55,718 --> 00:14:56,880 And the other one's called ImageName, 311 00:14:56,880 --> 00:14:59,078 which is the process name. 312 00:14:59,078 --> 00:15:01,230 And that's the one that we are interested in 313 00:15:01,230 --> 00:15:03,270 because we know the process ID is changing, 314 00:15:03,270 --> 00:15:05,370 but the process name, it doesn't change. 315 00:15:05,370 --> 00:15:09,810 So we need to look for the process by looking up its name. 316 00:15:09,810 --> 00:15:11,070 And the last one at the bottom, 317 00:15:11,070 --> 00:15:13,860 it's called UniqueProcessID or the Process ID. 318 00:15:13,860 --> 00:15:17,373 And this is the one that we are doing all of that to get. 319 00:15:19,753 --> 00:15:23,130 Here we have the system process information. 320 00:15:23,130 --> 00:15:26,160 This is just an example, a process called System. 321 00:15:26,160 --> 00:15:27,960 It's a Unicode process name. 322 00:15:27,960 --> 00:15:29,736 So you make sure when you're doing this 323 00:15:29,736 --> 00:15:34,736 a Unicode string has no bytes between each character. 324 00:15:35,148 --> 00:15:38,880 At the top, the next process is at offset 0x0. 325 00:15:38,880 --> 00:15:42,754 This is what we use to go through each process 326 00:15:42,754 --> 00:15:45,450 in the data that we get. 327 00:15:45,450 --> 00:15:47,370 Offset 0x3C has the process name, 328 00:15:47,370 --> 00:15:50,103 and offset 0x44 has the process ID. 329 00:15:51,540 --> 00:15:54,930 So the way this works is we don't know how much data 330 00:15:54,930 --> 00:15:58,020 all the processes running in the background will be. 331 00:15:58,020 --> 00:16:00,630 So we can allocate arbitrary value 332 00:16:00,630 --> 00:16:03,960 using something like NTAllocateVirtualMemory, 333 00:16:03,960 --> 00:16:06,570 and we call the NtQuerySystemInformation 334 00:16:06,570 --> 00:16:11,570 and that might not give us a success value as a return. 335 00:16:12,330 --> 00:16:15,870 So what we do here is we allocate more memory, 336 00:16:15,870 --> 00:16:18,960 which is like, let's say 2000 in hex or something, 337 00:16:18,960 --> 00:16:21,150 and then we call the same API again. 338 00:16:21,150 --> 00:16:23,580 Once we get a successful value back, 339 00:16:23,580 --> 00:16:25,320 that means we have all the data that we want, 340 00:16:25,320 --> 00:16:27,390 that we can parse through each process using 341 00:16:27,390 --> 00:16:30,117 the same thing that I just discussed here. 342 00:16:30,117 --> 00:16:33,273 The process ID, and the name, and all of that. 343 00:16:35,100 --> 00:16:37,950 Once we have the process ID, we can move forward 344 00:16:37,950 --> 00:16:40,624 with the NtOpenProcess, very straightforward. 345 00:16:40,624 --> 00:16:43,074 It takes four arguments. 346 00:16:43,074 --> 00:16:45,715 One of them is called OBJECT_ATTRIBUTES. 347 00:16:45,715 --> 00:16:48,143 The OBJECT_ATTRIBUTES here is another structure 348 00:16:48,143 --> 00:16:51,363 that we're not kind of like we're not using most of it. 349 00:16:51,363 --> 00:16:53,850 We just need the length. 350 00:16:53,850 --> 00:16:56,280 Everything else should be 0s. 351 00:16:56,280 --> 00:16:59,970 Like the directory object name, all of that could be used 352 00:16:59,970 --> 00:17:02,640 for other stuff, but not for this case. 353 00:17:02,640 --> 00:17:06,930 And we also have the client ID, or PC client ID here. 354 00:17:06,930 --> 00:17:09,150 This is the process ID we just obtained. 355 00:17:09,150 --> 00:17:11,490 So we will use that. 356 00:17:11,490 --> 00:17:13,140 We also have the DesiredAccess. 357 00:17:13,140 --> 00:17:17,310 which is all accessed 1 and 5fs in hex. 358 00:17:17,310 --> 00:17:19,830 And the variable at the top of the process handle, 359 00:17:19,830 --> 00:17:22,353 this is to receive the handle for the process. 360 00:17:23,880 --> 00:17:25,797 Once we are done and we opened the process, 361 00:17:25,797 --> 00:17:26,940 and we have a handle, 362 00:17:26,940 --> 00:17:29,490 we can keep going with the NtAllocateVirtualMemory. 363 00:17:30,810 --> 00:17:33,210 This API is like the Godfather of the virtual 364 00:17:33,210 --> 00:17:35,160 Alloc and all its variants. 365 00:17:35,160 --> 00:17:37,010 It's very similar to virtual outlook. 366 00:17:38,040 --> 00:17:40,230 The only difference here is the base address, 367 00:17:40,230 --> 00:17:42,630 like the second argument, it's in and out, 368 00:17:42,630 --> 00:17:44,735 this variable will be used to get back 369 00:17:44,735 --> 00:17:47,070 the allocated address in memory. 370 00:17:47,070 --> 00:17:50,373 And we will use that later to write our shellcode. 371 00:17:51,450 --> 00:17:53,820 The process handled, the one that we just got before, 372 00:17:53,820 --> 00:17:56,670 and the 0 bits is just 0s. 373 00:17:56,670 --> 00:17:58,950 It's kind of optional here, so. 374 00:17:58,950 --> 00:18:02,546 We have the region size which is the size of the shellcode. 375 00:18:02,546 --> 00:18:05,610 We have the allocation type, and the protect, 376 00:18:05,610 --> 00:18:07,223 very similar to virtual outlook. 377 00:18:07,223 --> 00:18:09,633 Just is just an example of what it looks like. 378 00:18:10,770 --> 00:18:13,950 The first one is the protect the PAGE_EXECUTE_READWRITE, 379 00:18:13,950 --> 00:18:15,662 what kind of permissions you need to get, 380 00:18:15,662 --> 00:18:20,220 and the type of the reserve or commit, or both. 381 00:18:20,220 --> 00:18:21,570 And the rest of the things here, 382 00:18:21,570 --> 00:18:25,530 that the size of the shellcode and what I just discussed. 383 00:18:25,530 --> 00:18:28,330 And finally we invoke the system code to make it happen. 384 00:18:29,820 --> 00:18:33,090 Next, we allocated some memory in the remote process, 385 00:18:33,090 --> 00:18:35,250 now we need to write our data there. 386 00:18:35,250 --> 00:18:37,350 We need to write the shellcode, which is, 387 00:18:37,350 --> 00:18:42,350 I'm using the Meterpreter shellcode here in this case. 388 00:18:42,480 --> 00:18:44,850 So here, very straightforward, same thing. 389 00:18:44,850 --> 00:18:46,770 We have the process handle, 390 00:18:46,770 --> 00:18:48,990 we have the base address, 391 00:18:48,990 --> 00:18:51,090 which is the pointer of the allocated space 392 00:18:51,090 --> 00:18:52,800 in the remote process. 393 00:18:52,800 --> 00:18:55,293 We have the buffer, which is a pointer to the shellcode 394 00:18:55,293 --> 00:18:57,420 that we have in our C program, 395 00:18:57,420 --> 00:18:59,550 like the Meterpreter shellcode, 396 00:18:59,550 --> 00:19:01,230 and the size of the shellcode, 397 00:19:01,230 --> 00:19:03,750 it's a number of bytes to write. 398 00:19:03,750 --> 00:19:05,550 And the last one is optional. 399 00:19:05,550 --> 00:19:08,040 This is the number of bites you get back, 400 00:19:08,040 --> 00:19:10,350 how many rights you were able to successfully write 401 00:19:10,350 --> 00:19:12,213 to the remote process. 402 00:19:14,108 --> 00:19:17,460 Once we're done, this is like the shellcode, same thing. 403 00:19:17,460 --> 00:19:19,590 We invoke the system code to make it happen 404 00:19:19,590 --> 00:19:23,463 and write the Meterpreter shellcode to the remote process. 405 00:19:26,310 --> 00:19:29,250 And here, once we have the shellcode written 406 00:19:29,250 --> 00:19:30,270 to the remote process, 407 00:19:30,270 --> 00:19:35,270 we spawn a thread from the process using NtCreateThread 408 00:19:35,810 --> 00:19:37,563 of the extended version of it. 409 00:19:38,550 --> 00:19:42,217 In this API, it takes 11 arguments, 410 00:19:42,217 --> 00:19:45,240 but actually the last six arguments are 0s. 411 00:19:45,240 --> 00:19:48,510 They're optional and we don't need them in this case. 412 00:19:48,510 --> 00:19:51,090 We're only interested in the first five. 413 00:19:51,090 --> 00:19:52,833 The PHANDLE of the thread, 414 00:19:52,833 --> 00:19:57,660 this is like a handle, like a variable to receive a handle 415 00:19:57,660 --> 00:20:00,570 for a thread which is not really going to be used. 416 00:20:00,570 --> 00:20:02,880 The second one is the desired access, same thing, 417 00:20:02,880 --> 00:20:07,170 we're using all access, which is 1 and 5fs in hex. 418 00:20:07,170 --> 00:20:08,970 And we have the object attributes, 419 00:20:08,970 --> 00:20:11,460 same thing as the NtOpenProcess. 420 00:20:11,460 --> 00:20:13,290 We're only using the length, 421 00:20:13,290 --> 00:20:16,620 and we're not using anything else in this structure. 422 00:20:16,620 --> 00:20:18,810 And then we have the process handle 423 00:20:18,810 --> 00:20:21,360 that we keep using all the time. 424 00:20:21,360 --> 00:20:23,700 And then we have the lpStartAddress 425 00:20:23,700 --> 00:20:25,890 which is a Meterpreter shellcode address 426 00:20:25,890 --> 00:20:29,673 that we we're able to write to the remote process. 427 00:20:32,130 --> 00:20:34,553 This is what it looks like in shellcoding. 428 00:20:34,553 --> 00:20:36,930 This is an example. 429 00:20:36,930 --> 00:20:39,780 So the shellcode pointer I'm using a tool 430 00:20:39,780 --> 00:20:43,800 called CrypTool.exe, you can use anything else you want. 431 00:20:43,800 --> 00:20:45,510 Just make sure when you're doing this, 432 00:20:45,510 --> 00:20:49,140 if you compiled your file using 32-bit, 433 00:20:49,140 --> 00:20:52,170 and you want to inject something into another process, 434 00:20:52,170 --> 00:20:55,290 make sure the process has 32-bit architecture. 435 00:20:55,290 --> 00:20:57,423 Otherwise you'll get access violation. 436 00:21:00,630 --> 00:21:02,520 So now we have two separate shellcodes. 437 00:21:02,520 --> 00:21:04,140 One is for syscall shellcode 438 00:21:04,140 --> 00:21:05,790 and the other one is the Meterpreter shellcode 439 00:21:05,790 --> 00:21:08,310 that is hiding in your C program. 440 00:21:08,310 --> 00:21:11,700 But now we need to combine those shellcodes together 441 00:21:11,700 --> 00:21:14,700 so we can use them if you're leveraging a vulnerability 442 00:21:14,700 --> 00:21:15,960 or something. 443 00:21:15,960 --> 00:21:19,590 And if you want to execute them at once. 444 00:21:19,590 --> 00:21:21,930 So here at the top, I have the green part at the top. 445 00:21:21,930 --> 00:21:24,810 This is just used to get the beginning 446 00:21:24,810 --> 00:21:26,720 of the Meterpreter shellcode. 447 00:21:26,720 --> 00:21:28,680 I'm using the cold pop technique here 448 00:21:28,680 --> 00:21:30,900 to just to get the address of the Meterpreter shellcode. 449 00:21:30,900 --> 00:21:33,060 And then I jump down, all the way down, 450 00:21:33,060 --> 00:21:34,818 to the green part at the bottom, 451 00:21:34,818 --> 00:21:38,313 which is the start of the syscall shellcode. 452 00:21:40,620 --> 00:21:43,170 So now once you have this large shellcode, 453 00:21:43,170 --> 00:21:45,960 a combination between syscall shellcode and Meterpreter 454 00:21:45,960 --> 00:21:48,120 is sandwiched between them. 455 00:21:48,120 --> 00:21:50,310 We need to execute it somehow. 456 00:21:50,310 --> 00:21:52,290 So you can execute this in memory. 457 00:21:52,290 --> 00:21:53,460 If you have a vulnerability, 458 00:21:53,460 --> 00:21:55,080 or you can just have a C program 459 00:21:55,080 --> 00:21:56,649 if you're running a malware. 460 00:21:56,649 --> 00:22:00,031 And you can use a shellcode tester, if you want. 461 00:22:00,031 --> 00:22:04,860 But if you do that, you'll still use some kernel32 APIs. 462 00:22:06,150 --> 00:22:08,370 So I wrote this execution skeleton to do that. 463 00:22:08,370 --> 00:22:11,910 So you can avoid kernel32 APIs. 464 00:22:11,910 --> 00:22:13,770 It's equivalent to the one that you can use 465 00:22:13,770 --> 00:22:16,080 VirtualAlloc and then Memcpy. 466 00:22:16,080 --> 00:22:18,900 This one's still using the same syscalls. 467 00:22:18,900 --> 00:22:21,969 You're still using NtAllocate and NtWrite, 468 00:22:21,969 --> 00:22:24,600 to write the shellcode to memory. 469 00:22:24,600 --> 00:22:28,650 And then the last line at the bottom is jump to this place 470 00:22:28,650 --> 00:22:30,123 and start executing. 471 00:22:38,370 --> 00:22:41,473 So it's demo time. So this is the tool I just started, 472 00:22:41,473 --> 00:22:43,800 now I'm gonna start the debugger. 473 00:22:43,800 --> 00:22:46,893 Just to show you the stuff, how it works in the debugger. 474 00:22:48,300 --> 00:22:49,400 - [Man] We can't see it. 475 00:22:49,400 --> 00:22:54,033 - Oh. 476 00:23:12,730 --> 00:23:13,813 Mine doesn't. 477 00:23:51,792 --> 00:23:54,450 - Guys you got like one minute. 478 00:23:54,450 --> 00:23:56,038 - Okay, it's ready. 479 00:23:56,038 --> 00:23:56,871 - Okay. 480 00:24:05,070 --> 00:24:07,600 - So here I'm using the CrypTool.exe, 481 00:24:07,600 --> 00:24:09,780 the one that I just mentioned. 482 00:24:09,780 --> 00:24:11,493 And this is a debugger x32dbg. 483 00:24:12,870 --> 00:24:15,390 So the first break point is 484 00:24:15,390 --> 00:24:19,470 where we get the actual CrypTool.exe, 485 00:24:19,470 --> 00:24:22,353 like we found the process here at the right side, 486 00:24:23,700 --> 00:24:26,640 and then now we can parse through the process 487 00:24:26,640 --> 00:24:28,203 and we get the process ID. 488 00:24:32,100 --> 00:24:33,990 This is just to verify the process ID 489 00:24:33,990 --> 00:24:37,293 that I got is the same using task task list. 490 00:24:38,610 --> 00:24:41,283 Convert the hex to a decimal so we can get, 491 00:24:42,360 --> 00:24:44,283 just to verify it's the same process. 492 00:24:47,940 --> 00:24:50,902 The second break point will be when we allocate the memory 493 00:24:50,902 --> 00:24:52,983 into the remote process. 494 00:24:53,910 --> 00:24:57,693 Here we have the allocated space at 18E0000. 495 00:24:58,740 --> 00:25:01,323 We open process hacker to make sure it's the same. 496 00:25:05,490 --> 00:25:08,403 It's there. We have the read right, execute permissions. 497 00:25:18,450 --> 00:25:19,283 I'm sorry. 498 00:25:22,530 --> 00:25:25,324 And the last part here just showing the Windows defender 499 00:25:25,324 --> 00:25:29,040 is up and running and we run it and we get 500 00:25:29,040 --> 00:25:30,930 Meterpreter shell back. 501 00:25:30,930 --> 00:25:32,970 And as you can see here, Windows defender 502 00:25:32,970 --> 00:25:34,260 was just taking a nap. 503 00:25:34,260 --> 00:25:35,560 It was not doing anything. 504 00:25:36,859 --> 00:25:39,859 (audience clapping)