1 00:00:00,360 --> 00:00:02,280 - So welcome to the 12 o'clock talk 2 00:00:02,280 --> 00:00:04,740 on "Avoiding Memory Scanners." 3 00:00:04,740 --> 00:00:06,360 Let me introduce Kyle. 4 00:00:06,360 --> 00:00:08,220 Kyle, it's all yours. 5 00:00:08,220 --> 00:00:09,053 - Thank you. 6 00:00:10,110 --> 00:00:10,950 All right. 7 00:00:10,950 --> 00:00:12,810 So first, we'll do a quick introduction. 8 00:00:12,810 --> 00:00:14,460 Like he said, my name is Kyle Avery. 9 00:00:14,460 --> 00:00:17,820 I'm currently the Offensive Security Lead at H-E-B. 10 00:00:17,820 --> 00:00:21,360 Before that, I was a red teamer and Penetration Tester 11 00:00:21,360 --> 00:00:23,940 at Black Hills Information Security. 12 00:00:23,940 --> 00:00:26,670 Most of my personal research and projects 13 00:00:26,670 --> 00:00:28,620 focuses on post exploitation. 14 00:00:28,620 --> 00:00:30,270 So this talks all about Windows, 15 00:00:30,270 --> 00:00:32,280 but I've also been branching 16 00:00:32,280 --> 00:00:35,340 into Mac as well more recently. 17 00:00:35,340 --> 00:00:37,920 At the bottom there, that's my Twitter, kyleavery_ 18 00:00:37,920 --> 00:00:39,330 and my GitHub, kyleavery. 19 00:00:39,330 --> 00:00:42,033 So feel free to give those a follow. 20 00:00:43,350 --> 00:00:46,980 So if you follow any of the InfoSec Twitter, 21 00:00:46,980 --> 00:00:50,610 and especially the offensive security red teamer Twitter, 22 00:00:50,610 --> 00:00:53,790 you've probably seen tweets like these from Dom Chell 23 00:00:53,790 --> 00:00:57,030 and Chatan talking about their commercial command 24 00:00:57,030 --> 00:00:58,050 and control frameworks. 25 00:00:58,050 --> 00:01:00,090 And so, they've recently, in the last year or so, 26 00:01:00,090 --> 00:01:01,980 started selling these tools 27 00:01:01,980 --> 00:01:03,840 that have lots of awesome features, 28 00:01:03,840 --> 00:01:05,940 but one of them that really stood out to me 29 00:01:05,940 --> 00:01:10,940 was this ability to bypass tools like PE-sieve and Moneta. 30 00:01:11,287 --> 00:01:12,810 And so, these tweets would come out 31 00:01:12,810 --> 00:01:14,917 and the comments are filled with people asking, 32 00:01:14,917 --> 00:01:16,077 "How do you do this?" 33 00:01:17,452 --> 00:01:20,520 And even the developers of the scanners asking for, 34 00:01:20,520 --> 00:01:22,620 maybe, some insight into what they're doing 35 00:01:22,620 --> 00:01:25,189 so they can start trying to detect it. 36 00:01:25,189 --> 00:01:26,670 And so, that really piqued my interest 37 00:01:26,670 --> 00:01:28,380 and I started doing some research 38 00:01:28,380 --> 00:01:30,210 to figure out what they might be doing. 39 00:01:30,210 --> 00:01:32,670 And that's what led me to this talk. 40 00:01:32,670 --> 00:01:35,280 And so, one thing, 41 00:01:35,280 --> 00:01:37,770 when I was at Black Hills and I started looking into this, 42 00:01:37,770 --> 00:01:40,140 we really heavily used Cobalt Strike, 43 00:01:40,140 --> 00:01:42,480 and I'm sure that that's true for a lot of other red teams 44 00:01:42,480 --> 00:01:45,450 and just even penetration testers, maybe. 45 00:01:45,450 --> 00:01:47,640 And so, all of the work that I've done 46 00:01:47,640 --> 00:01:50,160 is made to work with Cobalt Strike. 47 00:01:50,160 --> 00:01:51,570 It's not specific to it. 48 00:01:51,570 --> 00:01:54,660 It doesn't necessarily use any unique features. 49 00:01:54,660 --> 00:01:57,300 And so, you could take any of the techniques 50 00:01:57,300 --> 00:01:58,290 that we're gonna talk about 51 00:01:58,290 --> 00:02:00,240 and the code that we're gonna talk about 52 00:02:00,240 --> 00:02:03,180 and port it to something else pretty easily, 53 00:02:03,180 --> 00:02:04,950 but it's all gonna be about Cobalt Strike, 54 00:02:04,950 --> 00:02:06,450 specifically because that's what I 55 00:02:06,450 --> 00:02:08,400 and a lot of my peers are using. 56 00:02:08,400 --> 00:02:10,770 And as an added benefit, 57 00:02:10,770 --> 00:02:11,970 Cobalt Strike is going to be one 58 00:02:11,970 --> 00:02:15,120 of the most heavily targeted tools by scanners. 59 00:02:15,120 --> 00:02:18,390 So between red teamers and actual threat actors, 60 00:02:18,390 --> 00:02:22,950 lots of malicious groups or simulating malicious groups 61 00:02:22,950 --> 00:02:24,120 are using Cobalt Strike. 62 00:02:24,120 --> 00:02:25,830 And so, memory scanners and YARN rules 63 00:02:25,830 --> 00:02:28,260 are heavily targeting Cobalt Strike, 64 00:02:28,260 --> 00:02:30,030 maybe more than some other tools. 65 00:02:30,030 --> 00:02:32,470 And so, any bypasses that we have might be 66 00:02:33,630 --> 00:02:35,670 more effectively demonstrated if they're used 67 00:02:35,670 --> 00:02:37,830 with Cobalt Strike than with something else. 68 00:02:37,830 --> 00:02:40,020 So the link there, that's for a tool that I wrote 69 00:02:40,020 --> 00:02:40,853 called AceLdr. 70 00:02:40,853 --> 00:02:42,780 It's going to be the combination 71 00:02:42,780 --> 00:02:43,950 of everything I'm talking about, 72 00:02:43,950 --> 00:02:46,770 and I'm gonna make it open source right after this, today. 73 00:02:46,770 --> 00:02:50,384 So as I'm walking off stage, I'll change that on my phone. 74 00:02:50,384 --> 00:02:52,290 (crowd applauds) 75 00:02:52,290 --> 00:02:53,123 Thanks. 76 00:02:54,000 --> 00:02:55,680 So just a quick agenda. 77 00:02:55,680 --> 00:02:58,020 First, we're gonna go over how do memory scanners work? 78 00:02:58,020 --> 00:03:00,390 And specifically, we're gonna talk about three 79 00:03:00,390 --> 00:03:02,398 really notable capabilities that they all share 80 00:03:02,398 --> 00:03:04,500 or have some overlap of. 81 00:03:04,500 --> 00:03:05,941 Then, we're gonna talk about how to bypass 82 00:03:05,941 --> 00:03:07,980 each of these techniques, 83 00:03:07,980 --> 00:03:10,410 how to bypass specific scanners. 84 00:03:10,410 --> 00:03:11,400 And then finally at the end, 85 00:03:11,400 --> 00:03:13,470 I'm gonna demonstrate my tool 86 00:03:13,470 --> 00:03:16,470 and then I'll open source it for y'all to go look at. 87 00:03:16,470 --> 00:03:17,303 Okay. 88 00:03:17,303 --> 00:03:19,110 The first technique that I wanna talk about 89 00:03:19,110 --> 00:03:20,370 is pattern matching. 90 00:03:20,370 --> 00:03:22,980 So pattern matching or signature scanning 91 00:03:22,980 --> 00:03:26,160 is probably the most well recognized feature 92 00:03:26,160 --> 00:03:27,540 of something like antivirus 93 00:03:27,540 --> 00:03:29,790 or even a lot of open source tools 94 00:03:29,790 --> 00:03:32,730 because it's probably the easiest thing to implement 95 00:03:32,730 --> 00:03:36,690 and to get just easy ways to detect malware. 96 00:03:36,690 --> 00:03:39,000 Once you have a piece of it and you can signature it, 97 00:03:39,000 --> 00:03:41,370 it's pretty easy to reuse a rule like this. 98 00:03:41,370 --> 00:03:44,760 And so, the most popular open source or public tool 99 00:03:44,760 --> 00:03:47,640 for this is probably YARA from VirusTotal. 100 00:03:47,640 --> 00:03:49,290 YARA, you can see on the side there, 101 00:03:49,290 --> 00:03:51,390 I have an example of one of their rules. 102 00:03:51,390 --> 00:03:53,760 They have abstracted a lot of the complexity 103 00:03:53,760 --> 00:03:54,780 of scanning things, 104 00:03:54,780 --> 00:03:57,090 whether it's memory or processes on disk, 105 00:03:57,090 --> 00:04:00,510 and given you this format that you can write rules in, 106 00:04:00,510 --> 00:04:03,090 where you define bytes and strings, 107 00:04:03,090 --> 00:04:05,490 and you use this to build 108 00:04:05,490 --> 00:04:07,260 these conditional logic statements 109 00:04:07,260 --> 00:04:11,340 to have some pretty dynamic signature-based rules. 110 00:04:11,340 --> 00:04:13,710 Then there are all these tools that implement YARA, 111 00:04:13,710 --> 00:04:15,870 whether they're just using it 112 00:04:15,870 --> 00:04:20,640 or they're maybe implementing some subset of its features. 113 00:04:20,640 --> 00:04:21,960 And so, one that I like to call out 114 00:04:21,960 --> 00:04:23,430 in particular is BeaconEye. 115 00:04:23,430 --> 00:04:25,920 This was one of the first Cobalt Strike tools 116 00:04:25,920 --> 00:04:28,980 that I saw or tools that came out to detect Cobalt Strike, 117 00:04:28,980 --> 00:04:30,750 specifically, that I saw. 118 00:04:30,750 --> 00:04:32,550 So BeaconEye from _EthicalChaos_. 119 00:04:32,550 --> 00:04:34,920 This actually uses YARA itself 120 00:04:34,920 --> 00:04:37,950 and it uses YARA to detect the Cobalt Strike configuration. 121 00:04:37,950 --> 00:04:39,690 So when Cobalt Strike initializes, 122 00:04:39,690 --> 00:04:40,950 it allocates some memory 123 00:04:40,950 --> 00:04:42,300 and it writes its configuration there 124 00:04:42,300 --> 00:04:43,950 so it can keep reading it back 125 00:04:43,950 --> 00:04:45,841 or maybe modify it dynamically 126 00:04:45,841 --> 00:04:49,770 to check what it should be doing and how it should work. 127 00:04:49,770 --> 00:04:51,780 There are also commercial security products 128 00:04:51,780 --> 00:04:52,980 that are using YARA. 129 00:04:52,980 --> 00:04:56,070 So I did a quick Google search for YARA ADR 130 00:04:56,070 --> 00:04:58,110 and I found Carbon Black and CrowdStrike 131 00:04:58,110 --> 00:05:00,150 specifically mentioning on their public websites 132 00:05:00,150 --> 00:05:01,410 that they use YARA. 133 00:05:01,410 --> 00:05:03,720 There are undoubtedly other vendors that do this 134 00:05:03,720 --> 00:05:05,670 and I just didn't find in my quick Google search, 135 00:05:05,670 --> 00:05:07,860 or maybe don't mention it publicly. 136 00:05:07,860 --> 00:05:10,200 And then there might be vendors that have something similar 137 00:05:10,200 --> 00:05:11,220 and it's not YARA, 138 00:05:11,220 --> 00:05:12,990 but they're doing essentially the same thing, right? 139 00:05:12,990 --> 00:05:15,000 And so, all of this is pattern matching. 140 00:05:15,000 --> 00:05:17,670 And pattern matching is traditionally easy to bypass 141 00:05:17,670 --> 00:05:20,670 because you just modify the part of your malware 142 00:05:20,670 --> 00:05:22,080 that's been signatured. 143 00:05:22,080 --> 00:05:23,640 But if you're already using it, 144 00:05:23,640 --> 00:05:25,647 and then someone writes a signature after the fact, 145 00:05:25,647 --> 00:05:28,233 you'd have to pull that back and then redeploy it. 146 00:05:30,930 --> 00:05:34,721 And so, a bypass or pattern matching could be temporary, 147 00:05:34,721 --> 00:05:37,410 where you just change the malware in a way 148 00:05:37,410 --> 00:05:38,670 that it doesn't get caught, 149 00:05:38,670 --> 00:05:41,160 but we'll talk about what a more permanent bypass 150 00:05:41,160 --> 00:05:43,110 might look like as well. 151 00:05:43,110 --> 00:05:45,119 So I've got just a quick demo here. 152 00:05:45,119 --> 00:05:46,710 If I can get this to... 153 00:05:46,710 --> 00:05:47,543 Okay. 154 00:05:47,543 --> 00:05:49,830 So on this box, I've got two command prompts running. 155 00:05:49,830 --> 00:05:52,080 One of them has Cobalt Strike injected into it, 156 00:05:52,080 --> 00:05:53,400 the other one does not. 157 00:05:53,400 --> 00:05:54,720 I've got this rules.txt, 158 00:05:54,720 --> 00:05:56,730 which is just a collection of YARA rules. 159 00:05:56,730 --> 00:05:58,320 And you can see, I scan these, 160 00:05:58,320 --> 00:06:00,120 the first one, it gets no results 161 00:06:00,120 --> 00:06:01,110 'cause Cobalt Strike isn't there. 162 00:06:01,110 --> 00:06:02,790 But the second one I scan, 163 00:06:02,790 --> 00:06:05,190 I get all kinds of hits for different components 164 00:06:05,190 --> 00:06:08,280 of Cobalt Strike that are in the memory of that process. 165 00:06:08,280 --> 00:06:11,163 So just a quick demo of what that looks like. 166 00:06:16,320 --> 00:06:17,153 All right. 167 00:06:17,153 --> 00:06:17,986 So the next thing I wanna talk about 168 00:06:17,986 --> 00:06:20,520 is so-called memory IOCs, 169 00:06:20,520 --> 00:06:21,570 and you might be thinking, "Okay, 170 00:06:21,570 --> 00:06:22,860 well these are all IOCs. 171 00:06:22,860 --> 00:06:23,940 That's the whole point." 172 00:06:23,940 --> 00:06:25,320 And I kind of agree, 173 00:06:25,320 --> 00:06:28,320 but this is just the most common term that I hear used. 174 00:06:28,320 --> 00:06:30,210 You could think of this as memory attributes, 175 00:06:30,210 --> 00:06:32,670 or I guess, memory indicators. 176 00:06:32,670 --> 00:06:33,503 I don't know. 177 00:06:33,503 --> 00:06:36,900 But basically, what all of these tools are looking for 178 00:06:36,900 --> 00:06:39,960 are suspicious attributes or suspicious settings 179 00:06:39,960 --> 00:06:40,920 on the memory itself. 180 00:06:40,920 --> 00:06:43,500 So memory can be executable, 181 00:06:43,500 --> 00:06:45,990 readable, writeable, or some combination of those. 182 00:06:45,990 --> 00:06:48,610 And so, looking for memory that's maybe executable 183 00:06:50,280 --> 00:06:52,200 might be an indicator that there's malware there. 184 00:06:52,200 --> 00:06:53,760 It's a very vague indicator, 185 00:06:53,760 --> 00:06:56,160 but malware probably needs to execute. 186 00:06:56,160 --> 00:06:58,230 So that's one thing that you could look for. 187 00:06:58,230 --> 00:07:00,900 You combine that with looking at the difference 188 00:07:00,900 --> 00:07:03,420 between image commit and private commit memory. 189 00:07:03,420 --> 00:07:07,110 So image commit memory is when you load a DLL 190 00:07:07,110 --> 00:07:10,350 or an EXE from disk that's going to be image commit, 191 00:07:10,350 --> 00:07:12,990 whereas private commit is where the program 192 00:07:12,990 --> 00:07:15,030 is dynamically allocated memory. 193 00:07:15,030 --> 00:07:16,950 And so, if you have private commit memory 194 00:07:16,950 --> 00:07:20,130 that was dynamically allocated and it's executable, 195 00:07:20,130 --> 00:07:22,740 that's a little bit suspicious, right? 196 00:07:22,740 --> 00:07:24,180 Typically on Windows, 197 00:07:24,180 --> 00:07:26,250 programs, when they want to execute new code, 198 00:07:26,250 --> 00:07:28,470 they load some DLL from disk. 199 00:07:28,470 --> 00:07:29,610 There are exceptions to this. 200 00:07:29,610 --> 00:07:33,300 We look at, such as the .NET run time or even web browsers, 201 00:07:33,300 --> 00:07:34,474 which are using JIT. 202 00:07:34,474 --> 00:07:35,790 So that might have 203 00:07:35,790 --> 00:07:37,980 some private commit memory that's executable. 204 00:07:37,980 --> 00:07:40,170 So it's not a foolproof thing to look for, 205 00:07:40,170 --> 00:07:42,330 but again, they're just tools that help the analysts 206 00:07:42,330 --> 00:07:45,030 figure out whether or not there might be malware somewhere 207 00:07:45,030 --> 00:07:47,070 so they can keep investigating. 208 00:07:47,070 --> 00:07:49,590 So we've got tools like Moneta from Forrest Orr, 209 00:07:49,590 --> 00:07:51,330 which does look for the private commit memory 210 00:07:51,330 --> 00:07:52,945 and executable permissions. 211 00:07:52,945 --> 00:07:57,720 It also looks for PEB image bases or even threads 212 00:07:57,720 --> 00:08:00,030 where the start address points to private memory. 213 00:08:00,030 --> 00:08:02,550 So even if it's not executable when it scans, 214 00:08:02,550 --> 00:08:03,810 if it looks at that start address 215 00:08:03,810 --> 00:08:06,750 and it's private commit memory, that's a bit odd. 216 00:08:06,750 --> 00:08:09,930 We have PE-sieve, which can actually scan non-executable 217 00:08:09,930 --> 00:08:11,520 or even inaccessible memory, 218 00:08:11,520 --> 00:08:14,089 like no access protected pages' memory 219 00:08:14,089 --> 00:08:15,690 to look for patterns. 220 00:08:15,690 --> 00:08:17,610 So PE-sieve doesn't use YARA, 221 00:08:17,610 --> 00:08:19,680 but it is a pattern matching, 222 00:08:19,680 --> 00:08:20,610 or at least part of it is, 223 00:08:20,610 --> 00:08:23,730 where it can look for bytes that look like shellcode 224 00:08:23,730 --> 00:08:26,070 or look like, maybe, especially Cobalt Strike 225 00:08:26,070 --> 00:08:27,480 or even XOR. 226 00:08:27,480 --> 00:08:29,910 We'll talk about a little bit later, XOR shellcode. 227 00:08:29,910 --> 00:08:32,280 It also checks the return addresses though 228 00:08:32,280 --> 00:08:35,700 of all threads and looks for private commit memory addresses 229 00:08:35,700 --> 00:08:37,410 in the return address. 230 00:08:37,410 --> 00:08:39,300 The last one I like to mention is malfind, 231 00:08:39,300 --> 00:08:41,970 which is from the Volatility forensics framework 232 00:08:41,970 --> 00:08:43,380 Malfind is similar to these, 233 00:08:43,380 --> 00:08:46,170 but it's specifically looking for private commit, 234 00:08:46,170 --> 00:08:47,880 read, write, and execute memory, 235 00:08:47,880 --> 00:08:49,920 which is a little bit more limiting than something 236 00:08:49,920 --> 00:08:53,310 like Moneta and you can't run it live on the system. 237 00:08:53,310 --> 00:08:56,853 And so, you have to take a forensic memory dump first. 238 00:08:57,990 --> 00:09:00,750 So taking a quick look at what the Moneta output 239 00:09:00,750 --> 00:09:01,770 might look like. 240 00:09:01,770 --> 00:09:02,970 You can see there at the top, 241 00:09:02,970 --> 00:09:07,560 I've allocated three sections of memory 242 00:09:07,560 --> 00:09:09,780 and they're all 444 kilobytes. 243 00:09:09,780 --> 00:09:11,640 One of them is page read/write, 244 00:09:11,640 --> 00:09:12,570 one of them is read/execute, 245 00:09:12,570 --> 00:09:14,400 the other ones execute/read/write. 246 00:09:14,400 --> 00:09:16,740 And so, you can then see that screenshot I've got 247 00:09:16,740 --> 00:09:19,560 of Process Hacker looking at the three regions of memory. 248 00:09:19,560 --> 00:09:22,200 And when I run Moneta there at the bottom, 249 00:09:22,200 --> 00:09:24,930 it creates two alerts for the RWX 250 00:09:24,930 --> 00:09:26,790 and then for the RX memory. 251 00:09:26,790 --> 00:09:28,050 And so, again, it's looking, 252 00:09:28,050 --> 00:09:30,420 it sees private commit memory because it was allocated 253 00:09:30,420 --> 00:09:32,940 and it says, "This is executable and private commit. 254 00:09:32,940 --> 00:09:34,920 You should take a look." 255 00:09:34,920 --> 00:09:36,270 So we've got a quick demo here. 256 00:09:36,270 --> 00:09:38,760 I've got my same two command exit processes. 257 00:09:38,760 --> 00:09:41,070 One has Cobalt Strike, the other one does not. 258 00:09:41,070 --> 00:09:43,380 I'm going to run Moneta on the one that doesn't 259 00:09:43,380 --> 00:09:44,790 and you can see scan completed. 260 00:09:44,790 --> 00:09:46,140 There's no alerts. 261 00:09:46,140 --> 00:09:47,820 I run it on the one that does though 262 00:09:47,820 --> 00:09:51,310 and then I get the two alerts for the thread 263 00:09:52,330 --> 00:09:53,850 with the non image memory 264 00:09:53,850 --> 00:09:57,060 and then one for just private executable memory. 265 00:09:57,060 --> 00:09:59,370 I can do the same thing with PE-sieve. 266 00:09:59,370 --> 00:10:03,360 So I'll scan the benign command.exe first 267 00:10:03,360 --> 00:10:06,483 and then I will scan the one with Cobalt Strike, 268 00:10:07,950 --> 00:10:10,800 and you can see now it finds two results 269 00:10:10,800 --> 00:10:12,413 and it says it found implanted shellcode. 270 00:10:12,413 --> 00:10:14,580 And so, these tools are looking for different things, 271 00:10:14,580 --> 00:10:16,680 but they're both looking at these memory attributes 272 00:10:16,680 --> 00:10:19,291 to figure out where they should look more closely 273 00:10:19,291 --> 00:10:22,623 for abnormal data in memory, potentially. 274 00:10:23,850 --> 00:10:25,620 The last capability I want to talk about 275 00:10:25,620 --> 00:10:27,690 is this idea of stack tracing. 276 00:10:27,690 --> 00:10:29,190 So the first two tools, 277 00:10:29,190 --> 00:10:31,440 BeaconHunter and Hunt-Sleeping-Beacons 278 00:10:31,440 --> 00:10:32,940 are essentially the same, 279 00:10:32,940 --> 00:10:34,980 at least in the context we're talking about, 280 00:10:34,980 --> 00:10:36,930 where they're looking for any thread 281 00:10:36,930 --> 00:10:39,720 that is sitting at a state of execution delay. 282 00:10:39,720 --> 00:10:42,480 And this will generate a lot of false positives 283 00:10:42,480 --> 00:10:46,860 because lots of things use the Win 32 sleep API call, 284 00:10:46,860 --> 00:10:49,530 but it will also find a stock Cobalt Strike 285 00:10:49,530 --> 00:10:51,630 and a lot of other stock command and control frameworks 286 00:10:51,630 --> 00:10:53,700 because they all work the same way, 287 00:10:53,700 --> 00:10:55,380 where they call out for an action 288 00:10:55,380 --> 00:10:56,430 and then they execute it 289 00:10:56,430 --> 00:10:58,620 and then they sleep for some duration of time. 290 00:10:58,620 --> 00:11:00,450 And so, during that sleep time, 291 00:11:00,450 --> 00:11:03,510 which is the majority of the time the implant is active, 292 00:11:03,510 --> 00:11:06,540 it will get caught by these two tools. 293 00:11:06,540 --> 00:11:09,810 The last one here MalMemDetect is from Waldo-irc, 294 00:11:09,810 --> 00:11:11,593 and this is a really interesting one 295 00:11:11,593 --> 00:11:14,400 where, basically, he has a DLL 296 00:11:14,400 --> 00:11:16,890 that you will load into a process, 297 00:11:16,890 --> 00:11:19,170 hopefully before it's infected with malware 298 00:11:19,170 --> 00:11:21,450 and it will hook certain functions. 299 00:11:21,450 --> 00:11:23,400 So internet connect A and connect W, 300 00:11:23,400 --> 00:11:25,433 NtWaitForSingleObject, and RtlAllocateHeap. 301 00:11:26,700 --> 00:11:28,560 It will hook these and, when they execute, 302 00:11:28,560 --> 00:11:30,450 before it allows that to run, 303 00:11:30,450 --> 00:11:32,820 it will actually check the return address. 304 00:11:32,820 --> 00:11:35,550 Similar to, I mentioned, PE-sieve does, 305 00:11:35,550 --> 00:11:38,220 but this is actually doing it at execution time, 306 00:11:38,220 --> 00:11:40,860 not just when you run the scanner. 307 00:11:40,860 --> 00:11:44,200 And so, if internet connect A is executed 308 00:11:45,111 --> 00:11:46,440 and is being called by shellcode 309 00:11:46,440 --> 00:11:48,150 from some private commit memory, 310 00:11:48,150 --> 00:11:50,913 then MalMemDetect will flag it as suspicious. 311 00:11:52,020 --> 00:11:54,780 So what I've got here is actually the Cobalt strike console 312 00:11:54,780 --> 00:11:57,390 and what I'm gonna do with this is I'm going to inject 313 00:11:57,390 --> 00:12:01,050 the MalMemDetect to DLL into this command prompt 314 00:12:01,050 --> 00:12:02,310 that I highlighted, 315 00:12:02,310 --> 00:12:03,390 and you can see to start, 316 00:12:03,390 --> 00:12:05,040 there's nothing on my desktop. 317 00:12:05,040 --> 00:12:08,550 I'm going to load MalMemDetect into the process. 318 00:12:08,550 --> 00:12:09,510 Once I do that, 319 00:12:09,510 --> 00:12:13,050 I can go ahead and look at the log file that gets created 320 00:12:13,050 --> 00:12:16,230 and this tells me that Mount mem detect loaded successfully. 321 00:12:16,230 --> 00:12:17,310 And then, once this is done, 322 00:12:17,310 --> 00:12:19,500 I can actually inject the process 323 00:12:19,500 --> 00:12:20,880 with a Cobalt Strike beacon. 324 00:12:20,880 --> 00:12:24,510 And so, I'll get my Cobalt Strike agent running in there. 325 00:12:24,510 --> 00:12:26,100 And then I'll look at the desktop again, 326 00:12:26,100 --> 00:12:27,810 and there's this detected log 327 00:12:27,810 --> 00:12:30,030 and you can see it sees all these suspicious malloc 328 00:12:30,030 --> 00:12:31,860 and internet connect calls. 329 00:12:31,860 --> 00:12:33,420 And so, it's definitely seeing Cobalt Strike, 330 00:12:33,420 --> 00:12:35,340 or at least something suspicious, 331 00:12:35,340 --> 00:12:37,590 that the analysts would look at more closely. 332 00:12:38,820 --> 00:12:39,900 All right. 333 00:12:39,900 --> 00:12:42,360 Now that we've talked about these three capabilities, 334 00:12:42,360 --> 00:12:44,970 I want to get into how we might bypass 335 00:12:44,970 --> 00:12:46,570 the memory standards themselves. 336 00:12:48,810 --> 00:12:49,720 So each scanner 337 00:12:50,580 --> 00:12:52,683 we can bypass it and it requires, 338 00:12:53,670 --> 00:12:54,630 at the most basic level, 339 00:12:54,630 --> 00:12:57,180 some combination of encryption and spoofing. 340 00:12:57,180 --> 00:12:58,230 And you'll see what I mean by that. 341 00:12:58,230 --> 00:13:00,540 It's different depending on the context. 342 00:13:00,540 --> 00:13:02,730 But one thing I wanna note before we move on 343 00:13:02,730 --> 00:13:05,550 is that, when I talk about a bypass in this talk, 344 00:13:05,550 --> 00:13:08,490 I'm not looking to generate a bunch of false positives 345 00:13:08,490 --> 00:13:10,020 and confuse an analyst, 346 00:13:10,020 --> 00:13:13,290 I'm not looking to blend in with existing false positives, 347 00:13:13,290 --> 00:13:15,960 I want to run the scanner and have zero results. 348 00:13:15,960 --> 00:13:18,330 I want it to look essentially the same as it did 349 00:13:18,330 --> 00:13:20,370 before I injected Cobalt Strike. 350 00:13:20,370 --> 00:13:23,130 And so, I don't want there to be anything to cause alarm. 351 00:13:23,130 --> 00:13:24,360 The other thing I wanna note 352 00:13:24,360 --> 00:13:26,460 is that when I talk about memory scanners, 353 00:13:26,460 --> 00:13:28,740 I'm not talking about commercial security products. 354 00:13:28,740 --> 00:13:31,740 So I mentioned earlier Carbon Black and CrowdStrike. 355 00:13:31,740 --> 00:13:34,560 These tools maybe have some overlap with memory scanners, 356 00:13:34,560 --> 00:13:36,180 they're looking at some of the same things, 357 00:13:36,180 --> 00:13:38,520 or maybe a lot of the same things, depending on the product, 358 00:13:38,520 --> 00:13:40,890 but they're not looking for all of the same things. 359 00:13:40,890 --> 00:13:43,440 And so, being able to bypass every memory scanner 360 00:13:43,440 --> 00:13:44,880 does not mean that you're gonna bypass 361 00:13:44,880 --> 00:13:47,580 every EDR product or antivirus. 362 00:13:47,580 --> 00:13:49,350 And likewise, being able to bypass EDR 363 00:13:49,350 --> 00:13:51,750 doesn't necessarily require bypassing 364 00:13:51,750 --> 00:13:52,740 all of these memory scanners. 365 00:13:52,740 --> 00:13:55,140 A lot of these are looking for things 366 00:13:55,140 --> 00:13:58,380 that are more intensive or require too much resource 367 00:13:58,380 --> 00:14:01,380 for a live product to run. 368 00:14:01,380 --> 00:14:03,480 And so, I just like to make that note 369 00:14:03,480 --> 00:14:05,640 so that people don't think 370 00:14:05,640 --> 00:14:07,620 that I'm bypassing a memory scanner 371 00:14:07,620 --> 00:14:08,880 because I'm bypassing this product, 372 00:14:08,880 --> 00:14:10,710 or I should be bypassing this product 373 00:14:10,710 --> 00:14:12,693 because I'm bypassing these scanners. 374 00:14:13,620 --> 00:14:16,530 So I mentioned that we're gonna be encrypting data 375 00:14:16,530 --> 00:14:17,610 to make this work. 376 00:14:17,610 --> 00:14:18,840 And so, we gotta talk about 377 00:14:18,840 --> 00:14:21,060 how do we want to encrypt things? 378 00:14:21,060 --> 00:14:24,600 The first thing that came to my mind was single byte XOR. 379 00:14:24,600 --> 00:14:27,090 Single byte XOR has been around for a million years 380 00:14:27,090 --> 00:14:28,920 and it's really simple to implement, 381 00:14:28,920 --> 00:14:31,680 it doesn't cause a huge performance delay, 382 00:14:31,680 --> 00:14:34,650 and it's just relatively easy to use, 383 00:14:34,650 --> 00:14:36,030 it's pretty straightforward. 384 00:14:36,030 --> 00:14:38,370 The problem with single byte XOR is that tools like YARA 385 00:14:38,370 --> 00:14:40,320 and PE-sieve, their pattern matching 386 00:14:40,320 --> 00:14:42,090 can actually detect single byte. 387 00:14:42,090 --> 00:14:46,200 So YARA has a modifier that you can use on byte arrays 388 00:14:46,200 --> 00:14:47,490 where you can tell it to try 389 00:14:47,490 --> 00:14:49,383 every single byte XOR possibility. 390 00:14:50,430 --> 00:14:53,910 PE-sieve uses a technique that looks at the null bytes 391 00:14:53,910 --> 00:14:58,200 encrypted with XOR to actually see or detect 392 00:14:58,200 --> 00:14:59,940 single byte XOR encryption. 393 00:14:59,940 --> 00:15:01,170 And so then, you might be thinking, "Okay, 394 00:15:01,170 --> 00:15:03,150 well, I'll use multi byte XOR encryption, 395 00:15:03,150 --> 00:15:05,220 or I'll use AES or RC4." 396 00:15:05,220 --> 00:15:07,350 But all of these, you'll see in a couple slides, 397 00:15:07,350 --> 00:15:10,282 have problems because they require us to allocate 398 00:15:10,282 --> 00:15:13,770 and then execute code in memory. 399 00:15:13,770 --> 00:15:16,080 And so, anything that we can do 400 00:15:16,080 --> 00:15:18,060 where we don't have to write our own code 401 00:15:18,060 --> 00:15:20,850 is going to be preferable in a couple slides. 402 00:15:20,850 --> 00:15:24,750 So the solution here is this system function 032. 403 00:15:24,750 --> 00:15:28,440 This is something that I first saw in Mimikatz, actually. 404 00:15:28,440 --> 00:15:29,520 So I put that screenshot there. 405 00:15:29,520 --> 00:15:32,160 You can see he's commenting me, he says, "RC4." 406 00:15:32,160 --> 00:15:35,340 And he calls them RTL encrypt data and decrypt data. 407 00:15:35,340 --> 00:15:36,450 But really, what these are, 408 00:15:36,450 --> 00:15:38,700 they're built in operating systems that you can submit 409 00:15:38,700 --> 00:15:42,180 a memory address and a size and an encryption key 410 00:15:42,180 --> 00:15:44,100 and it will go and encrypt it with RC4. 411 00:15:44,100 --> 00:15:45,990 And so, we don't have to write any RC4 code. 412 00:15:45,990 --> 00:15:47,560 We don't have to do anything like that. 413 00:15:47,560 --> 00:15:50,133 It will take care of all of that for us. 414 00:15:51,720 --> 00:15:53,520 So what do we want to encrypt with this? 415 00:15:53,520 --> 00:15:56,220 Well, the first thing is we want to encrypt the heap. 416 00:15:56,220 --> 00:15:58,050 I mentioned earlier that Cobalt Strike, 417 00:15:58,050 --> 00:15:59,550 when it initializes, 418 00:15:59,550 --> 00:16:02,100 it dynamically allocates some memory, 419 00:16:02,100 --> 00:16:04,170 and then it writes its configuration there. 420 00:16:04,170 --> 00:16:05,760 Well, that is all on the heap. 421 00:16:05,760 --> 00:16:08,010 And so, the heap is a data structure, 422 00:16:08,010 --> 00:16:08,843 if you're not familiar, 423 00:16:08,843 --> 00:16:10,200 where things like malloc 424 00:16:10,200 --> 00:16:13,590 and other dynamic memory allocations go. 425 00:16:13,590 --> 00:16:16,260 So the first demo that I saw of this was, again, 426 00:16:16,260 --> 00:16:17,093 from Waldo-irc. 427 00:16:17,093 --> 00:16:18,930 It's called LockedExeDemo. 428 00:16:18,930 --> 00:16:21,210 So this is a proof of concept that will try 429 00:16:21,210 --> 00:16:23,820 and encrypt right before the beacon goes to sleep. 430 00:16:23,820 --> 00:16:26,220 It will try and encrypt all the heap entries in the process 431 00:16:26,220 --> 00:16:27,240 which aren't busy. 432 00:16:27,240 --> 00:16:28,770 So it checks every single heap entry 433 00:16:28,770 --> 00:16:29,670 and says, "Are you busy? 434 00:16:29,670 --> 00:16:30,510 Are you being accessed?" 435 00:16:30,510 --> 00:16:32,670 And if not, it will encrypt it. 436 00:16:32,670 --> 00:16:34,350 I've seen some trouble with this 437 00:16:34,350 --> 00:16:36,150 because, maybe, the beacon is sleeping 438 00:16:36,150 --> 00:16:39,090 and it has encrypted something that was not busy 439 00:16:39,090 --> 00:16:40,380 when it went to sleep, 440 00:16:40,380 --> 00:16:41,970 but then during the sleep time, 441 00:16:41,970 --> 00:16:44,610 the process needs to access that memory and it can't. 442 00:16:44,610 --> 00:16:45,990 And so, there's a little bit of risk here, 443 00:16:45,990 --> 00:16:47,703 but overall, it works pretty well. 444 00:16:48,990 --> 00:16:49,823 Shortly after that, 445 00:16:49,823 --> 00:16:51,420 I came out with a proof of concept 446 00:16:51,420 --> 00:16:53,940 to allocate a secondary heap. 447 00:16:53,940 --> 00:16:57,030 So I create a brand new heap that is different 448 00:16:57,030 --> 00:16:58,860 than the process's original one. 449 00:16:58,860 --> 00:17:01,110 And I tell Cobalt Strike that I want to, 450 00:17:01,110 --> 00:17:02,370 anytime it's going to allocate memory, 451 00:17:02,370 --> 00:17:04,380 I want to use that heap instead. 452 00:17:04,380 --> 00:17:06,600 And that allows me to, essentially, do the same thing 453 00:17:06,600 --> 00:17:08,790 as Waldo, where I'm gonna check if things are busy, 454 00:17:08,790 --> 00:17:11,190 which they really shouldn't be if I'm about to go to sleep, 455 00:17:11,190 --> 00:17:12,624 and then I can encrypt them 456 00:17:12,624 --> 00:17:15,600 and nothing that the host process is doing 457 00:17:15,600 --> 00:17:16,980 should be on there. 458 00:17:16,980 --> 00:17:19,770 And so, I don't have any risk of impacting something 459 00:17:19,770 --> 00:17:23,700 that might need to get accessed while my agent is sleeping. 460 00:17:23,700 --> 00:17:26,370 The last example is actually from the official 461 00:17:26,370 --> 00:17:27,570 Sleep Mask Kit 462 00:17:27,570 --> 00:17:29,220 that is part of Cobalt Strike. 463 00:17:29,220 --> 00:17:32,730 So Sleep Mask Kit is one of the extensions 464 00:17:32,730 --> 00:17:34,800 that you can download if you have a Cobalt Strike license 465 00:17:34,800 --> 00:17:37,560 that allows you to encrypt certain things at sleep, 466 00:17:37,560 --> 00:17:39,300 one of them being the heap. 467 00:17:39,300 --> 00:17:42,810 And so, Cobalt Strike will actually give you just a big list 468 00:17:42,810 --> 00:17:45,150 of, "Here's all the memory addresses of heap entries 469 00:17:45,150 --> 00:17:46,020 that I've allocated. 470 00:17:46,020 --> 00:17:47,190 Please, encrypt them." 471 00:17:47,190 --> 00:17:49,590 And so, this is actually a pretty nice setup 472 00:17:49,590 --> 00:17:52,054 because you're not creating a secondary heap 473 00:17:52,054 --> 00:17:55,620 and you're not worrying about damaging entries 474 00:17:55,620 --> 00:17:57,630 that are allocated by the original process. 475 00:17:57,630 --> 00:17:59,070 You're only going to encrypt things 476 00:17:59,070 --> 00:18:01,860 that Cobalt Strike itself allocated. 477 00:18:01,860 --> 00:18:04,470 And so, this is something that's specific to Cobalt Strike 478 00:18:04,470 --> 00:18:07,020 and requires you to use their Sleep Mask Kit, 479 00:18:07,020 --> 00:18:08,580 which you'll see in a few slides 480 00:18:08,580 --> 00:18:10,953 why I don't necessarily want to do that. 481 00:18:12,510 --> 00:18:13,650 So let's do a quick demo here. 482 00:18:13,650 --> 00:18:16,140 I've loaded my heap encryption that I talked about, 483 00:18:16,140 --> 00:18:18,210 where it allocates the secondary heap. 484 00:18:18,210 --> 00:18:21,270 I've got my beacon here, already running. 485 00:18:21,270 --> 00:18:23,370 I'm going to, you can't see this, 486 00:18:23,370 --> 00:18:24,510 but I'm just saying, Spawn." 487 00:18:24,510 --> 00:18:26,547 I'm gonna launch a couple extra beacons. 488 00:18:26,547 --> 00:18:28,747 And so, these will all call back real quick. 489 00:18:32,760 --> 00:18:34,320 And then once those are all started, 490 00:18:34,320 --> 00:18:36,600 we're gonna go over to the Windows box 491 00:18:36,600 --> 00:18:38,280 and we're going to run BeaconEye, 492 00:18:38,280 --> 00:18:40,740 that tool I mentioned earlier that uses YARA. 493 00:18:40,740 --> 00:18:42,300 And it shouldn't give us any results now 494 00:18:42,300 --> 00:18:44,130 because we've loaded that aggressor script, 495 00:18:44,130 --> 00:18:47,910 which instructs Cobalt Strike to create that secondary heap 496 00:18:47,910 --> 00:18:48,743 and then encrypt them all. 497 00:18:48,743 --> 00:18:49,890 And so, you can see, okay, great. 498 00:18:49,890 --> 00:18:51,180 It does not. 499 00:18:51,180 --> 00:18:53,160 So that's the first thing 500 00:18:53,160 --> 00:18:54,780 is getting past those YARA rules 501 00:18:54,780 --> 00:18:56,430 that look at the heap, right? 502 00:18:56,430 --> 00:18:57,263 Now that we've done that, 503 00:18:57,263 --> 00:18:58,830 we wanna look at YARA rules 504 00:18:58,830 --> 00:19:00,360 that target Cobalt Strike itself. 505 00:19:00,360 --> 00:19:01,290 So Cobalt Strike, yeah, sure, 506 00:19:01,290 --> 00:19:03,300 it allocates some dynamic memory 507 00:19:03,300 --> 00:19:04,860 and we want to encrypt those things, 508 00:19:04,860 --> 00:19:06,750 but there's also the entire implant itself 509 00:19:06,750 --> 00:19:09,090 sitting in memory that there are plenty of YARA rules, 510 00:19:09,090 --> 00:19:10,260 almost all those YARA rules 511 00:19:10,260 --> 00:19:12,293 that I have in that text file are for that itself, 512 00:19:12,293 --> 00:19:15,090 not for things that's going to allocate. 513 00:19:15,090 --> 00:19:17,580 And so, being able to consistently evade 514 00:19:17,580 --> 00:19:21,300 all of those YARA rules and tools like Moneta and PE-sieve 515 00:19:21,300 --> 00:19:23,040 is going to require us 516 00:19:23,040 --> 00:19:24,840 not only to encrypt all of the data 517 00:19:24,840 --> 00:19:26,580 associated with our implant, 518 00:19:26,580 --> 00:19:29,520 but also put it in non-exec executable memory. 519 00:19:29,520 --> 00:19:31,440 Because if you remember, tools like Moneta 520 00:19:31,440 --> 00:19:34,140 are looking for any executable private commit memory, 521 00:19:34,140 --> 00:19:35,430 regardless of what signature. 522 00:19:35,430 --> 00:19:37,560 It's not even looking at any signatures. 523 00:19:37,560 --> 00:19:40,320 It's only looking for, "Is there suspicious memory 524 00:19:40,320 --> 00:19:42,420 or threads pointing at suspicious memory?" 525 00:19:43,320 --> 00:19:44,910 And so, the nice thing is, 526 00:19:44,910 --> 00:19:46,980 and I've hinted at this a couple of times, 527 00:19:46,980 --> 00:19:49,050 the way that these frameworks work 528 00:19:49,050 --> 00:19:51,480 is they will call out, get an instruction, 529 00:19:51,480 --> 00:19:53,370 do whatever that they're supposed to do, 530 00:19:53,370 --> 00:19:56,040 and then they will sleep for these long periods of time. 531 00:19:56,040 --> 00:19:58,440 And traditionally, your sleep is much longer 532 00:19:58,440 --> 00:20:00,450 than the execution takes. 533 00:20:00,450 --> 00:20:01,920 And so, for a majority of the time 534 00:20:01,920 --> 00:20:04,200 the implant is on a computer, it's sleeping, 535 00:20:04,200 --> 00:20:05,370 it's not doing anything. 536 00:20:05,370 --> 00:20:06,420 And if the implant's sleeping, 537 00:20:06,420 --> 00:20:08,520 there's no reason we can't encrypt all of it 538 00:20:08,520 --> 00:20:10,290 and make it non executable. 539 00:20:10,290 --> 00:20:12,840 We just have to find a way to do that. 540 00:20:12,840 --> 00:20:14,460 I mentioned before that, 541 00:20:14,460 --> 00:20:16,410 when we write our encryption code, 542 00:20:16,410 --> 00:20:19,020 before I talked about system functions 032, 543 00:20:19,020 --> 00:20:22,290 that we wouldn't wanna implement our own encryption routine. 544 00:20:22,290 --> 00:20:23,490 And the reason for that is this. 545 00:20:23,490 --> 00:20:25,320 We want to evade tools like Moneta. 546 00:20:25,320 --> 00:20:26,640 And if we have an encryption routine, 547 00:20:26,640 --> 00:20:30,360 that's sitting in executable private commit memory, 548 00:20:30,360 --> 00:20:31,380 that's going to get flagged. 549 00:20:31,380 --> 00:20:33,480 And so, our beacon might get ignored, 550 00:20:33,480 --> 00:20:35,250 but that will get caught anyway. 551 00:20:35,250 --> 00:20:37,470 And so, there's not a huge change 552 00:20:37,470 --> 00:20:39,363 in the actual indicators on the host. 553 00:20:40,440 --> 00:20:42,150 So first, we can talk about this stub 554 00:20:42,150 --> 00:20:44,160 where we have some executable code, 555 00:20:44,160 --> 00:20:45,150 which is not preferable, 556 00:20:45,150 --> 00:20:46,020 but it is an option. 557 00:20:46,020 --> 00:20:47,250 And so, first of all, 558 00:20:47,250 --> 00:20:49,590 we have the Sleep Mask Kit from Cobalt Strike. 559 00:20:49,590 --> 00:20:51,210 And this is why I don't like to use this 560 00:20:51,210 --> 00:20:52,620 for the heap encryption. 561 00:20:52,620 --> 00:20:55,890 The whole reason is, is because if we use this, 562 00:20:55,890 --> 00:20:57,990 we have to leave that executable. 563 00:20:57,990 --> 00:21:00,150 And so, if we leave that Sleep Mask stub, 564 00:21:00,150 --> 00:21:00,983 which is just 565 00:21:02,760 --> 00:21:05,400 a small section of memory that we leave unencrypted 566 00:21:05,400 --> 00:21:08,040 and executable, if we leave that there, 567 00:21:08,040 --> 00:21:10,020 then that's going to get caught by Moneta anyway, 568 00:21:10,020 --> 00:21:11,670 and potentially caught by YARA rules. 569 00:21:11,670 --> 00:21:13,800 And we've seen, they've already had YARA rules come out 570 00:21:13,800 --> 00:21:16,380 that look specifically for the Sleep Mask Kit 571 00:21:16,380 --> 00:21:19,260 or even parts of it that you can't change. 572 00:21:19,260 --> 00:21:22,830 And so, this does maybe hide some of the indicators, 573 00:21:22,830 --> 00:21:23,910 but it doesn't hide them all. 574 00:21:23,910 --> 00:21:25,860 So it doesn't really solve our problem. 575 00:21:25,860 --> 00:21:28,320 The other option we have is this project shellcode 576 00:21:28,320 --> 00:21:30,540 fluctuation from mgeeky, 577 00:21:30,540 --> 00:21:33,810 and this is very similar to the Sleep Mask Kit stub. 578 00:21:33,810 --> 00:21:36,840 All this is doing is it makes the memory inaccessible 579 00:21:36,840 --> 00:21:39,810 or non-executable and it doesn't change it back. 580 00:21:39,810 --> 00:21:41,550 And so, when the execution continues, 581 00:21:41,550 --> 00:21:44,490 it will try and execute non-executable memory, 582 00:21:44,490 --> 00:21:46,200 and it will generate an error. 583 00:21:46,200 --> 00:21:47,460 But before all of that, 584 00:21:47,460 --> 00:21:49,920 it registers a vectored exception handler. 585 00:21:49,920 --> 00:21:51,420 And so, when that error gets generated 586 00:21:51,420 --> 00:21:53,370 from trying to execute inaccessible 587 00:21:53,370 --> 00:21:55,350 or non-accountable memory, 588 00:21:55,350 --> 00:21:57,240 it will go to the exception handler 589 00:21:57,240 --> 00:21:59,100 and that exception handler has to be executable 590 00:21:59,100 --> 00:22:00,273 for it to function, 591 00:22:00,273 --> 00:22:03,990 and then it will fix the memory and resume execution. 592 00:22:03,990 --> 00:22:07,320 And so, shellcode fluctuation is similar to Sleep Mask Kit. 593 00:22:07,320 --> 00:22:08,910 It implemented differently, 594 00:22:08,910 --> 00:22:10,740 but you're gonna have the same issue 595 00:22:10,740 --> 00:22:13,290 where you have to have some executable memory, 596 00:22:13,290 --> 00:22:14,220 no matter what. 597 00:22:14,220 --> 00:22:15,840 And so, again, it doesn't really solve 598 00:22:15,840 --> 00:22:19,590 or it's really not a true bypass in the way 599 00:22:19,590 --> 00:22:20,640 that I want it to be. 600 00:22:21,900 --> 00:22:24,240 The next thing we can look at is using ROP. 601 00:22:24,240 --> 00:22:26,370 And so, if you're familiar with exploit development, 602 00:22:26,370 --> 00:22:28,350 you've seen Return Oriented Programming 603 00:22:28,350 --> 00:22:31,830 as a popular way to get around DEP. 604 00:22:31,830 --> 00:22:32,790 But in this case, 605 00:22:32,790 --> 00:22:36,330 we can actually use it for changing memory permissions. 606 00:22:36,330 --> 00:22:38,926 So the first proof of concept that came out 607 00:22:38,926 --> 00:22:42,180 as far as I'm aware was from Josh Lospinoso. 608 00:22:42,180 --> 00:22:43,680 It's called Gargoyle. 609 00:22:43,680 --> 00:22:45,630 And Gargoyle is a proof of concept. 610 00:22:45,630 --> 00:22:47,050 It just launches message box 611 00:22:48,330 --> 00:22:49,530 and it's 32 bit, 612 00:22:49,530 --> 00:22:51,450 but the whole point of this is that it demonstrates 613 00:22:51,450 --> 00:22:55,140 using ROP to queue up these different APC calls 614 00:22:55,140 --> 00:22:57,900 that you could implement a sleep routine, 615 00:22:57,900 --> 00:22:59,460 but he's just doing a message box 616 00:22:59,460 --> 00:23:01,230 where it will do something where, 617 00:23:01,230 --> 00:23:04,800 while the rest of the code is not executable. 618 00:23:04,800 --> 00:23:08,220 Now just recently, Waldo came out with YouMayPasser, 619 00:23:08,220 --> 00:23:12,390 which is a x64 implementation of Gargoyle 620 00:23:12,390 --> 00:23:15,048 that is ready to use with something like Cobalt Strike. 621 00:23:15,048 --> 00:23:16,860 So it's not just a proof of concept. 622 00:23:16,860 --> 00:23:18,570 It's something you could use right now. 623 00:23:18,570 --> 00:23:20,046 And just after that, 624 00:23:20,046 --> 00:23:23,680 thefLinkk came out with DeepSleep, 625 00:23:23,680 --> 00:23:25,860 which is very similar to Waldo's project. 626 00:23:25,860 --> 00:23:27,930 I think his is more of a proof of concept, 627 00:23:27,930 --> 00:23:29,153 but it just doesn't use APCs. 628 00:23:29,153 --> 00:23:30,900 And so, all of these are pretty awesome 629 00:23:30,900 --> 00:23:32,730 because they solve our issue 630 00:23:32,730 --> 00:23:35,100 of needing executable code to do things. 631 00:23:35,100 --> 00:23:36,870 If we can use Return Oriented Programming 632 00:23:36,870 --> 00:23:40,680 to encrypt our data and to change the memory permissions, 633 00:23:40,680 --> 00:23:44,250 now we're at a point where we can actually have, 634 00:23:44,250 --> 00:23:46,470 during sleep, this change is waiting 635 00:23:46,470 --> 00:23:48,180 or slowly executing 636 00:23:48,180 --> 00:23:52,620 to perform all of our obfuscation on the code itself. 637 00:23:52,620 --> 00:23:53,790 The problem with ROP, 638 00:23:53,790 --> 00:23:55,530 and if you've done exploit development, 639 00:23:55,530 --> 00:23:56,910 you've probably run into this, 640 00:23:56,910 --> 00:23:59,130 as Windows updates or as you try and switch 641 00:23:59,130 --> 00:24:00,330 to different versions, 642 00:24:00,330 --> 00:24:02,080 the gadgets that you're calling 643 00:24:04,016 --> 00:24:05,580 may not exist in the process. 644 00:24:05,580 --> 00:24:07,470 And so, you try and resolve a gadget that you need, 645 00:24:07,470 --> 00:24:09,210 you might not be able to find it, 646 00:24:09,210 --> 00:24:10,740 and now your project doesn't work 647 00:24:10,740 --> 00:24:12,690 or you have to come up with some change for it to work 648 00:24:12,690 --> 00:24:14,313 or maybe load a new library. 649 00:24:15,300 --> 00:24:17,130 And so, these work and they solve the problem, 650 00:24:17,130 --> 00:24:18,480 but they're a little bit of a headache 651 00:24:18,480 --> 00:24:20,310 because you have to keep on top of them 652 00:24:20,310 --> 00:24:21,663 as new versions come out. 653 00:24:22,740 --> 00:24:26,490 Now, what is the solution to this 654 00:24:26,490 --> 00:24:28,290 is this project from Austin Hudson. 655 00:24:28,290 --> 00:24:31,740 So this is called FOLIAGE and FOLIAGE is a proof of concept 656 00:24:31,740 --> 00:24:35,310 on GitHub that is similar to Gargoyle, 657 00:24:35,310 --> 00:24:39,450 but instead of using ROP, instead of trying to find gadgets, 658 00:24:39,450 --> 00:24:42,270 it's going to use this API called NtContinue. 659 00:24:42,270 --> 00:24:44,370 And NtContinue is really awesome 660 00:24:44,370 --> 00:24:47,190 because it's traditionally used for exception handling, 661 00:24:47,190 --> 00:24:51,570 but what it's purpose is is you pass it a context. 662 00:24:51,570 --> 00:24:54,900 The context defines what all of the CPU registers should be. 663 00:24:54,900 --> 00:24:55,733 So you tell it, 664 00:24:55,733 --> 00:24:57,180 "Here's what the instruction pointer should be. 665 00:24:57,180 --> 00:24:59,670 Here's what all of the general purpose register should be. 666 00:24:59,670 --> 00:25:02,040 Here's what the stack pointer should be." 667 00:25:02,040 --> 00:25:04,170 And it will go and changes the thread 668 00:25:04,170 --> 00:25:06,330 to have all of that information. 669 00:25:06,330 --> 00:25:09,840 And so, this is almost like you're performing ROP, 670 00:25:09,840 --> 00:25:11,100 where you can define 671 00:25:11,100 --> 00:25:13,470 what the whole context should look like 672 00:25:13,470 --> 00:25:16,560 and execute whatever you want with an instruction pointer. 673 00:25:16,560 --> 00:25:18,540 And so, what Austin did is he came up with a way 674 00:25:18,540 --> 00:25:22,290 to cue a series of these asynchronous procedure calls 675 00:25:22,290 --> 00:25:25,140 that, one at a time, executes NtContinue, 676 00:25:25,140 --> 00:25:26,880 passing at a different context. 677 00:25:26,880 --> 00:25:29,220 So first, you'll execute NtContinue to do, 678 00:25:29,220 --> 00:25:30,240 maybe, your obfuscation, 679 00:25:30,240 --> 00:25:32,490 and then you'll do it to change the permissions, 680 00:25:32,490 --> 00:25:33,600 and then you'll do it to sleep. 681 00:25:33,600 --> 00:25:35,130 And we'll talk about exactly how this works 682 00:25:35,130 --> 00:25:36,030 on the next slide. 683 00:25:37,170 --> 00:25:39,390 So the sleep chain, how this works. 684 00:25:39,390 --> 00:25:40,500 Before it executes, 685 00:25:40,500 --> 00:25:43,740 it's gonna open a handle to this driver, KsecDD, 686 00:25:43,740 --> 00:25:46,650 which is a driver that you can use for encryption. 687 00:25:46,650 --> 00:25:49,590 It's an alternative to system function 032 688 00:25:49,590 --> 00:25:50,423 that you could use. 689 00:25:50,423 --> 00:25:52,470 It's already on the computer and you don't have to write 690 00:25:52,470 --> 00:25:53,870 your own encryption routine. 691 00:25:54,840 --> 00:25:56,850 Then, it's going to open a handle to the current thread 692 00:25:56,850 --> 00:25:58,800 so that it can, during this leap process, 693 00:25:58,800 --> 00:25:59,910 modify its context. 694 00:25:59,910 --> 00:26:03,183 And we'll talk about why exactly he does that in a bit. 695 00:26:04,080 --> 00:26:05,790 Then, it's gonna create a brand new thread 696 00:26:05,790 --> 00:26:09,300 which is going to hold this APC queue. 697 00:26:09,300 --> 00:26:10,530 It creates a new event, 698 00:26:10,530 --> 00:26:13,170 which we're going to use to keep the thread from exiting. 699 00:26:13,170 --> 00:26:15,870 It's gonna copy the context of the new thread 700 00:26:15,870 --> 00:26:17,520 to this brand new context structure, 701 00:26:17,520 --> 00:26:19,413 which we're going to reuse. 702 00:26:20,340 --> 00:26:21,540 Then, it's gonna queue this series 703 00:26:21,540 --> 00:26:23,220 of APC calls to NtContinue. 704 00:26:23,220 --> 00:26:27,330 So the first call is going to be just waiting on that event, 705 00:26:27,330 --> 00:26:29,100 which keeps the thread from exiting. 706 00:26:29,100 --> 00:26:31,560 Then, we're going to change the memory permissions 707 00:26:31,560 --> 00:26:33,780 of our entire beacon to be Read/Write. 708 00:26:33,780 --> 00:26:36,570 Then, we're going to tell that driver to encrypt the memory. 709 00:26:36,570 --> 00:26:38,160 Then, we're gonna save the context 710 00:26:38,160 --> 00:26:40,830 of our original thread so that we can restore it. 711 00:26:40,830 --> 00:26:43,350 We're gonna set the original thread context 712 00:26:43,350 --> 00:26:44,730 to this new fake one, 713 00:26:44,730 --> 00:26:46,980 and this is actually going to be one of the options 714 00:26:46,980 --> 00:26:49,890 we can use for bypassing some of the stack tracing. 715 00:26:49,890 --> 00:26:52,710 So we'll talk about that in a few slides. 716 00:26:52,710 --> 00:26:53,730 Then it's going to sleep. 717 00:26:53,730 --> 00:26:55,170 It uses NtDelayExecution, 718 00:26:55,170 --> 00:26:56,580 it waits for the number of seconds 719 00:26:56,580 --> 00:26:58,830 that the operator specified. 720 00:26:58,830 --> 00:26:59,973 Once that's done, 721 00:27:01,120 --> 00:27:04,380 it will instruct that driver to decrypt the memory. 722 00:27:04,380 --> 00:27:06,480 It'll then restore the original thread context, 723 00:27:06,480 --> 00:27:08,490 change the memory back to executable, 724 00:27:08,490 --> 00:27:11,070 and exit that new APC thread. 725 00:27:11,070 --> 00:27:12,150 So it queues all of these up. 726 00:27:12,150 --> 00:27:13,530 It hasn't actually done any of this yet. 727 00:27:13,530 --> 00:27:15,810 It's just queuing these up in that new thread. 728 00:27:15,810 --> 00:27:16,643 And once that's done, 729 00:27:16,643 --> 00:27:18,900 it forces that thread into an alertable state. 730 00:27:18,900 --> 00:27:20,940 And this is important for APCs 731 00:27:20,940 --> 00:27:23,550 because they have to be alertable for an APC to execute. 732 00:27:23,550 --> 00:27:25,950 And so, it forces it into an alertable state 733 00:27:25,950 --> 00:27:27,990 and then it signals that event and waits on it 734 00:27:27,990 --> 00:27:30,060 so that the original thread, while this is all happening, 735 00:27:30,060 --> 00:27:30,985 the original thread doesn't exit 736 00:27:30,985 --> 00:27:33,180 and doesn't do anything else. 737 00:27:33,180 --> 00:27:35,490 One thing that I glossed over here 738 00:27:35,490 --> 00:27:38,727 is that all of these are going to return to NtTestAlert 739 00:27:38,727 --> 00:27:40,830 and NtTestAlert is another API call 740 00:27:40,830 --> 00:27:43,680 that you can use to make it alertable again. 741 00:27:43,680 --> 00:27:45,690 And so, this is what keeps the chain moving. 742 00:27:45,690 --> 00:27:49,380 So everything executes, it returns to NtTestAlert, 743 00:27:49,380 --> 00:27:50,880 which then makes it alertable again 744 00:27:50,880 --> 00:27:52,983 and executes the next item in the chain. 745 00:27:55,710 --> 00:27:59,280 Just recently, there's a project called Ekko from CSpider 746 00:27:59,280 --> 00:28:01,830 and this is actually based on some reverse engineering 747 00:28:01,830 --> 00:28:04,170 of one of the commercial C2 products that I mentioned 748 00:28:04,170 --> 00:28:05,190 in the beginning. 749 00:28:05,190 --> 00:28:08,820 But the way that this works is very similar to FOLIAGE, 750 00:28:08,820 --> 00:28:12,660 except instead of queuing APCs with NGQ APC, 751 00:28:12,660 --> 00:28:15,060 it's going to use CreateTimerQueueTimer, 752 00:28:15,060 --> 00:28:16,410 and so very similar, 753 00:28:16,410 --> 00:28:18,810 but it's going to use timers to queue these instead. 754 00:28:18,810 --> 00:28:21,630 There are some limitations on the number of arguments 755 00:28:21,630 --> 00:28:22,710 you can pass and things, 756 00:28:22,710 --> 00:28:24,739 but overall it's approximately the same, 757 00:28:24,739 --> 00:28:26,820 but it's just an alternative that you could use 758 00:28:26,820 --> 00:28:28,920 that still uses this NtContinue 759 00:28:28,920 --> 00:28:31,440 as what it's queuing and queues context. 760 00:28:31,440 --> 00:28:35,158 It just doesn't call it with NT Queue APC. 761 00:28:35,158 --> 00:28:37,530 So we can do a quick demo here of FOLIAGE. 762 00:28:37,530 --> 00:28:40,180 I'm going to look at my two command prompt processes. 763 00:28:44,880 --> 00:28:47,430 I'm going to inject Cobalt Strike into one of them. 764 00:28:50,100 --> 00:28:51,390 Then I will run Moneta on it 765 00:28:51,390 --> 00:28:53,880 and you can see, I get no results from Moneta. 766 00:28:53,880 --> 00:28:55,860 I'm then going to run PE-sieve, 767 00:28:55,860 --> 00:28:56,790 and same thing, 768 00:28:56,790 --> 00:28:59,010 I'm not going to get any results from PE-sieve, 769 00:28:59,010 --> 00:29:01,110 now, just because of having FOLIAGE there. 770 00:29:01,950 --> 00:29:04,983 But you can see my beacon is definitely here in 6460. 771 00:29:07,080 --> 00:29:09,780 All right, so the next thing we wanna do is avoid sleep. 772 00:29:09,780 --> 00:29:11,850 And what I mean by this is if we wanna bypass 773 00:29:11,850 --> 00:29:13,650 some of these stack tracing capabilities, 774 00:29:13,650 --> 00:29:15,570 like Hunt-Sleeping- Beacons, 775 00:29:15,570 --> 00:29:18,270 we have to avoid using NtDelayExecution. 776 00:29:18,270 --> 00:29:21,390 So even FOLIAGE, which bypasses tools like Moneta 777 00:29:21,390 --> 00:29:23,400 and PE-sieve as it is on GitHub, 778 00:29:23,400 --> 00:29:25,830 it's going to get caught by Hunt-Sleeping-Beacons. 779 00:29:25,830 --> 00:29:27,540 Again, these generate lots of false positives. 780 00:29:27,540 --> 00:29:28,860 It's not a great indicator, 781 00:29:28,860 --> 00:29:31,830 but it is something that I'd like to avoid. 782 00:29:31,830 --> 00:29:33,090 There are a couple ways we can do this 783 00:29:33,090 --> 00:29:36,270 that just don't use sleep or sleepy EX or NtDelayExecution. 784 00:29:36,270 --> 00:29:39,630 We could use our own code that sleeps, 785 00:29:39,630 --> 00:29:41,160 but that runs into the same problem 786 00:29:41,160 --> 00:29:44,130 where we don't want executable code, right? 787 00:29:44,130 --> 00:29:46,440 The other thing we can do is use timers again, 788 00:29:46,440 --> 00:29:48,240 and you can see there at the bottom, 789 00:29:48,240 --> 00:29:49,800 I've shown you what that might look like. 790 00:29:49,800 --> 00:29:53,560 The problem with that is you have to allocate 791 00:29:56,043 --> 00:29:58,500 or you have to use three different API calls to do this. 792 00:29:58,500 --> 00:30:00,450 And so, when we start talking about rock chains, 793 00:30:00,450 --> 00:30:03,780 that makes it much larger, maybe, than it needs to be. 794 00:30:03,780 --> 00:30:06,330 The last option here, just using WaitForSingleObject, 795 00:30:06,330 --> 00:30:07,380 is, I think, the best. 796 00:30:07,380 --> 00:30:10,680 You pick something that isn't going to become alertable, 797 00:30:10,680 --> 00:30:13,830 maybe the original thread that's sleeping 798 00:30:13,830 --> 00:30:15,810 because we're not doing anything with that. 799 00:30:15,810 --> 00:30:18,870 We wait on that, and then we use WaitForSingleObject's 800 00:30:18,870 --> 00:30:20,393 timeout parameter to sleep. 801 00:30:20,393 --> 00:30:23,220 And so, this allows us to effectively sleep 802 00:30:23,220 --> 00:30:27,960 without using Hunt-Sleeping-Beacons or NtDelayExecution, 803 00:30:27,960 --> 00:30:30,900 or it allows us to sleep without using NtDelayExecution, 804 00:30:30,900 --> 00:30:33,513 and then not get caught by Hunt-Sleeping-Beacons. 805 00:30:34,380 --> 00:30:36,750 So I've got a really simple proof of concept here 806 00:30:36,750 --> 00:30:38,490 where I've just hooked sleep and replaced it 807 00:30:38,490 --> 00:30:40,230 with the WaitForSingleObject. 808 00:30:40,230 --> 00:30:44,403 I'm going to inject into 5296 here, 809 00:30:49,320 --> 00:30:51,510 and then we'll go ahead and run Hunt-Sleeping-Beacons, 810 00:30:51,510 --> 00:30:54,600 and you can see, I think I highlighted here, maybe not, 811 00:30:54,600 --> 00:30:55,950 but it finds zero threads. 812 00:30:55,950 --> 00:30:57,270 The output's verbose for that. 813 00:30:57,270 --> 00:30:59,310 But it does not find anything, 814 00:30:59,310 --> 00:31:02,440 even though I have my beacon in 5296 sleeping 815 00:31:04,764 --> 00:31:06,003 and executing on system. 816 00:31:07,050 --> 00:31:08,130 Okay. 817 00:31:08,130 --> 00:31:10,260 Next, we wanna talk about return address spoofing. 818 00:31:10,260 --> 00:31:13,260 So I talked about tools like Moneta and MalMemDetect, 819 00:31:13,260 --> 00:31:15,840 which try and look at the return addresses. 820 00:31:15,840 --> 00:31:19,023 Or Rather, not Moneta, PE-sieve and MalMemDetect, 821 00:31:20,010 --> 00:31:22,230 excuse me, which look at the return addresses. 822 00:31:22,230 --> 00:31:23,550 And so, there's two ways 823 00:31:23,550 --> 00:31:24,990 that we can do return address spoofing 824 00:31:24,990 --> 00:31:27,090 and this is a really important difference, actually. 825 00:31:27,090 --> 00:31:29,190 Looking at return address spoofing at rest 826 00:31:29,190 --> 00:31:32,340 versus return address spoofing at execution time. 827 00:31:32,340 --> 00:31:33,870 So return address spoofing at rest, 828 00:31:33,870 --> 00:31:36,840 I don't necessarily think there's a ton of value here. 829 00:31:36,840 --> 00:31:39,060 All you're really getting out of this is bypassing 830 00:31:39,060 --> 00:31:40,230 something like PE-sieve, 831 00:31:40,230 --> 00:31:45,150 which is looking at at the return address when it scans it. 832 00:31:45,150 --> 00:31:47,923 And so, from a security product point of view, 833 00:31:47,923 --> 00:31:50,820 security products don't tend to scan processes 834 00:31:50,820 --> 00:31:53,010 to look at their return addresses, but PE-sieve does 835 00:31:53,010 --> 00:31:53,878 and that's our goal. 836 00:31:53,878 --> 00:31:55,950 So this is something we want to do. 837 00:31:55,950 --> 00:31:58,770 The first option we have is another project from mgeeky 838 00:31:58,770 --> 00:32:00,330 called Thread Stack Spoofing. 839 00:32:00,330 --> 00:32:02,580 This will just overwrite the return address 840 00:32:02,580 --> 00:32:04,380 with zero during sleep 841 00:32:04,380 --> 00:32:07,230 and this causes the stack to get truncated. 842 00:32:07,230 --> 00:32:08,760 There are some scenarios though, 843 00:32:08,760 --> 00:32:11,070 where this is going to leak arguments on the stack. 844 00:32:11,070 --> 00:32:13,680 And so, you will generate IOCs in those scenarios 845 00:32:13,680 --> 00:32:16,230 and again, it just depends on a couple of variables 846 00:32:16,230 --> 00:32:17,820 that we're not gonna go into. 847 00:32:17,820 --> 00:32:19,560 The next option is a little bit simpler, 848 00:32:19,560 --> 00:32:23,040 and it's just using this set context API, 849 00:32:23,040 --> 00:32:25,110 which was already demonstrated in FOLIAGE, 850 00:32:25,110 --> 00:32:29,220 to copy a fake context where we specify 851 00:32:29,220 --> 00:32:30,630 a different return address, 852 00:32:30,630 --> 00:32:32,970 and we copy it over our thread during sleep. 853 00:32:32,970 --> 00:32:34,800 And so, once we do this, if it scans it, 854 00:32:34,800 --> 00:32:36,240 it's going to see whatever we put there, 855 00:32:36,240 --> 00:32:39,900 which could be an API call to a memory address 856 00:32:39,900 --> 00:32:42,270 that isn't private commit, just some API call 857 00:32:42,270 --> 00:32:43,770 in a normal DLL. 858 00:32:43,770 --> 00:32:45,570 And so, it won't flag anymore. 859 00:32:45,570 --> 00:32:47,280 So that effectively solves that. 860 00:32:47,280 --> 00:32:49,863 It's a pretty simple solution for this. 861 00:32:50,910 --> 00:32:53,100 When we talk about return address spoofing 862 00:32:53,100 --> 00:32:54,420 at execution time, 863 00:32:54,420 --> 00:32:56,550 this is where it gets a little bit more difficult. 864 00:32:56,550 --> 00:32:58,530 So just about a month ago, 865 00:32:58,530 --> 00:33:00,510 there was a project called Call Stack Spoofers 866 00:33:00,510 --> 00:33:01,710 from Will Burgess, 867 00:33:01,710 --> 00:33:04,620 and this is a proof of concept that is really interesting, 868 00:33:04,620 --> 00:33:07,950 where it will actually copy a full stack, 869 00:33:07,950 --> 00:33:11,220 unwind from just something on his test machine. 870 00:33:11,220 --> 00:33:13,740 He's hard coded these in his program. 871 00:33:13,740 --> 00:33:15,180 And so, when the thread is sleeping, 872 00:33:15,180 --> 00:33:17,892 it will copy that entire stack over. 873 00:33:17,892 --> 00:33:19,980 And then when it's done executing, 874 00:33:19,980 --> 00:33:21,090 or excuse me, when it's done sleeping, 875 00:33:21,090 --> 00:33:22,950 it will start trying to execute those things 876 00:33:22,950 --> 00:33:24,120 and at some point, will error, 877 00:33:24,120 --> 00:33:26,400 even though it's a valid stack at some point, 878 00:33:26,400 --> 00:33:28,380 it will error because it doesn't have 879 00:33:28,380 --> 00:33:31,740 the right things loaded or it can't resolve the addresses. 880 00:33:31,740 --> 00:33:32,880 But before that, again, 881 00:33:32,880 --> 00:33:35,040 he's registered a vectored exception handler 882 00:33:35,040 --> 00:33:36,210 that will catch this. 883 00:33:36,210 --> 00:33:39,063 And so, he can restore the old stack once that happens. 884 00:33:40,410 --> 00:33:41,730 The other option here, 885 00:33:41,730 --> 00:33:44,220 which I think is a little bit better for our purposes, 886 00:33:44,220 --> 00:33:48,150 is just called x64 Return Address Spoofing from namazso, 887 00:33:48,150 --> 00:33:49,890 and this is something that's been on the internet 888 00:33:49,890 --> 00:33:50,793 for a long time. 889 00:33:52,590 --> 00:33:54,148 It's been on the internet for a long time, 890 00:33:54,148 --> 00:33:55,590 and essentially, all it's doing, 891 00:33:55,590 --> 00:33:57,270 and we're gonna go through how this works specifically, 892 00:33:57,270 --> 00:34:00,180 but all it's doing is it's storing a ROP gadget 893 00:34:00,180 --> 00:34:01,560 as the return address. 894 00:34:01,560 --> 00:34:03,930 And so, while it's executing this, 895 00:34:03,930 --> 00:34:07,140 ROP gadget is going to sit in the return address. 896 00:34:07,140 --> 00:34:08,820 And so, if you look at the stack, 897 00:34:08,820 --> 00:34:11,160 it's going to look like it's doing something legitimate, 898 00:34:11,160 --> 00:34:13,173 but we're actually executing our code. 899 00:34:14,280 --> 00:34:15,180 So how does this work? 900 00:34:15,180 --> 00:34:17,670 Well first, we need a wrapper program 901 00:34:17,670 --> 00:34:21,690 and the wrapper program is just our malware, 902 00:34:21,690 --> 00:34:23,540 so it's our loader for Cobalt Strike. 903 00:34:24,570 --> 00:34:26,190 First, it's gonna have this structure here, 904 00:34:26,190 --> 00:34:28,890 which has a trampoline spot, 905 00:34:28,890 --> 00:34:30,540 it's got a spot for the target function, 906 00:34:30,540 --> 00:34:32,370 and it's also got this spot called RBX, 907 00:34:32,370 --> 00:34:34,320 which we're gonna use for data storage 908 00:34:34,320 --> 00:34:36,120 in the actual shellcode in a second. 909 00:34:37,530 --> 00:34:40,920 Then, we just cast this on the shellcode itself, 910 00:34:40,920 --> 00:34:42,210 we cast it as a function, 911 00:34:42,210 --> 00:34:43,980 and we pass it whatever arguments. 912 00:34:43,980 --> 00:34:45,360 So it's a little bit messy here, 913 00:34:45,360 --> 00:34:46,800 but you can see me calling sleep 914 00:34:46,800 --> 00:34:50,340 and I'm passing it five seconds, 5,000 milliseconds, 915 00:34:50,340 --> 00:34:52,680 as well as that parameter structure. 916 00:34:52,680 --> 00:34:54,750 This also works for larger functions 917 00:34:54,750 --> 00:34:56,250 that require more arguments. 918 00:34:56,250 --> 00:34:58,890 And so, you can see here, I'm passing it. 919 00:34:58,890 --> 00:35:01,690 I think this is five arguments for write process memory. 920 00:35:03,030 --> 00:35:05,520 But once you call that 921 00:35:05,520 --> 00:35:06,540 or once you've done that cast 922 00:35:06,540 --> 00:35:08,970 and you've called into the shellcode itself, 923 00:35:08,970 --> 00:35:11,610 we're gonna go through how this works specifically as well. 924 00:35:11,610 --> 00:35:14,280 So first thing we wanna do is just save 925 00:35:14,280 --> 00:35:16,200 the original return address. 926 00:35:16,200 --> 00:35:17,380 We want to move 927 00:35:21,930 --> 00:35:24,390 the trampoline gadget and the intended function, 928 00:35:24,390 --> 00:35:26,165 we're gonna move that into RAX 929 00:35:26,165 --> 00:35:29,130 and we're gonna put the jump RBX gadget 930 00:35:29,130 --> 00:35:30,270 as the new return address. 931 00:35:30,270 --> 00:35:32,040 So this is where the spoof happens, 932 00:35:32,040 --> 00:35:33,423 at that last line there. 933 00:35:34,680 --> 00:35:37,050 Yeah, at that last two lines there, rather, 934 00:35:37,050 --> 00:35:39,000 where we're storing that gadget in r10 935 00:35:39,000 --> 00:35:41,400 and then we're moving it into the stack pointer. 936 00:35:42,360 --> 00:35:45,330 Then, we're gonna move the intended function into r10 937 00:35:45,330 --> 00:35:48,120 and we're going to preserve the original return address 938 00:35:48,120 --> 00:35:50,940 and the RBX value at the original RBX value 939 00:35:50,940 --> 00:35:53,910 so that we can restore those when we're done. 940 00:35:53,910 --> 00:35:56,160 Then, we're gonna move this fix up function, 941 00:35:56,160 --> 00:35:59,010 that we'll talk about on the next slide, into RBX. 942 00:35:59,010 --> 00:36:02,060 And this is important because, since jump RBX 943 00:36:02,060 --> 00:36:03,870 is on the stack, 944 00:36:03,870 --> 00:36:04,770 at that last line, 945 00:36:04,770 --> 00:36:06,360 we're gonna jump to the intended function, 946 00:36:06,360 --> 00:36:08,520 so we jump to sleep or we jump to right process memory 947 00:36:08,520 --> 00:36:10,500 or whatever it is we passed here, 948 00:36:10,500 --> 00:36:11,340 we're gonna jump to it. 949 00:36:11,340 --> 00:36:13,500 And when it's done, it's going to return 950 00:36:13,500 --> 00:36:15,450 and the return address is jump RBX. 951 00:36:15,450 --> 00:36:16,650 And so, whatever's in RBX, 952 00:36:16,650 --> 00:36:17,850 in this case, our cleanup function, 953 00:36:17,850 --> 00:36:20,013 is what it's going to jump to. 954 00:36:21,120 --> 00:36:23,250 So we move here and we can see it jumps 955 00:36:23,250 --> 00:36:24,600 to the fix up structure. 956 00:36:24,600 --> 00:36:28,020 All this does is it restores the original RBX 957 00:36:28,020 --> 00:36:31,890 and then it jumps back to the original return address 958 00:36:31,890 --> 00:36:33,420 that restores execution. 959 00:36:33,420 --> 00:36:34,770 So all of this combined, 960 00:36:34,770 --> 00:36:37,290 maybe a little bit confusing in this presentation setting, 961 00:36:37,290 --> 00:36:39,210 but all of this, if you look to the code, 962 00:36:39,210 --> 00:36:41,460 it's maybe more cohesive, 963 00:36:41,460 --> 00:36:43,440 and what it's doing is it's storing that jump RBX 964 00:36:43,440 --> 00:36:44,273 on the stack. 965 00:36:44,273 --> 00:36:46,710 It's executing your function with a jump to it. 966 00:36:46,710 --> 00:36:47,880 And then when that returns, 967 00:36:47,880 --> 00:36:49,620 it's going to return to your gadget, 968 00:36:49,620 --> 00:36:51,930 which in RBX, we're storing our cleanup, 969 00:36:51,930 --> 00:36:54,390 which gets us back to whatever called it. 970 00:36:54,390 --> 00:36:56,910 And so, effectively, we bypass tools 971 00:36:56,910 --> 00:36:58,800 like MalMemDetect with this, 972 00:36:58,800 --> 00:37:00,200 and I'll show you that here. 973 00:37:03,960 --> 00:37:06,030 So we list our two command prompts again. 974 00:37:06,030 --> 00:37:09,120 We're going to inject into 8568. 975 00:37:09,120 --> 00:37:11,760 We see there's nothing on the desktop right now. 976 00:37:11,760 --> 00:37:16,125 When we load MalMemDetect into 8568, 977 00:37:16,125 --> 00:37:18,510 we'll see our log gets created on the desktop, 978 00:37:18,510 --> 00:37:21,690 which just tells us that MalMemDetect loaded successfully. 979 00:37:21,690 --> 00:37:24,273 And then, we'll inject our beacon into it. 980 00:37:25,470 --> 00:37:26,730 And then, once that's done, 981 00:37:26,730 --> 00:37:28,800 we'll try and look at the log for the detection, 982 00:37:28,800 --> 00:37:32,280 but when we run this, we get, "The file cannot be found," 983 00:37:32,280 --> 00:37:34,560 'cause there's no detection log for this. 984 00:37:34,560 --> 00:37:37,710 But we look, 8568 is definitely beaconing back 985 00:37:37,710 --> 00:37:39,960 and we just haven't generated anything there. 986 00:37:41,550 --> 00:37:42,383 Okay. 987 00:37:42,383 --> 00:37:43,500 So all of that said, 988 00:37:43,500 --> 00:37:46,680 the last part that I wanna talk about is AceLdr. 989 00:37:46,680 --> 00:37:49,050 So AceLdr is the tool that I wrote. 990 00:37:49,050 --> 00:37:51,810 It is able to bypass all of the scanners 991 00:37:51,810 --> 00:37:52,643 that we talked about, 992 00:37:52,643 --> 00:37:55,740 so PE-sieve, Moneta, MalMemDetect, 993 00:37:55,740 --> 00:37:57,990 all of the Cobalt Strike YARA rules that I have 994 00:37:57,990 --> 00:37:59,090 or could find, anyway. 995 00:38:00,330 --> 00:38:03,330 It also bypasses, there was a tool that came out 996 00:38:03,330 --> 00:38:05,490 after I submitted this talk, called Patriot, 997 00:38:05,490 --> 00:38:09,150 which was made to detect FOLIAGE specifically 998 00:38:09,150 --> 00:38:10,800 from Joe at Elastic, 999 00:38:10,800 --> 00:38:12,570 but it will bypass Patriot as well. 1000 00:38:12,570 --> 00:38:14,020 I got that a couple days ago. 1001 00:38:15,690 --> 00:38:17,160 All you have to do to use this, 1002 00:38:17,160 --> 00:38:18,180 if you're a Cobalt Strike user, 1003 00:38:18,180 --> 00:38:20,580 is you download the bin or you build it yourself, 1004 00:38:20,580 --> 00:38:22,290 and then you import one script 1005 00:38:22,290 --> 00:38:24,240 and any shellcode that you generate will have 1006 00:38:24,240 --> 00:38:26,690 all of the capabilities that we're talking about. 1007 00:38:27,630 --> 00:38:28,560 Everything that it encrypts, 1008 00:38:28,560 --> 00:38:31,320 it uses system functions 032 for. 1009 00:38:31,320 --> 00:38:33,150 It's going to use the technique that I mentioned, 1010 00:38:33,150 --> 00:38:35,790 where it creates a new heap 1011 00:38:35,790 --> 00:38:38,670 and then allocates things there to encrypt them. 1012 00:38:38,670 --> 00:38:41,970 It's going to use FOLIAGE to obfuscate 1013 00:38:41,970 --> 00:38:45,030 the memory permissions and encrypt the actual beacon code. 1014 00:38:45,030 --> 00:38:48,060 But it's going to delay execution with WaitForSingleObject. 1015 00:38:48,060 --> 00:38:49,440 And finally, it's going to perform 1016 00:38:49,440 --> 00:38:51,570 the return address boothing that I talked about 1017 00:38:51,570 --> 00:38:55,170 for internet connect A/W for NtWaitForSingleObject 1018 00:38:55,170 --> 00:38:56,520 and for RtlAllocateHeap, 1019 00:38:56,520 --> 00:39:00,570 which are all the things that MalMemDetect looks for. 1020 00:39:00,570 --> 00:39:03,910 So I've got just a demo here of using AceLdr. 1021 00:39:03,910 --> 00:39:05,700 Well, look. We've got our command prompts. 1022 00:39:05,700 --> 00:39:07,950 We've got three of them and you'll see why. 1023 00:39:07,950 --> 00:39:11,550 We're gonna use that 7676 at the end for MalMemDetect, 1024 00:39:11,550 --> 00:39:13,890 but we'll inject into 9108. 1025 00:39:13,890 --> 00:39:16,080 We'll give this a second here 1026 00:39:16,080 --> 00:39:17,640 and it will get our call back. 1027 00:39:17,640 --> 00:39:19,740 So we have our beacon now. 1028 00:39:19,740 --> 00:39:21,780 Then, we'll go and start trying to scan it 1029 00:39:21,780 --> 00:39:24,240 with different tools that the analyst might use. 1030 00:39:24,240 --> 00:39:26,310 So the first thing I do here is I just list out, 1031 00:39:26,310 --> 00:39:27,510 here's all the YARA rules, 1032 00:39:27,510 --> 00:39:28,343 just so you can see 1033 00:39:28,343 --> 00:39:30,550 that there are a good number of them, at least. 1034 00:39:32,580 --> 00:39:34,430 We'll go ahead and scan it with YARA. 1035 00:39:36,090 --> 00:39:36,923 It calls back, 1036 00:39:36,923 --> 00:39:38,280 but there's no output from that 1037 00:39:38,280 --> 00:39:40,170 because it didn't find anything. 1038 00:39:40,170 --> 00:39:41,880 We'll run Hunt-Sleeping-Beacons, 1039 00:39:41,880 --> 00:39:44,970 and you can see, we got found zero threads. 1040 00:39:44,970 --> 00:39:46,890 We'll run Moneta targeting it, 1041 00:39:46,890 --> 00:39:50,040 and we get no alerts there. 1042 00:39:50,040 --> 00:39:51,507 We'll run PE-sieve, 1043 00:39:51,507 --> 00:39:53,880 looking at it as well. 1044 00:39:53,880 --> 00:39:54,900 And when this finishes, 1045 00:39:54,900 --> 00:39:57,930 you'll see there's zero findings here. 1046 00:39:57,930 --> 00:40:00,180 We'll go ahead and look at our command prompts again. 1047 00:40:00,180 --> 00:40:02,370 And this time we're gonna use the 7676 1048 00:40:02,370 --> 00:40:05,100 so that we can inject MalMemDetect into it 1049 00:40:05,100 --> 00:40:06,690 before we do anything. 1050 00:40:06,690 --> 00:40:09,060 We'll look at the desktop real quick. 1051 00:40:09,060 --> 00:40:09,990 Once that calls back, 1052 00:40:09,990 --> 00:40:11,970 you'll see there's nothing on the desktop. 1053 00:40:11,970 --> 00:40:14,040 We'll load MalMemDetect into it 1054 00:40:14,040 --> 00:40:16,080 and we'll make sure that it loaded successfully 1055 00:40:16,080 --> 00:40:17,613 by reading that text file. 1056 00:40:20,160 --> 00:40:21,480 Okay, we see it loaded. 1057 00:40:21,480 --> 00:40:23,820 We've got all the output from it. 1058 00:40:23,820 --> 00:40:26,580 We'll go ahead and inject into that process now. 1059 00:40:26,580 --> 00:40:27,960 We'll wait for it to call back. 1060 00:40:27,960 --> 00:40:29,583 I'm gonna zoom in here. 1061 00:40:31,904 --> 00:40:35,100 Okay, we got our call back from 7676. 1062 00:40:35,100 --> 00:40:38,670 Then, we go ahead and scan it with MalMemDetect here. 1063 00:40:38,670 --> 00:40:41,490 Or we try and look at the detection log 1064 00:40:41,490 --> 00:40:44,400 from MalMemDetect and we see that we have no file specified. 1065 00:40:44,400 --> 00:40:47,340 So it has definitely not been detected there. 1066 00:40:47,340 --> 00:40:49,501 We jump over to the box, one last thing, 1067 00:40:49,501 --> 00:40:50,705 and we're gonna look at, 1068 00:40:50,705 --> 00:40:54,270 we've got all the same command prompt, 7676, 9108. 1069 00:40:54,270 --> 00:40:56,940 We run BeaconEye and it finds no beacon processes. 1070 00:40:56,940 --> 00:41:00,450 It can't find any data on the heap 1071 00:41:00,450 --> 00:41:03,250 that leads it to believe there are configurations there. 1072 00:41:04,470 --> 00:41:05,772 So some final notes. 1073 00:41:05,772 --> 00:41:07,290 I talk about AceLdr, 1074 00:41:07,290 --> 00:41:09,120 and again, it is specific for Cobalt Strike. 1075 00:41:09,120 --> 00:41:12,540 If you try and use that with another commanding control, 1076 00:41:12,540 --> 00:41:13,650 first of all, you wouldn't be able to import 1077 00:41:13,650 --> 00:41:14,483 the aggressor script, 1078 00:41:14,483 --> 00:41:15,780 but even if you just try to use it 1079 00:41:15,780 --> 00:41:19,500 as a reflective DLL loader, it may or may not work. 1080 00:41:19,500 --> 00:41:20,700 I haven't tried it with anything else, 1081 00:41:20,700 --> 00:41:23,730 but it's really tested and made for Cobalt Strike. 1082 00:41:23,730 --> 00:41:25,650 But these things and the proof of concepts 1083 00:41:25,650 --> 00:41:28,620 that I talked about can all be used for just about anything. 1084 00:41:28,620 --> 00:41:30,101 If you wrote your own malware implant, 1085 00:41:30,101 --> 00:41:32,520 or if you prefer some other framework, 1086 00:41:32,520 --> 00:41:34,290 there's no reason you shouldn't be able to do this, 1087 00:41:34,290 --> 00:41:37,020 especially if it's written in an unmanaged language, 1088 00:41:37,020 --> 00:41:38,040 like C or C++ plus. 1089 00:41:38,040 --> 00:41:40,320 If you have a C# implant, 1090 00:41:40,320 --> 00:41:41,220 you might have problems 1091 00:41:41,220 --> 00:41:43,830 because there's some jet memory being allocated 1092 00:41:43,830 --> 00:41:44,700 that might cause you issues. 1093 00:41:44,700 --> 00:41:47,250 But if it's just a C implant, like Cobalt Strike, 1094 00:41:47,250 --> 00:41:49,650 you're not gonna have problems there. 1095 00:41:49,650 --> 00:41:52,650 The techniques we talked about bypass existing scanners. 1096 00:41:52,650 --> 00:41:55,410 I already mentioned that that tool Patriot came out 1097 00:41:55,410 --> 00:41:57,120 a couple weeks ago and that detected it 1098 00:41:57,120 --> 00:42:00,120 because it was looking for FOLIAGE, specifically. 1099 00:42:00,120 --> 00:42:02,970 So there's no guarantee that you're going to evade 1100 00:42:02,970 --> 00:42:03,810 these things forever. 1101 00:42:03,810 --> 00:42:07,020 The goal was to look at these really established scanners, 1102 00:42:07,020 --> 00:42:10,680 like PE-sieve and even Moneta and all of the YARA rules 1103 00:42:10,680 --> 00:42:12,600 that are being used more commonly 1104 00:42:12,600 --> 00:42:15,570 and don't tend to generate a ton of false positives. 1105 00:42:15,570 --> 00:42:17,370 So looking at these things and figuring out 1106 00:42:17,370 --> 00:42:19,770 how can we generically bypass these 1107 00:42:19,770 --> 00:42:21,930 without just breaking small signatures? 1108 00:42:21,930 --> 00:42:23,970 Although being said, there's no reason to believe 1109 00:42:23,970 --> 00:42:26,280 that there's not gonna be another scanner that comes out 1110 00:42:26,280 --> 00:42:29,945 that detects one specific part of something we dom maybe. 1111 00:42:29,945 --> 00:42:31,620 But that being said, 1112 00:42:31,620 --> 00:42:34,270 I might try and come up with a bypass for it as well. 1113 00:42:35,400 --> 00:42:37,020 I also left out some scanners 1114 00:42:37,020 --> 00:42:39,000 and also some bypass techniques 1115 00:42:39,000 --> 00:42:42,148 because they were meant to specifically target 1116 00:42:42,148 --> 00:42:43,623 really specific things. 1117 00:42:44,787 --> 00:42:47,340 Let's say we had a YARA rule that detected Cobalt Strike 1118 00:42:47,340 --> 00:42:49,770 and someone wrote a tool 1119 00:42:49,770 --> 00:42:52,290 that just changed the bits that that YARA rule 1120 00:42:52,290 --> 00:42:53,460 was looking for, 1121 00:42:53,460 --> 00:42:55,410 I'm not going to include that in my talk 1122 00:42:55,410 --> 00:42:59,040 or in my section of bypassing patterns 1123 00:42:59,040 --> 00:43:01,080 because, in my mind, that's a bit fragile. 1124 00:43:01,080 --> 00:43:03,420 And so, we want something like encryption. 1125 00:43:03,420 --> 00:43:05,670 And I didn't specifically mention this, but AceLdr, 1126 00:43:05,670 --> 00:43:06,810 every time it's going to sleep, 1127 00:43:06,810 --> 00:43:08,520 it generates a brand new encryption key 1128 00:43:08,520 --> 00:43:09,630 and it encrypts everything. 1129 00:43:09,630 --> 00:43:11,580 And so, you can't just look at, "Okay, 1130 00:43:11,580 --> 00:43:12,630 where's the key stored?" 1131 00:43:12,630 --> 00:43:15,150 Or, "Let's look for some bytes once they're encrypted," 1132 00:43:15,150 --> 00:43:16,680 'cause they're gonna be different on every computer 1133 00:43:16,680 --> 00:43:18,873 every time it sleeps, just by design. 1134 00:43:19,830 --> 00:43:22,200 And so, that is everything I had to talk about. 1135 00:43:22,200 --> 00:43:23,280 I hope you guys enjoyed. 1136 00:43:23,280 --> 00:43:25,230 I'm going to make a AceLdr public 1137 00:43:25,230 --> 00:43:26,280 right after I walk off stage. 1138 00:43:26,280 --> 00:43:28,181 But thank y'all for coming. 1139 00:43:28,181 --> 00:43:31,014 (crowd applauds)