 So, next, um, I'm gonna make the same joke I did earlier. Don't care. Uh, how many people here use antivirus at work? How many people think that antivirus is worth a shit? Oh man. CISSP over here. How many people have said, well, I'll solve this problem, I'll get an EDR, yeah? How many people think the EDRs are worth a shit? Ah, sucker. Time to learn about how EDRs may not be as effective as you think they are. Let's give Nomad a big round of applause. Had a great time, man. Thank you. Appreciate it. Hello Defcon. And today we're going to, well, my name is Dimitri Snashkov. And a couple words about what I do and who I am. Just because it is applicable to our talk. Um, Red Team Operator helped my team execute the testing efforts. Um, sometimes create tools. Sometimes release them. And so because this talk is going to be from the perspective of Red Team Operator, um, I want to set some stage before we go dive into details. Um, I think that Linux matters. I think that it runs a lot of payloads in the cloud and elsewhere. And I do think that, uh, attack and offense actually tries to get there as fast as they can by passing office networks, dropping there through applications. And I do think that the defense follows the attack. And as such, we start seeing as operators, we start seeing a lot of presence of EDR on Linux. And so what is EDR? Endpoint detection response, right? And we as operators are supposed to kind of respond to that by stress testing them and seeing what they can do. So it's a story, right? It's a story of us getting onto the Linux box time and time again and being caught. Fifteen minutes, ten minutes. What happened? Two, three years ago it wasn't the case. We knew exactly what we were doing there. Now there's this fancy thing called EDR. But we can't really define what it is. Is it a pure play EDR product? Is it a side gig for whitelisting applications? Is it a DLP? Perhaps it's maybe some homegrown scripts, right, that catch us or some form of other manual or tool assisted, uh, threat hunting. And so when we drop to the box, we do not know what it is. On top of that, we have to address initial foothold. Let's say our exploit worked, we got there, but so what do we do? How do we maintain presence there? Our activities may be logged, supervised, right? We need to stay there for a while. It's not a fifteen minute job to establish a foothold and basically compromise anything else in that network. We have to persist. While we're doing it, we're supposed to evade automation that is definitely watching over our actions. And maybe even deflect the artifacts that we brought in into that environment. On top of that, we may be in a position that we are in quiet boxes and defense actually knows what they run. White listed binaries, processes are quiet, right? So we are the anomaly. There are two sort of ways of, uh, tackling our issues strategically, right? It's an operational evasion where we shut down the EDR, blind it in a way, you know, maybe we're confusing it from the operational perspective. And you guys really need to check out the talk that Timson and Ruth Killa has done this morning for that. Here we're gonna take a look at the behavioral evasion, right? So what does that mean? We are gonna try to take the execution of our programs and we're gonna confuse EDRs from that standpoint. We're gonna try to bypass them from the behavior of our, uh, cradle, payload, bootstrap, whatever the case may be that we're gonna talk about. And then we're also going to try to deflect that artifact discovery that we've been talking about. Alright, so what are the objectives strategically? Well, we know we need to, uh, we need to evade detection at runtime. That's, that's a given, right? Somehow we need to serve their payload, our payloads in such a way that they're either undetectable or maybe easily sort of, um, you know, they're, they're created in such a way that EDR doesn't know what to do with it. Strategically there are three choices. We can drop our tools right on the box, but that may not work because they may detect our, our, our programs, our malicious payloads right there. We can start developing offensive tools right on the box, but then we have to make sure that we have the development facilities. We have to have compilers. Maybe we can have some tools on the box themselves to, to compile all that. Also not ideal. And the third choice is fully living off the land. Utilization, right? We take what we're given and try to work with it, but then again, we do not know where we are, how quiet the box is, what is whitelisted, are we going to find what we can rely on to extend and maintain our foothold? And so maybe there is a way to do an assemble attack, right? It's a blended approach that has a couple of ideas. The first idea maybe we can bring in small malware cradles that are not malicious in nature. They're just bootstrap code that gets loaded with malicious code at runtime as it runs. And so EDRs, they're building the story of consistent execution of a program is not going to be able to do that. Or maybe we can interject into that story and then build the iterative capabilities by loading our cradle with a malware. The second idea is probably more powerful, depends on where you are, is to take the whitelisted binaries and essentially turn them into Trojan horses, turn them into decoys of our own actions. The reason why it's powerful is because the whitelisted binaries are there, they're supposed to be, they're trusted. So the story that EDR builds, we're attacking the trust, right? And that's more powerful. And in this talk we're going to talk about both of these ideas how they can actually progress in parallel. So in the first stage, we're going to see how we can actually work with what ingredients do we have to build that cake, you know, to cook it, to bake it rather. And we're going to heavily rely on preloader in Linux operating system for that. We're going to see how we can chain our preloading and then maybe hide some things from the EDR. And last but not least, we're going to talk about the concept of rapid prototyping which is really important. Because of the constraints that we cannot bring our own tools and we have to somehow try to build them on site, rapid tooling prototype is really important for us. In the second stage, we're going to try to weaponize and operationalize the offensive capabilities that we've built. We're going to look at mimicry and decoys in operating system for our own actions and benefit. And we're going to see some other things that will help us persist. So stage number one, let's take a quick trip, you know, down the memory lane into the dynamic linking and loading. Just like in other operating systems, your linker is a tool, set of tools, a framework that allows you to basically assemble your executable with dynamic libraries, static libraries, whatever the case may be, essentially present a consistent view of that binary, right? The loader and linker, they see two different execution views, they have, or two different memory footprint views, right? There is a linker view and there is an execution view, segments versus sections. And linker basically says, okay, well, I'm going to find your dynamic library if you are looking for it at runtime and I'm going to patch it into the executable, I'm going to run relocation of the memory and I'm going to hand it off to the actual execution. In practice, if you're the operator or any user of the Linux system, it looks very simple. When your executable is compiled with dependencies on a dynamic library, if it runs and it doesn't find the dependency, it bombs out and you're given an error pointing to the actual library that is missing. Once the dependency is found and you can do that by various tools available on a Linux machine, you can actually launch it back and everything is going to be fine if your library path is set up right and your dependency is found. And also the other concept is, um, is, uh, elf hooking, right? Used everywhere for malicious and non-malicious purposes to introspect binaries to change its behavior to hot patch a binary. Essentially what it does is you can use the, you can use the preloader to actually find a library that is supposed to be loaded into the memory space of the executable with the feature and functionality that you can introduce into it that is foreign to the execution of that binary itself. And so you can basically say, okay, well, I can take a functionality, I can reroute it. We're breaking the API contract here by rerouting our execution to, to the libraries that we bring in. But there is a problem with that. The problem is that you need to know the API. If library is, C library is known very well, there are main pages for it, the contracts are known, the APIs are known. For example for F open case, F open, uh, API, you know exactly what it returns, what it takes, and how that works. And so when you're preloading the binary with a known F open API, you know how to interject that, right? You can reroute it and interject it. But unfortunately in the black box scenario that we're working in, when we're dropping in the box and we do not know what we are trying to preload, that presents a problem. But for first need to understand what that binary does, we need to trace it, maybe reverse engineer it a little bit, we cannot do it most of the time on the box itself. So what if we are going to be a little bit more agnostic as to the specifics of the API we're trying to hook? What if we are not going to the actual subversion of the target? We're not going to rewrite functionality in the library that we're preloading. But we're still going to compel it to execute our code. How do we do this? Let's look at the relationship that the processes have on Linux, parent and child process. If you're the parent of a process, you likely, let's just say, own the bootstrap process of it. You can introspect it and you can have some formal relationship between the two. And so we can try and deliver the payload generically in a known way by abusing this relationship and trust. And then, you know, the world is your oyster. You can do other things with it. Let's see how that works. But first is just the viability check. Why do we need to do this? Well, if we're taking the two paths, the clean preload cradles, right? And the second path is using the binaries that you find on the disk. You can time the loading of the modules and you can actually work towards blinding EDRs that way. The EDRs may not be able to fully trace your execution if you're taking care of splitting your payload into different libraries using the preloads. And you can abuse the parent-child relationship on Linux and attain your goals that way. What we want is we want to take a target process and turn it into this monstrosity instrumented with our payload, our malicious payload, and also trigger that payload or parts of it when we want to. So let's walk through that process. In order for us to do this, let's turn our attention back into the ELF format. But in this case, we're going to look at it from the offensive standpoint. We're going to take the sections of the ELF and we're going to try to introduce malicious code in it. Well, in the case of a cradle that we're bringing in, it's really easy because we can compile things into those sections. And our compiler, our friendly compiler, is helping us with that by using sections like init array or finny or maybe even as a pre-nit array. Essentially, we can supersede the understanding of the execution by injecting code into the sections that will be executed before your main, right? And so the one curious thing or side effect of loading and linking, I guess, in this case, is that control is given to that shared object that you're introducing through loading before transferring control to the main. So you see what we're doing here? We're basically trying to preload the executable and interject and control its execution before it even starts. Pairing child relationship, maybe. The other thing is we can take a look at things past ELF format. We can look at the library, libc library in Linux operating system. We can actually hook libc start main. The reason why that's useful is because libc start main is everywhere. It sets up the memory, you know, hooks up different things, sets up execution contacts for executables on Linux, at least in many cases. And we can do that, right? By basically hooking libc start main and then looking for a dynamic next function that goes into the original main. By using the dlc and dl open. But that's not optimal. Why is this not optimal? Well, let's go back, actually. The reason why it's not optimal is because EDRs can actually look for dlc and dl open and basically deny your execution. It's very easy to trace and see what dlc is being used and just say, no, you guys cannot load any libraries into this process. Okay. Well, if you, if you, the EDR do not like us that way, what we're going to do, we're going to use a facility called weak symbols. What weak symbols mean is that if you are trying to load a binary with a library of your choosing and you define a function, maybe a global function or some variable that you're exporting from that library. Normally, as we've seen before, when you cannot find a feature or function that you're looking for, your destination bombs out. It basically says, no, I can't continue. I can't find that code. Well, what weak symbols are doing for you is it says, okay, well, if it's not present, just skip it. Maybe it's loaded down the line, but we don't care about that. So if we are dropping in a sandbox and we're seeing, okay, well, do we have a library sitting next to our executable or otherwise found through the library path, we can find it, we'll load it. If it's not there on the sandbox, if we did not, if some, if, for example, incident response has taken our library, but not, has taken our binary cradle, but not the library, then we're not going to launch it. And so this story unravels, right? You can chain preloads and libraries through the weak symbols. You can say if it's present, launch it into memory, it's not, then skip it. That's called controlled weak graphs. There's also foreign weak graphs. Did you know that almost every binary on Linux contains weak symbols? And did you know that you can actually hook them from the library preloading them? CXA finalizing GMO start is a good example. There are others, especially in the, in solutions that deal with, for example, Java virtual machine. So essentially what that gives us is if we're not able to bring our cradles, we can find weak symbols in libraries or executables on the box itself because they're given to us and we're going to take advantage of that. And also I talked about the chain weak graphs. You can actually split the execution of your payload or the payload itself across a chain of dynamic libraries. So when the EDR gets one library, it doesn't see the full picture. That's what we want. Next up is the construction, right? The constructors are very useful when you're coding C or C++ application. You have a way to say, okay, well that's my constructor, you know, so it's a virtual memory for dependencies and all that good stuff. We can take advantage of that. How do we, how do we do this? Well, what we do is we preload a binary with a library that defines a constructor for that execution. So essentially before it gets to the main, we're saying, oops, that's an object. Don't do execution of a main. Instead, run the constructor before you hand it off to main. And the same thing with destructor. Before the binary is, you know, ends its execution, just execute whatever we're given in a destructor. Destructors are powerful that way because you can time the execution of your malware. Nothing tells you to, if you're preloading slash bin slash ls, bin slash, your malware has to run at the outset of that execution. You can run for hours and then when the, well, bin ls is not a good idea but maybe some, some long running process, right? And when you kill it, maybe sending a signal to it or whatever the case may be, this is where you trigger the execution of your malware, right? So now with the constructors, we can do it in a target agnostic manner. We can take any executable on Linux and basically start preloading it in a generic way. And if EDR technology actually knows about that trick and they say, okay, well, we'll interject and we'll just give you a constructor, a default constructor, turns out there are priorities on the constructors. And so if they load at a default priority of 200, what we can do is we basically load it that's at the priority higher than that at one on one, right? And the same thing with the destructor, we will basically patch a different priority to a constructor to override the defense. The other thing that we can do to break that story that EDR kind of builds by saying, okay, well, indicators of compromise are there, you know, are they building a story? Is it a malicious executable? Is it not? Am I going to kill it? Am I not going to kill it? Is to trigger that malware loading through out of bed signals? Not only regular signals, but even exception handling, right? Nothing tells us that we cannot instrument our cradle or preload the the decoy library decoy decoy binary on the system. And then basically divide by zero. That's not a recoverable event in most cases, but we can implement the handler. So what EDR sees as a completely disastrous event and stops looking, we recover from it and we continue running, right? Tips and tricks like that. So you can self trigger your own execution there. And we're actually going to see that coupled with other things later on. And then obviously if you're bringing in your libraries, you can start building user land root kits on it. You can clean your LD preload from your own environment. So if EDRs are looking at your memory space and says, hey, where is the payload? And if they're relying on environmental variables, they're not going to be able to find it. All that good stuff can go in their obfuscation of your loaders, right? Runtime situational checks. Possibly even foregoing the main itself. Maybe you're doing some assembly tricks to basically saying, okay, if EDR is looking for main, I'm not going to have it, or I can rename main to something else, something innocuous. And you can even substitute the actual loader LD.SO on Linux to have your own into the interpreter section. So if EDRs are instrumenting in some way the LD.SO, they're not going to see it executing. Okay, so now we have some primitives to work with, some recipes, some tips. How do we progress further? How do we expand and scale our presence there, right? That's important because we have to have almost all a cart set of tools and primitives in order to bypass different versions of EDRs because we do not know what it is, right? It could be whitelisting technology that we know about. It could be something else. Okay, well, we mentioned LD.SO as a default linker and loader for Linux operating system. What about system libraries and binaries that run other binaries on systems? Well, LD.SO not only runs programs that, you know, that it finds or Lipsy start patches it in, but it can also run directly your payloads, right? And if your EDRs are watching over the regular expressions like what is your process name, right? I'm not going to allow some things that I do not like and I can only do things a certain way. That known good story, that trust has been broken if you are able to preload the actual loader with chained execution of other system binaries on a system that you can find them, right? And that goes into the whole idea of, you know, who gets there first, right? Like are you watching for Busybox? Are you watching for LD.SO? Are you watching for VI launching into the memory, switching TTYs and basically executing your code? Are you doing all that EDR? If you're not doing all of that, then obviously you're going to miss that. But from our perspective, from the operating perspective, that's too chatty, right? Because that assumes that the defense can analyze our command line, right? And so it's also all that, you know, it may be really easily defeated. Okay. Well, we need to devise some other things. Maybe we can up our anti- invasion capabilities. Maybe we can bring in, interpret the languages into the mix, right? So we can prototype easily once we drop in the box. And so before we actually get to interpret languages, we can even talk about highly reflected pieces of code that are encoded into the shared libraries. Nothing to say that you have to create your shared libraries out of a C or C plus plus, right? You can actually use form function interface and run things out of Python or maybe compile things with the C go. And by the way, what does it give us? It gives us as an attacker a privilege of 256 functions highly reflective before the defense can actually find our main and figure out how we're executing. So just by shimming, it, shimming out of the consistent, consistent execution of C language into some other stacks, for example, interpret language or VMs or other things that are very highly reflective, the EDR loses our trail and therefore it cannot build a consistent story to be able to determine if we are malicious or not. And the same thing with interpret languages, you can actually run some things in it, for example, you can preload things with Lua. That's a completely different execution and it gives you different memory footprint if EDRs are not watching for it. And you can, with Cheney, you can mix and match all these things. So see how many, it's a death by a thousand cuts in a menu of respects as far as EDR building that story. That's what we're after. We're basically trying to abstract it to the point where we're persistent, you know, if, if it's not a known good and if it's not a known bad, because EDRs are running on, you know, most EDRs run on performance and they cannot consume too much CPU time or, or analysis time, they'll say, okay, fine, I'll let you go. And so right now we know that those primitives that we're trying to build are not that primitive, right? But stage two is how do we package this whole thing? How do we make this rapid prototyping actionable? How do we make it maybe even more defensible for us? So start thinking about preloader, preloaders. Let's start thinking how do we expand the functionality and make them more flexible, I should say. In this example, if we're taking slash bin slash ls and we're preloading it with our malware execution chain, right, any arguments that we're passing in into the preloader are not going to end up being used because they're eaten by the ls. Well, you know, what can we do with this? How can we make our loader even more expanded? We can start moving back on the command line with environmental variables that are being consumed by the preloader, right? And mind you, in this case, the preloader is only a dynamic library. It's not an executable. It is loaded as a constructor into slash bin slash ls. And so in this case, we are saying, hey, you know, take that bin ls, preloaded with libctx.so, by the way, go into the background, by the way, rename itself in the process table as SMTP process. By the way, have a chain of shims that load into, you know, you dynamically unravel that chain and load it back into the memory. And by the way, pass arguments to those chain, to the chain or to those libraries that were preloading. That's one way of doing it. And those chains can use all the things that we talked about. They can be highly reflective. They can escape into, into interpretive languages. They can even switch on different IPCs, right? They can run over pipes or they can source their payloads over various facilities that the operating system has. Now, and obviously they can clean up after themselves, right? They can remove all the things that they've loaded, ld preload, all the environmental variables. So if you're there first, you'll probably see that. If you're not, you won't. One small little problem. The loader that we're trying to do, the preloader chain that we're trying to launch, at least one of them is a file, right? A file, ld.so tries to load first. And as such, it's on disk, it's scannable, admins can find it, whatever the case may be. Yes, we know about EDR identity crisis. Yes, we know not everything is being watched, but there is a chance. So we want flexibility. Can we work with memory? Can we load things over memory? Well, loading modules into the memory is a really interesting thing. It's very common, right? Mapping memory and stuff like that. So your operating system is going to love you for that. There are facilities. But as soon as you start trying to execute something from memory, your operating system will not like it at all. So, historical has been, there have been many different ways of operating shared memory on Linux. Dev SHM, right? You can stuff some things in there, but again, EDRs may know about that, they watch it. Naked memory mapping of files is also something that is being watched by EDRs because you can put permissions on it, you can change permissions, you can create, read write, execute sections in there, and then, you know, obviously that's detectable. And most of the time, you can't really obtain execution from memory location because of that because you cannot mark your memory executable at some time, you know, sometimes you just can't do that. As kernel 317 rolls in, we're gaining a specific separate system call, which is MMFD create. That's not a new technique to load things into memory from MMFD create. But if you want to do this, here's the API to do this, MMFD create, you allocate memory, and then you basically pass it to F exec VE, or maybe you emulate execution, but the point that it works, you basically have a way to execute things over memory, right? Essentially, it is the relaxed, the operating system relaxes rules on execution when you use that specific system call. But that's not what we're after. It is going to hell, but we're not after that. A curious side effect of running MMFD create is that it exposes a file descriptor like any other Linux process in a proc, right? And that MMFD creates a proc FD, in this case, you know, 2, descriptor number 2, for example, or 3, whatever the case may be. That's what we're after, and let's review what we can do with this. Well, if we're breaking the story of EDR, and we're splitting payloads across libraries, we can split payloads across memory spaces of processes. We can say we can have, we can line up 10 cradles, launch them up into the memory, and those 10 cradles are going to be separate processes that may host a part of the payload. How do we reach out to those processes and ask them, hey, give me your part, give me one tenth of a payload so I can execute it. This is what we can do with MMFD create. Instead of if we're taking the preloader and instead of executing and loading the module from a disk, we can ask a different process to give us a descriptor that maintains or contains the library or a payload in such a way that we can execute it. So we're gaining, we're reaching out to a process ID, 564117 and saying, hey, give me an exposed file descriptor. The only problem here is while we're actually doing execution and loading from memory, what is 564117? And if we're not in the relationship with that process, if we're not the parent-child relationship or we're not super user, then we're not going to be able to see that, you know, that process descriptor because of the Linux security model. So let's work on 564117. And before we do that, we have to look at the nature, which is really brutal at allocating resources and very efficient. And there are things in nature that you can learn from, right, we can learn from. One of these things is a phenomenon of a virus that infects a specific ant colony, right? And once the ant is infected, the virus doesn't kill the ant. What it does, it basically turns it into a zombie by saying, okay, ant, I'm going to control your muscles instead of nervous system. And as such, you're going to climb up the tree, bite on the leaf, and you're going to stay there until I tell you to release yourself or die or whatever the case may be. At this point, the spores mature and then they rain down on other ants and the story continues, the cycle of life, right? The interesting part from this is the fact that we're controlling the muscle system of an ant without killing it. And so a zombie ant farm is designed to do exactly that. It is an out of target process store of payloads. It's a broker and a dealer of the payload that is somewhere in the memory that the preloaders that we're looking at can ask it to release payloads for their consumption. So it is a broker that reaches over the cross process memory for a payload. Without going into details on how it actually does that in terms of what features it has, defensive capabilities and what not, let's first think how it works conceptually. Conceptually, this ZEV essentially it loads things into the memory. It asks the operator to load payloads directly from the URL into its memory and then expose the payload that was loaded from the URL into the memory, into the operating system, into the file system, through the proc. Right? And then your uber preload basically goes out and says, retrieve it. And because I can actually launch my parent child relationship with the preload, then I gain access to the payloader's memory space. This is how that looks, right? Your payload chain, because we're operating on the same user ID so we can introspect processes. We're saying, go give me a payload out of somebody else's memory space. And by the way, do it in the proc. And by the way, do it from the memory. And by the way, I don't care about your ADR. Right? And so in this case, 564117 that we've seen before, it acts as a broker and a dealer for the payloads for us. Conceptually, you know, the big picture is how that works, right? You have facilities and primitives where you create this monster target process that you can instrument with different, you know, code running through sections or compilers or loaders, wherever the case may be. Your loader asks Zaaf to basically give him the payload or features or functionality. And it loads the target executable with them. So what the ADR sees, now it needs to connect the dots and see the full story across memory processes of the entire, you know, maybe 10 or 20 different mechanisms. The IPC, the sockets, the URL retrieval, you know, two different processes that are involved or three different processes that are involved. And if it gets the real cradle or a clean executable, it's not going to see any of that. So that's where we're after. So the pipeline is getting stronger here. Okay, well, one other problem that Zaaf itself is a, is an executable. How do we, it's a catch 22, right? Like how do we get executable that doesn't drop on disk? So we can get the library payload that doesn't drop on disk by using Zaaf. But how does Zaaf get there? Right? And so we're returning our attention back into MMFD create, but only doing this from the interpreted language. For example, Python. Right? Through common function interface, you can call up the Linux operating system sys calls, right? You can say, hey, MMFD create from Linux or from Python, execute itself and give me whatever you're going to give me. Well, Python is just a string of text, right? You're not dropping executables on a disk anymore. What you're doing is just running a script in the Python. So now you're extending that story for EDR all the way out into just a string of text that loads, that executes the, the URL retrieval of Zaaf itself and launches it in the memory through the interpretation, through interpreted language. Py preload is what I called it, right? It reaches out to the URL endpoint to web server, fetches things and launches them into the memory by using decoys. So for example, when EDR or your threat hunters are looking at the process table, what they see is a bash, for example, that launches bin ls, but they do not see the relationship of the Python code basically getting things out from elsewhere and unraveling that chain. So again, we're trying to blind the EDR from the behavioral standpoint so it doesn't build, doesn't have a chance to build that story. And along the way we're basically trying to, to prevent EDR from having, to latch on any kind of trust that we're doing. Okay. And so, you know, conceptually it's really easy now, right? Like a Python script that is very small, it's a text, you drop it in, it gets a Zaaf, Zaaf launches into the memory, Zaaf itself has facilities to interface with. So we're having a shell script go out to its socket and say, hey, load all of your payloads from all these other locations, be it file system or, you know, external network interface or URL, whatever the case may be. Store it in your own memory space and delve it out as needed, as asked. And a whole, you know, if we were to have a visual of this whole thing it looks like this, right? Number one is your PyPryload driver that gets the Zaaf out of the external location. In memory execution of a process for Zaaf, Zaaf presents a driver sort of socket that says, okay, well, here's your, you know, Jason, go get me something from external, expose me some, some payloads and I'm going to use the Uber preloader pipeline to go get the payloads from it and I'm going to instrument the process that I want slash bin slash alas or whatever the case may be to do the bidding on our end. So all that is we're going to, we're going to go into a demo and this demo is going to show if we can do that. Okay, so that's zombie and farm, right? First we're going to fetch a remote binary and execute it from memory as we talked. And so we have a, we watch the file system just to make sure we're not dropping anything on disk, right? And then we're launching a HTTP server to serve the payloads and in this case there's going to be a malicious alas command for example that comes out of that URL and pipe preloader is a python script that says, okay, that's a binary go fetch it, execute it and load it from a specific file descriptory. We have a way to do this and yet we're seeing that nothing has been dumped on disk, right? Nothing is there. The second thing that we're doing is we're actually, you know, fetching the preloader library if we want to. Exactly the same thing, executing it without preloader, seeing that it works, right? Then we're watching the file system making sure it's not dropping anything on disk starting the HTTP server. And then essentially telling the preloader that what we're loading is a shared object out of somewhere in the URL, executing it in the bin alas and by the way, you know, that bin alas is not going to describe something on a box. So both bin alas and the preloader runs in memory with, you know, loaded malicious code here, okay? Then let's fetch Zaf. Let's do exactly the same thing to it as we did previously to the alas. So let's basically break that story even more. Same thing, watching the file system launch in Zaf, saying that it's running as bash, executing loading it into the memory as a process 12, 8, 2, to 4. Zaf itself opens up a management socket that we can send commands to and basically saying okay well Zaf now load the same alas from external location as a module in its own memory space. And let's make sure that we can actually see that module loaded in there, right? File descriptor 6. We had forced the last one. Let's see where it loaded, right? So MMFD is a ephemeral descriptor that is executing in Zaf memory space and then we can just go directly for execution of that alas. Instead of doing a path on disk, we're doing a path in the memory catching a file descriptor 6 from Zaf, right? And that's a regular executable that we fetched. Pretty powerful. And then, you know, we basically just keep doing this. We can, you know, create preloader chains and those things. Doing exactly the same thing here, right? We have our previous module that we have loaded, but instead of loading executable we're going to load a library for preloading and it should end up being on file descriptor 7, which is true. And then instead of executing out of proc we preload alas with exploit that comes out of its, you know, Zaf's memory, right? The module is still there. You can destage it however you want. But the point here is that we're now splitting execution of payloads and delivery into two memory processes. Okay. Other things, other research to break that story that is going on right now, it's not fully complete but I kind of wanted to talk about that a little bit, is if we are owning our code crave, or code cave, essentially we can randomize, we can remove ASLR from the process by creating a personality trick, right? We're basically forking executable, we're changing the personality and we're executing it without the memory space, with memory space that is not randomized anymore. And then we write or read into the memory process, into the process memory, our exploit. So our exploit no longer needs to come from a library that you preload, it can come from a text, right? How do we do this? Well, we essentially, like I was saying, we fork then address the randomized, put a flag on the personality adjustment of a process that we're launching, because we're parent and child relationship, we're able to do that, and we're releasing it for execution. And then if we have a destination process that has a code cave that we can stuff our exploit in, we're able to do that in an address, in a user-to-user address space by writing a process VM, write a V. So we're working on this. Summary, preloading is a really viable path to evasion. Grab the executable from Linux, preload it, do it in memory. Out of process payload delivery works. And in my view, it's going to continue to extend into more attacks, and we're going to do more research on it. From the red team perspective, do not use, you know, all of that on one engagement at the same time, because it's going to burn your payloads and mechanisms of delivery, choose things wisely. C forward and function interface is important to interface and to escape from EDR story by basically switching the stacks, the technical stacks, and then use those source of assemble attack, splitting, scattering and then assembling things on a box as you choose to, it depends on which EDR you're going against and what the consequences may be. The code for both zombie and all these examples is released. You guys can download it, play with it, send bugs, add to it, it's open. Defense, optics into proc, optics into IPC, optics into process loader, optics in MMFD create must clearly define what EDRs do for you in the scope of your threat model, what it can and cannot do, and start implementing Linux capabilities. There's no reason why BNLS should run a socket code, right? And obviously last but not least is start thinking about the protective context, quiescing your boxes, making sure you know what runs and how you're protecting your stuff. Thank you.