So, welcome to the 12 o'clock talk on avoiding memory scanners. Let me introduce Kyle. Kyle, it's all yours. Thank you. Alright. So, first we'll do a quick introduction. Like I said, my name is Kyle Avery. I'm currently the offensive security lead at HEB. Before that, I was a red teamer and penetration tester at Black Hills Information Security. Most of my personal research and projects focuses on post-exploitation. So, this talk is all about Windows, but I've also been kind of branching into Mac as well more recently. At the bottom there, that's my Twitter, Kyle Avery underscore, and my GitHub, Kyle Avery, so feel free to give those a follow. So, if you follow any of the sort of InfoSec Twitter and especially the offensive security red teamer Twitter, you've probably seen tweets like these from Dom Chell and Chetan talking about, they're commercial command and control frameworks. And so, they've recently in the last year or so started selling these tools that have lots of awesome features, but one of them that really stood out to me was this ability to bypass tools like PE Civ and Moneta. And so, these tweets would come out and the comments are filled with people asking, how do you do this? And even the developers of the scanners asking for maybe some insight into what they're doing so they can start trying to detect it. And so, that really piqued my interest and I started kind of doing some research to figure out what they might be doing, and that's what sort of led me to this talk. And so, one thing, when I was at Black Hills and I started looking into this, we really heavily used Cobalt Strike, and I'm sure that that's true for a lot of other red teams and just even penetration testers maybe. And so, all of the work that I've done is sort of made to work with Cobalt Strike. It's not specific to it, it doesn't necessarily use any unique features. And so, you could take a look at it and say, hey, I'm going to take any of the techniques that we're going to talk about and the code that we're going to talk about and port it to something else pretty easily. But it's all going to be about Cobalt Strikes, specifically because that's what I and a lot of my peers are using. And as sort of an added benefit, Cobalt Strike is going to be one of the most heavily targeted tools by scanners. So, between red teamers and actual threat actors lots of malicious groups or simulating malicious groups are using Cobalt Strike. 18 00 our rules are heavily targeting Cobalt Strike, maybe more than some other tools, and so any bypasses that we have might be more effectively demonstrated if they're used with Cobalt Strike than with something else. So the link there, that's for a tool that I wrote called Ace Loader. It's going to be sort of the combination of everything I'm talking about, and I'm going to make it open source right after this today. So like as I'm walking off stage, I'll change that on my phone. Thanks. So just a quick agenda. First we're going to go over how do memory scanners work, and specifically we're going to talk about three really notable capabilities that they all kind of share or have some overlap of. Then we're going to talk about how to bypass each of these, each of these techniques, how to bypass specific scanners, and then finally at the end I'm going to demonstrate my tool, and then I'll open source it for you all to go look at. Okay. The first technique that I want to talk about is pattern. So pattern matching or signature scanning is probably the most well-recognized feature of something like antivirus or even a lot of open source tools because it's probably the easiest thing to implement and to get, you know, just easy ways to detect malware. Once you have a piece of it and you can sort of signature it, it's pretty easy to reuse a rule like this. And so the most popular open source or public tool for this is probably Yara from VirusTotal. Yara, you can see on the side there I have an example. Yara is a very popular tool for this. It's a very popular example of one of their rules. They have abstracted a lot of the complexity of scanning things, whether it's memory or processes on disk, and given you this sort of format that you can write rules in where you define bytes and strings and you use this to build these conditional logic statements to have some pretty dynamic signature-based rules. Then there are all these tools that sort of implement Yara, whether it's they're just sort of using it or they're maybe implementing some subject. So I'm going to show you a little bit of a demonstration of that. So let's start with Yara. So Yara is a key component. It's a set of features. So one that I like to call out in particular is Beacon Eye. This is one of the first Kobalt Strike tools that I saw, or I see the tools that came out to detect Kobalt Strike specifically that I saw. So Beacon Eye from Ethical Chaos, this actually uses Yara itself, and it uses Yara to detect the Kobalt Strike configuration. So when Kobalt Strike initializes, it allocates a memory and it writes its configuration there so it can keep reading it back or maybe modify it dynamically to check, you know, what it should be doing and how it should work. There are also commercial security products that are using Yara. So I did a quick Google search for Yara EDR, and I found Carbon Black and CrowdStrike specifically mentioning on their public websites that they use Yara. There are undoubtedly other vendors that do this, and I just didn't find in my quick Google search, or maybe don't mention it publicly. And then there might be vendors that have something similar, and it's not Yara, but they're doing essentially the same thing, right? And so all of this is pattern matching. And pattern matching is traditionally kind of easy to bypass because you just modify the part of your malware that's been signatured. But if you're already using it, and then someone writes a signature after the fact, you'd have to sort of pull that back and then redeploy it. And so what this allows you to... And so a bypass for pattern matching could be temporary, right? Where, you know, you just change the malware in a way that it doesn't get caught. But we'll talk about what a more sort of permanent bypass might look like as well. So I've got just a quick demo here. If I can get this to... Okay. Okay, so on this box, I've got two command prompts running. One of them has Cobalt Strike injected into it. The other one does not. I've got this rules.txt, which is just a collection of Yara rules. And you can see I scan these. The first one, it gets no results because Cobalt Strike isn't there. But the second one I scan, I get all kinds of hits for different components of Cobalt Strike that are in the memory of that process. So just a quick, you know, a demo of what that looks like. All right. So the next thing I want to talk about is so-called memory IOCs. And you might be thinking, okay, well, these are all IOCs. That's the whole point. And I kind of agree, but this is just the most common term that I hear used. You could think of this as memory attributes or, I guess, memory indicators. I don't know. But basically, what all of these tools are looking for are suspicious attributes or suspicious settings on the memory itself. So memory can be executable, readable, writable, or some combination of those. Okay. So looking for memory that's maybe executable might be an indicator that there's malware there. It's a very vague indicator. But that's, you know, malware probably needs to execute. So that's one thing that you could look for. You combine that with looking at the difference between image commit and private commit memory. So image commit memory is when you load a DLL or an EXE from disk. That's going to be image commit, whereas private commit is where the program is dynamically allocating memory. And so if you have private commit memory, that was dynamically allocated, and it's executable, that's a little bit suspicious, right? Typically on Windows programs, when they want to execute new code, they load some DLL from disk. There are exceptions to this. We look at such as the .NET Runtime or even web browsers, which are using JIT. So that might have some private commit memory that's executable. So it's not a foolproof thing to look for. But again, they're just tools that help the analyst kind of figure out whether or not there might be malware somewhere so they can keep investigating. So we've got tools like Moneta from Forrest.Org, which does look for the private commit memory and executable permissions. It also looks for PEB image bases or even threads where the start address points to private memory. So even if it's not executable when it scans, if it looks at that start address and it's private commit memory, that's a bit odd. We have PESIV, which can actually scan non-executable or even inaccessible memory, like no access protected pages memory, to look for patterns. So, PESIV doesn't use YARA, but it is sort of a pattern matching, or at least part of it is, where it can look for bytes that look like shellcode or look like maybe especially Cobalt Strike or even XOR, we'll talk about that a little bit later, XOR shellcode. It also checks the return addresses, though, of all threads and looks for private commit memory addresses in the return address. The last one I'd like to mention is Malfind, which is from the volatility forensics framework. Malfind is similar to these, but it's specifically looking for private commit, read, write, and execute memory, which is a little bit more limiting than something like Moneta, and you can't run it live on the system, and so you have to take a forensic sort of memory dump first. So, taking a quick look at what the Moneta output might look like, you can see there at the top, I've allocated three sort of sections of memory, and they're all 444 kilobytes. One of them is page read write, one of them is read execute, the other one's execute read write, and so you can then say, you can see that screenshot I've got of Process Hacker looking at the three regions of memory, and when I run Moneta there at the bottom, it creates two alerts for the RWX and then for the RX memory. And so, again, it's looking, it sees private commit memory because it was allocated, and it says, this is executable and private commit, you should take a look. So, we've got a quick demo here. I've got my same two command.exe processes. One has killable strike, the other one does not. I'm going to run Moneta on the one that doesn't, and you can see scan completed, there's no alerts. I run it on the one that does, though, and then I get the two alerts for the thread with the non-image memory, and then one for just private executable memory. I can do the same thing with PESIV. So, I'll scan the benign command.exe first, and then I will scan the one with killable strike, and you can see now it finds two results, and it says it found implanted shellcode. And so, these tools are looking for different things, but they're both looking at these sort of memory attributes to figure out where they should look more closely for abnormal data in memory, potentially. The last capability I want to talk about is this idea of stack tracing. So, the first two tools, beacon hunter and hunt sleeping beacons, are essentially the same, at least in the context we're talking about, where they're looking for any thread that is sitting at a state of execution delay. And this will generate a lot of false positives because lots of things use the Win32 sleep API call, but it will also find a stock cobalt strike and a lot of other stock command and control frameworks because they all sort of work the same way, where they call out for an action, and then they execute it, and then they sleep for some duration of time. And so, during that sleep time, which is the majority of the time the implant is active, it will get caught by these two tools. The last one here, malmemdetect, is from Waldo IRC, and this is a really interesting one, where basically he has a DLL that you will load into a process, hopefully before it's infected with malware, and it will hook certain functions. So, internet connect A and connect W, NTWAVE for single object, and RTL allocate heap. It will hook these, and when they execute, before it allows that to run, it will actually check the return address, similar to I mentioned PECIV does, but this is actually doing it at execution time, not just when you run the scanner. And so, if internet connect A is executed, and it's being called by shellcode from some private commit memory, then malmemdetect will flag it as suspicious. So, what I've got here is actually the COBOL strike console, and what I'm going to do with this is I'm going to inject the malmemdetect DLL into this command prompt that I highlighted, and you can see to start, there's nothing on my desktop. I'm going to load malmemdetect into the process. Once I do that, I can go ahead, and look at the log file that gets graded, and this tells me that malmemdetect loaded successfully, and then once this is done, I can actually inject the process with a COBOL strike beacon, and so I'll get my COBOL strike agent running in there, and then I'll look at the desktop again, and there's this detected log, and you can see it sees all these suspicious malloc, and internet connect calls, and so it's definitely seeing COBOL strike, or at least something sort of suspicious that the analyst should look at more closely. All right. Now that we've talked about these three capabilities, I want to get into how we might bypass the memory standards themselves. So each scanner, we can bypass it, and it requires, at the most basic level, some combination of encryption and spoofing, and you'll see what I mean by that. It's sort of different depending on the context, but one thing I want to note before we move on is that when I talk about a bypass in this talk, I'm not looking to generate a bunch of false positives and confuse an analyst. I'm not looking to blend in with existing false positives. I want to run the scanner and have zero results. I want it to look essentially the same as it did before I injected COBOL strike, and so I don't want there to be anything to cause alarm. The other thing I want to note is that when I talk about memory scanners, I'm not talking about commercial security products. So I mentioned earlier Carbon Black and CrowdStrike. These tools maybe have some overlap with memory scanners. They're looking at some of the same things, or maybe a lot of the same things, depending on the product, but they're not looking for, they're looking for all of the same things. And so being able to bypass every memory scanner does not mean that you're going to bypass every EDR product or antivirus. And likewise, being able to bypass EDR doesn't necessarily require bypassing all of these memory scanners. A lot of these are looking for things that are more intensive or require too much resource for a live product to run. And so I just like to make that note so that people don't think that, you know, I'm bypassing a memory scanner because I'm bypassing this product, I should be bypassing this product because I'm bypassing these scanners. So I mentioned that we're going to be encrypting data for, to make this work. And so we got to talk about how do we want to encrypt things? The first thing that came to my mind was Single Byte XOR. Single Byte XOR has been around for a million years, and it's really simple to implement. It doesn't cause a huge performance delay, and it's just relatively easy to use. It's pretty straightforward. The problem with Single Byte XOR is that tools like Yara and PESIV, their pattern matching can actually detect Single Byte XOR. So Yara has a modifier that you can use on byte arrays where you can tell it to try every Single Byte XOR possibility. PESIV uses a technique that looks at the null bytes encrypted with XOR to actually see or detect Single Byte XOR encryption. And so then you might be thinking, okay, well, I'll use multibyte XOR encryption, or I'll use AES or RC4. But all of these, you'll see in a couple slides, have problems because they require us to allocate and then execute code in memory. And so anything that we can do where we don't have to write our own code is going to be preferable in a couple slides. So the solution here is this system function 032. This is something that I first saw in Mimikatz, actually. So I put that screenshot there. You can see he's commenting these as RC4, and he calls them RTL encrypt data and decrypt data. But really what these are, are they're built-in operating systems that you can submit a memory address and a size and an encryption key, and it will go and encrypt it with RC4. And so we don't have to write any RC4 code. We don't have to do anything like that. It will take care of all of that for us. So what do we want to encrypt with this? Well, the first thing is we want to encrypt the heap. I mentioned earlier that Cobalt Strike, when it initializes, it dynamically allocates some memory and then it writes its configuration there. Well, that is all on the heap. And so the heap is a data structure, if you're not familiar, where things like malloc and other dynamic memory allocations go. So the first demo that I saw of this was, again, from Waldo IRC. It's called Locked Eggsy Demo. So this is a proof of concept that will try and encrypt right before the beacon goes to sleep. It will try and encrypt all the heap entries in the process which aren't busy. So it checks every single heap entry and says, are you busy? Are you being accessed? And if not, it will encrypt it. I've seen some trouble with this because maybe the beacon is sleeping and it has encrypted something. That was not busy when it went to sleep, but then during the sleep time, the process needs to access that memory and it can't. And so there's a little bit of risk here, but overall it works pretty well. Shortly after that, I came out with a proof of concept to allocate a secondary heap. So I create a brand new heap that is different than the process's original one. And I tell Cobalt Strike that I want it to, anytime it's going to allocate memory, I want it to use that heap instead. And that allows me to essentially do the same thing as Waldo, where I'm going to check if things are busy, which they really shouldn't be if I'm about to go to sleep. And then I can encrypt them. And nothing that the host process is doing should be on there. And so I don't have any risk of impacting something that might need to get accessed while my agent is sleeping. The last example is actually from the official Sleep Mask Kit that is part of Cobalt Strike. So Sleep Mask Kit is one of the sort of extensions that you can download if you have a Cobalt Strike license that allows you to encrypt certain things that sleep, one of them being the heap. And so Cobalt Strike will actually give you just a big list of, here's all the memory addresses of heap entries that I've allocated, please encrypt them. And so this is actually a pretty nice setup because you're not creating a secondary heap and you're not worrying about damaging entries that are allocated by the original process. You're only going to encrypt things that Cobalt Strike itself allocated. And so this is something that's specific to Cobalt Strike and requires you to use their Sleep Mask Kit. Which you'll see in a few slides why I don't necessarily want to do that. But, so let's do a quick demo here. I've loaded my heap encryption that I talked about where it allocates the secondary heap. I've got my beacon here already running. I'm going to, you can't see this, but I'm just saying spawn. I'm going to launch a couple extra beacons. And so these will all call back real quick. And then once those are all started, we're going to go over to the Windows box and we're going to run beacon eye, that tool I mentioned earlier that uses Yara. And it shouldn't give us any results now because we've loaded that aggressor script which instructs Cobalt Strike to encrypt, or to create that secondary heap and then encrypt them all. And so you can see, okay great, it does not. So that's the first thing, is getting past those sort of Yara rules that look at the heap, right? Now that we've done that, we want to look at Yara rules that target Cobalt Strike itself. So Cobalt Strike, yeah sure, it allocates some dynamic memory and we want to encrypt those things. But there's also the entire implant itself that we're using in memory, that there are plenty of Yara rules, almost all those Yara rules that I have in that text file are for that itself, not for things it's going to allocate. And so being able to consistently evade all of those Yara rules and tools like Moneta and PESIV is going to require us not only to encrypt all of the data associated with our implant, but also put it in non-executable memory. Because if you remember, tools like Moneta are looking for any executable private commit memory regardless of what signature, it's only looking for is there suspicious memory or threads pointing at suspicious memory. And so the nice thing is, and I've kind of hinted at this a couple of times, the way that these frameworks work is they will call out, get an instruction, do whatever that they're supposed to do, and then they will sleep for these long periods of time, and traditionally your sleep is much longer than the execution takes, and so for a majority of the time the implant is on a computer, it's sleeping, it's not doing anything. And if the implant's sleeping, there's no reason we can't encrypt all of it and make it non-executable, we just have to find a way to do that. I mentioned before that when we write our encryption code, before I talked about system function 032, that we wouldn't want to implement our own encryption routine. And the reason for that is this, we want to evade tools like Moneta, and if we have an encryption routine that's sitting in executable private commit memory, that's going to get flagged, and so our beacon might get ignored, but that will get caught anyway, and that will change in the actual indicators on the host. So first we can talk about this stub where we have some executable code, which is not preferable, but it is an option. And so first of all we have the sleep mask kit from Cobalt Strike, and this is why I don't like to use this for the heap encryption. The whole reason is because if we use this, we have to leave that executable. And so if we leave that sleep mask, sub, which is just like a small section of memory that we leave unencrypted and executable, if we leave that there, then that's going to get caught by Moneta anyway, and potentially caught by YAR rules, and we've seen they've already had YAR rules come out that look specifically for the sleep mask kit or even parts of it that you can't change. And so this does maybe hide some of the indicators, but it doesn't hide them all, so it doesn't really solve our problem. The other option we have is this project shellcode fluctuation from mgeeky, and this is very similar to the sleep mask kit stub. All this is doing is it makes the memory inaccessible or nonexecutable, and it doesn't change it back, and so when the execution continues, it will try and execute nonexecutable memory, and it will generate an error. But before all of that, it registers a vector exception handler, and so when that error gets generated from trying to execute inaccessible or nonexecutable memory, it will go to the exception handler, and that exception handler has to be executable for it to function, and then it will sort of fix the memory and resume execution. As I said, it's implemented differently, but you're going to have the same issue where you have to have some executable memory no matter what. And so again, it doesn't really solve or it's really not a true bypass in the way that I want it to be. The next thing we can look at is using ROC. And so if you're familiar with exploit development, you've seen return-oriented programming as sort of a popular way to get around DEP, but in this case, we can actually use it for changing memory permissions. So the first proof of concept that came out, as far as I'm aware, was from Josh Lospinoso. It's called Gargoyle. And Gargoyle is a proof of concept. It just launches MessageBox, and it's 32-bit. But the whole point of this is that it demonstrates using ROC to queue up these different APC calls that will... You could implement a sleep routine, but he's just doing a MessageBox where it will do something while the rest of the code is not executable. So we came out with You May Passer, which is a x64 implementation of Gargoyle that is ready to use with something like Cobalt Strike. So it's not just a proof of concept. It's something you could use right now. And just after that, the link, or VF link, came out with Deep Sleep, which is very similar to Waldo's project. I think his is more of a proof of concept, but it just doesn't use APCs. And so all of these are pretty awesome because they solve our issue of needing executable code to do things. So to encrypt our data and to change the memory permissions, now we're at a point where we can actually have, during sleep, this sort of chain just waiting or slowly executing to perform all of our obfuscation on the code itself. The problem with ROP, and if you've done exploit development, you've probably run into this, as Windows updates or as you try and switch to different versions, the gadgets that you're calling may not exist in the process. You might not be able to find it, and now your project doesn't work, or you have to come up with some change for it to work, or maybe load a new library. And so these work, and they solve the problem, but they're a little bit of a headache because you have to kind of keep on top of them as new versions come out. Now, what is sort of the solution to this is this project from Austin Hudson. So this is called Foliage, and Foliage is a proof of concept on GitHub that is similar to Gargoyle, but instead of using ROP, instead of trying to find gadgets, it's going to use this API called nt-continue. And nt-continue is really awesome because it's traditionally used for exception handling, but what its purpose is is you pass it a context. The context defines what all of the CPU registers should be, so you tell it, here's what the instruction pointer should be, here's what all of the general purpose registers should be, here's what the stack pointer should be, and it will go and change the thread to have all of that information. And so this is almost like you're performing ROP where you can sort of define what the whole context should look like and execute whatever you want with an instruction pointer. And so what Austin did is he came up with a way to queue a series of these asynchronous procedure calls that one at a time executes nt-continue passing it a different context. So first you'll execute nt-continue to do maybe your obfuscation, and then you'll do it to change the permissions, and then you'll do it to sleep, and we'll talk about exactly how this works on the next slide. So the sort of sleep chain, how this works, before it executes, it's going to open a handle to this driver, ksecdd, which is a driver that you can use for encryption. It's an alternative to system function 032 that you could use. It's already on the computer and you don't have to write your own encryption routine. Then it's going to open a handle to the current thread so that it can, during the sleep process, modify its context, and we'll talk about why exactly he does that in a bit. Then it's going to create a brand new thread, which is going to sort of hold this apc queue. It creates a new event, which we're going to use to keep the thread from exiting. It's going to copy the context of the new thread to this brand new context structure, which we're going to reuse. Then it's going to queue this series of apc calls to nt-continue. So the first call is going to be just waiting on that event, which keeps the thread from exiting. Then we're going to change the memory permissions of our entire beacon to be read right. Then we're going to tell that driver to encrypt the memory. Then we're going to save the context of our original thread so that we can restore it. We're going to set the original thread context to this new fake one, and this is actually going to be one of the options we can use for bypassing some of the stack tracing, so we'll talk about that in a few slides. Then it's going to sleep. It uses nt-delay execution. It waits for the number of seconds that the operator specified. Once that's done, it will instruct that driver to decrypt the memory. It'll then restore the original thread context, change the memory back to executable, and exit that new APC thread. So it queues all of these up. It hasn't actually done any of this yet. It's just queuing these up in that new thread. Once that's done, it forces that thread into an alertable state. This is important for APCs because they have to be alertable for an APC to execute. So it forces it into an alertable state, and then it signals that event and waits on it so that the original thread, while this is all happening, the original thread doesn't exit and doesn't do anything else. One thing that I sort of glossed over here is that all of these are going to return to NT test alert. And NT test alert is another API call that you can use to make it alertable again, and so this is what keeps the chain moving. So everything executes, it returns to NT test alert, which then makes it alertable again and executes the next item in the chain. Just recently, there's a project called Echo from C Spider, and this is actually based on some reverse engineering of one of the commercial C2 products that I mentioned in the beginning. But the way that this works is very similar to Foliage, except instead of queuing APCs with NT queue APC, it's going to use create timer queue timer, and so very similar, but it's going to use timers to queue these instead. There are some limitations on the number of arguments you can pass and things, but overall it's approximately the same. But it's just an alternative that you could use that still uses this NT continue as what it's queuing, and queues context. It just doesn't call it with NT queue APC. So we can do a quick demo here of Foliage, I'm going to look at my two command prompt processes. I'm going to inject Cobalt Strike into one of them. Then I will run Moneta on it, and you can see I get no results from Moneta. I'm then going to run PESIV, and same thing, I'm not going to get any results from PESIV. Now, just because of having Foliage there. But you can see my beacon is definitely here in 6460. Alright, so the next thing we want to do is avoid sleep. And what I mean by this is if we want to bypass some of these stack tracing capabilities, like hunt sleeping beacons, we have to avoid using NT delay execution. So even Foliage, which bypasses tools like Moneta and PESIV, as it is on GitHub, is going to get caught by hunt sleeping beacons. Again, these generate lots of false positives, it's not a great indicator, but it is something that I'd like to avoid. There are a couple ways we can do this that just don't use sleep or sleepy X or NT delay execution. We could use our own code that sleeps, but that runs into the same problem where we don't want executable code. The other thing we can do is use timers again, and you can see there at the bottom, I've sort of shown you what that might look like. The problem with that is you have to allocate three different you have to use three different API calls to do this, and so when we start talking about ROP chains, that makes it much larger maybe than it needs to be. The last option here, just using wait for single object is I think the best. You pick something that isn't going to become alertable, maybe the original thread that's sleeping, because we're not doing anything with that. We wait on that, and then we use wait for single object's timeout parameter to sleep. This allows us to effectively sleep without using hunt sleeping beacons or NT delay execution. It allows us to sleep without using NT delay execution and then not get caught by hunt sleeping beacons. So I've got a really simple proof of concept here where I've just hooked sleep and replaced it with wait for single object. I'm going to inject into 5296 here. And then we'll go ahead and run hunt sleeping beacons, and you can see, I think I highlighted here, maybe not, but it finds zero threads. The output's kind of verbose for that, but it does not find anything even though I have my beacon in 5296 sleeping and executing on system. Okay. Next we want to talk about return address spoofing. So I talked about tools like Moneta and Malmemdetect which try and look at the return addresses, or rather not Moneta, PECIF and Malmemdetect. Excuse me. Which look at the return addresses. And so there's two ways that we can do return address spoofing, and this is a really important difference actually, looking at return address spoofing at rest versus return address spoofing at execution time. So return address spoofing at rest, I don't necessarily think there's a ton of value here. All you're really getting out of this is bypassing something like PECIF, which is looking at the return address when it scans it. And so from a security product point of view, security products don't tend to scan processes to look at their return addresses, but PECIF does and that's our goal. So this is something we want to do. The first option we have is another project from Mgeeky called thread stack spoofing. This will just overwrite the return address with zero during sleep, and this causes the stack to get truncated. There are some scenarios though where this is going to leak arguments on the stack, and so you will generate IOCs in those scenarios, and again it just depends on a couple of variables that we're not going to go into. The next option is a little bit simpler, and it's just using this set context API, which was already demonstrated in Foliage, to copy a fake context where we specify a different return address, and we copy it over our thread during sleep. And so once we do this, if it scans it, it's going to see whatever we put there, which could be an API call to a memory address that is in private command, just some API call in a normal DLL, and so it won't flag anymore. So that effectively solves that. It's a pretty simple solution for this. When we talk about return address spoofing at execution time, this is where it gets a little bit more difficult. So just about a month ago, there was a project called call stack spoofer from Will Burgess, and this is a proof of concept that is really interesting, where it will actually copy a full stack unwind from just something on his test machine. He sort of hard coded these in his program, and so when the thread is sleeping, it will copy that entire stack over, and then when it's done executing, or excuse me, when it's done sleeping, it will start trying to execute those things, and at some point will error, even though it's a valid stack at some point, it will error because it doesn't have the right things loaded, or it can't resolve the addresses. But before that, again, he's registered a vector exception handler that will catch this, and so he can store the old stack once that happens. The other option here, which I think is a little bit better for our purposes, is just called x64 return address spoofing from Namazo, and this is something that's been on the internet for a long time. Excuse me. It's been on the internet for a long time, and essentially all it's doing, and we're going to go through how this works specifically, but all it's doing is it's storing a ROP gadget as the return address. And so while it's executing, this ROP gadget is going to sit in the return address, and so if you look at the stack, it's going to look like it's doing something legitimate, but we're actually executing our code. So how does this work? Well, first we need a sort of wrapper program, and the wrapper program is just, you know, our malware. So our loader for Cobalt Strike. It's going to, first it's going to have this structure here, which has a trampoline spot. It's got a spot for the target function, and it's also got this spot called rbx, which is we're going to use for data storage in the actual shellcode in a second. Then we sort of just cast this, the shellcode itself, we cast it as a function, and we pass it whatever arguments. So it's a little bit messy here, but you can see me calling sleep, and I'm passing it five seconds, 5,000 milliseconds, as well as that parameter structure. This also works for larger functions that require more arguments, and so you can see here, I'm passing it, I think this is five arguments for write process memory. But once you call that, once you've done that cast, and you've called into the shellcode itself, we're going to go through how this works specifically as well. So first thing we want to do is just save the original return address. We want to move that whole data structure with our gadget and the trampoline, excuse me, the trampoline gadget and the intended function. We're going to move that into rax, and we're going to put the jump rbx gadget as the new return address. So this is where the spoof happens, at that last line there, or excuse me, yeah, at that last two lines there, rather. Where we're storing that gadget in r10 and then we're moving it into the stack pointer. Then we're going to move the intended function into r10 and we're going to preserve the original return address and the rbx value, the original rbx value so that we can restore those when we're done. Then we're going to move this fixup function that we'll talk about on the next slide into rbx. And this is important because since jump rbx is on the stack, at that last line, we're going to jump to the intended function, so we jump to sleep or we jump to write process memory or whatever it is we passed here. We're going to jump to it, and when it's done, it's going to return and the return address is jump rbx. And so whatever's in rbx, in this case our cleanup function, is what it's going to jump to. So we move here, and we can see it jumps to the fixup structure. All this does is it sort of restores the original rbx, and then it jumps back to the original return address that restores execution. So all of this combined may be a little bit confusing in this presentation setting, but all of this, if you look to the code, it's maybe more cohesive. And what it's doing is it's storing that jump rbx on the stack, it's executing your function with a jump to it, and then when that returns, it's going to return to your gadget, which in rbx we're storing our cleanup, which gets us back to whatever called it. And so effectively, we bypass tools like malmemdetect with this, and I'll show you that here. So we list our two command prompts again. We're going to inject into 8568. We see there's nothing on the desktop right now. When we load malmemdetect into 8568, we'll see our log gets created on the desktop, which just tells us that malmemdetect loaded successfully. And then we'll inject our beacon into it. And then once that's done, we'll try and look at the log for the detection, but when we run this, we get the file cannot be found, because there's no detection log for this. But we look, 8568 is definitely beacon-engaged. And we just haven't generated anything there. Okay. So all of that said, the last sort of part that I want to talk about is aceloader. So aceloader is the tool that I wrote. It is able to bypass all of the scanners that we talked about, so peciv, moneta, malmemdetect, all of the cobalt strike yara rules that I have or could find anyway. It also bypasses there was a tool that came out after I submitted this talk called patriot, which was made to detect foliage specifically from Joe at elastic. But it will bypass patriot as well. I got that a couple days ago. All you have to do to use this if you're a cobalt strike user is you download the bin or you build it yourself and then you import one script and any shellcode that you generate will have all of the capabilities that we're talking about. It encrypts everything that it encrypts. It uses system function 032 for. It's going to use the technique that I mentioned where it creates a new heap and then allocates things there to encrypt them. It's going to use foliage to obfuscate the memory permissions and encrypt the actual beacon code. But it's going to delay execution with wait for single object. And finally it's going to perform the return address spoofing that I talked about for internet connect A and W for NT wait for single object and for RT allocate heap which are all the things that malmemdetect looks for. So I've got just a demo here of kind of using aceloader. Well look we've got our command prompts. We've got three of them and you will see why. We're going to use that 7676 at the end for malmemdetect. But we'll inject into 9108. We'll give this a second here and it will get our callback. So we have our beacon now. Then we'll go and start trying to scan it with different tools that the analysts might use. So the first thing I do here is I just list out. Here's all the YARA rules just so you can see that there are a good number of them at least. We'll go ahead and scan it with YARA. It calls back but there's no output from that because it didn't find anything. We'll run hunt sleeping beacons and you can see we've got found zero threads. We'll run moneta targeting it and we get no alerts there. We'll run PESIV looking at it as well and when this finishes you'll see there's zero findings here. We'll go ahead and look at our command prompts again and this time we're going to use the 7676 so that we can inject malmemdetect into it before we do anything. We'll look at the desktop real quick. Once that calls back you'll see there's nothing on the desktop. We'll load malmemdetect into it and we'll make sure that it loaded successfully by reading that text file. Okay, we see it loaded. We've got all the output from it. We'll go ahead and inject into that process now. We'll wait for it to call back. I'm going to zoom in here. Okay, we got our callback from 7676. Then we go ahead and scan it with malmemdetect here. We try and look at the detection log from malmemdetect and we see that we have no file specified. So it has definitely not been detected there. We jump over to the box. One last thing and we're going to look at we've got all the same command prompts 7676 9108. We run beacon eye and it finds no beacon processes. It can't find any data on the heap that leads it to believe there are configurations there. So some final notes. I talked about the DLL loader and again it is specific for cobalt strike if you try and use that with another command and control. I mean first of all you wouldn't be able to import the aggressor script but even if you just try to use it as a reflective DLL loader it may or may not work. I haven't tried it with anything else but it's really tested and made for cobalt strike. But these things and the proof of concepts that I talked about can all be used for just about anything. If you wrote your own malware implant or if you prefer some other framework there's no reason you shouldn't be able to do this especially if it's written in English like C or C++. If you have like a C sharp implant you might have problems because there's some like JIT memory being allocated that might cause you issues but if it's just a C implant like cobalt strike you're not going to have problems there. The techniques we talked about bypass existing scanners. I already mentioned that that tool Patriot came out a couple weeks ago and that detected it because it was looking for foliage specifically. So there's no guarantee that you're going to evade these things forever. The goal was to look at these really established scanners like PESIV and even Moneta and all of the YARA rules that are being used more commonly and don't tend to generate a ton of false positives. So looking at these things and figuring out how can we generically bypass these without just breaking small signatures. All that being said there's no reason to believe that there's not going to be another scanner that comes out that detects one specific part of something we do maybe. But that being said I might try and come up with a bypass for it as well. I also left out some scanners and also some bypass techniques because they were meant to specifically target really specific things. Let's say we had a YARA rule that detected Cobalt Strike and someone wrote a tool that just changed the bits that that YARA rule was looking for. I'm not going to include that in my section about bypassing patterns. Because in my mind that's a bit fragile and so we want something like encryption and I didn't specifically mention this but AceLoader, every time it's going to sleep it just generates a brand new encryption key and encrypts everything. And so you can't just look at okay where's the key stored or let's look for some bytes once they're encrypted because they're going to be different on every computer every time it sleeps just by design. And so that is everything I had to talk about. I hope you guys enjoyed. I'm going to make AceLoader public right after I walk off stage but thank you all for coming.