 First off, I just want to thank everybody for being here. I know it's late in the day. Having everybody here is what makes it possible. So I really just appreciate you all being here. So now we're designed to be using legacy Microsoft transports and session architecture. That's what this is going to be about. But a little bit about me is first and foremost, I'm a principal red teamer at Equinix. And I know we have a lot of Equinix people here. So I definitely want to give a shout out and definitely thank the support I get from them. Also, I was a student at St. Vincent State University. Computer science. I have a great apartment. And several faculty, yeah, several faculty are goons here and have been for a really long time. So I definitely appreciate them. Want to reach out to, shout out to Blackbridge. They do great pen testing, consulting. You know, so that's kind of a background as I do a lot of red teaming, consulting, coding, developing all that sort of stuff. And primarily, I like to stick to Python or C++. And in this case, we're going to be looking at, you know, some of the challenges that red teamers face, because we need to compromise endpoints and networks. And then we need to, you know, exfiltrate data. But the thing about the red teaming is that everything is in scope. And nobody knows that we're coming. And so remaining undetected is a key part. Or at least maintaining our access. If we're detected, the gig's kind of up, especially being, you know, not a legit bad guy, because you really only get one chance. You know, once the blue teamers know about it, it's kind of game over. But anyway, so if we, you know, use like traditional frameworks to suffer a C2, that's great. We definitely want to do that. But what if those channels are compromised? And what are the key things that those things do? They reach out to your C2 server, even if it's over an extended period of time. If that's ever picked up, then you kind of lose everything. So the focus on this is looking at implementing, you know, multiple, you know, TDPs at different levels and provide enough functionality to allow us to regain access to machines where we maybe have lost it or just to simply do something without having any sort of the indicators that would result from a process reaching out to the internet or another server for a tasking. Just some prerequisite, high level overview. We do abuse some of the things within Windows. And so I'm going to be covering at a high level Windows-like sessions and their stations. So it can things like that, but then also there's some other protocols that we're going to cover. It's pretty simple. The first thing we're going to look at is, you know, the different sessions. When a user logs into a Windows machine, they're going to have their own log-on session. And so if there's, you know, terminal services or multiple users can log in over RDPs as an example, then you'll have a different session for each one of those users. So what if we have a service like a implant that's running in session zero and we want to create a process inside of another user session? Maybe a session is just logged in? Can we do that from session zero? Which is basically where all the services log in or where they're running. So that's going to be one of the main topics that we talk about today is how can we achieve this and what are the best ways to do it and what is the, what are our abilities to detect it as well. Which brings me to a framework that I've been working on. And as soon as I get back to my room, I'll release the code in my GitHub so it'll be available. It's written in C++. There's a command line agent, but then also I've been implementing a graphical front-end using I'm GUI. So that'll be available. But just kind of a high-level overview of this is that, again, it's for long-term persistent access in case we need to recover it. But the main thing is that it doesn't reach out to a C2 server. It sits there on the endpoint running and then it waits for tasking. So we abuse some other different protocols within it to keep the network association away from the process. And we're going to go through that in more detail. But the way that we're doing it is that we're supporting, or the main thing is that we wanted to support the ability to implement different types of transports. So what if a specific transport only allows ingress? We still want this functionality. So there's a custom messaging protocol that's implemented. And the main takeaways is that an operator can issue a task and the task is going to be sent to the implant and it's going to do something. And the way that that is delivered is through a route. Notifications, those are the responses. And those are optional. So that's one of the key things is that you don't have to get a response from a task. So again, bi-directional transports think of stateful protocols such as TCP. You have your SIN, your SINAC and your AC. You have transmission back and forth between the two. But then in a unidirectional, you would have stateless protocols such as UDP. Or in the main one that we're going to use now are mail slots. And so those only require data being sent to the implant versus back and forth. So this actually gives us a lot of flexibility in that we can send a task off to a machine that's implanted and then not receive a response at all if we don't care about it. But if we do want to receive a response, we can have it sent back to a different machine over a different transport altogether. So we have a lot of flexibility and we're not tied to anything specific. Really, anything that, you know, any sort of protocol that, you know, uses the network, we can implement as a transport layer. So tasks, this is like one of the key components. So again, these are inbound. So it's a message being received by the implant. The implant then does something based on whatever you're tasking it to do, create a process in a user's logon session or creates a user, which obviously isn't very stealthy, but again, it's an option. So one of the questions is since the messaging protocol is a couple of days from the transport layer, how can we deliver a response, especially when considering a transport is unidirectional. This is where routes come to play. So within an obligatory implant, you have routes which describe a destination. And this would include all the information that's required to actually, you know, send that information off to it. So for instance, a mail slot, we would include the net bios name of the machine and then the name of the mail slot. I'm not going to spend too much time on this because we're going to get to it. We're going to have demos, which is probably going to clear a lot of this up. But the main thing is that each route entry is mapped to a unique identifier and this is used in route lookups. And then the notifications is the last piece. So if you send off a task and you want to have like a response, you want to execute successfully or what happened, we're just to receive data back, then you can say, hey, send me a notification over to this transport to this destination. So I'm going to talk about mail slots a little bit. Why do we want to use mail slots? Well, here's a quote from Microsoft. Remote mail slot protocol is a simple, unreliable, insecure and unidirectional inter-process communication protocol between client and the server. A mail slot is represented locally on the server as a file. So you read that and you're like, well, maybe we shouldn't use it. But there's actually a lot of advantages to using mail slots. So one thing about a mail slot is that the traffic isn't associated with the process. So normally, like, and we're going to demo this later, but normally if you have network activity through one way or another, you're going to have that associated with the process. So in this case, it doesn't, which is really good for us because we're again, we're not creating the path of, or I'm sorry, where the process isn't associated with network activity. So as defenders dig into this, we're trying to break those process changing events and the network activity. So this isn't going to be associated. Also, it's a very legacy. So it supports Windows 2000 APIs. So we could potentially use this on a wide range of machines. One key thing if you go to implement this in development is that you have to use the net biosname. You can't use the IP address. Even if you look in Wireshark and you see, if you see that the packets are being sent and they're being delivered to the endpoint, they're not processed correctly. And so the very big thing about mail slots is that you have to use the net biosname. Otherwise, it'll fail, but you'll see the network traffic. But it won't be delivered to your process for processing. This is extremely legacy protocol. So authentication isn't required, nor is it supported. I guess that was left to people that implemented the protocol themselves. So that's going to ring me to my first demo. Yeah, skip that. Okay. Well, it looks like the videos aren't sitting down. So we're going to have to skip the demos. Well, demo one was basically to show the usage of the of the tool and using mail slots to task a remote agent. And it worked. The demos are available for download. So I can download those and check it if you want. But in the last demo, if we could have seen it, what we would have seen is one machine sending a task to another one that was implanted. And then doing something. Whenever I was creating my DEF CON submission, I came across an article with this quote. And it was the first link after searching mail slots. And it gave me pause. I was thinking, so with the release of Windows 11 instead of preview build 25 or 314, we have started disabling the remote mail slot protocol by default. This is a precursor to deprecation and eventual removal from Windows. You aren't using this extremely legacy protocol unless you're also using the deprecated and disabled by default SMBV1 protocol. So 99.97% of you have nothing to worry about. This was a principal program manager. Yeah. So it gave me pause because I was thinking, kind of like Byte leader said in his talk this morning is like, am I the idiot? Am I dumb dumb? Did I somehow configure all these default Windows boxes with SMBV1 enabled? So I checked and that would bring me to the demo 2. And let me just illustrate verbally the best I can. Oops. In demo 2, we were going to look at actually showing through PowerShell that on Windows 11, 10 and Windows server 2016 that SMBV1 not only wasn't enabled but on the server even, it wasn't installed. And then it worked. So, yeah. Sorry about the demos. I believe we also looked at in Wireshark that we were actually using the mail slot protocol. They're being delivered over NetBios and SMB. So even though SMBV1 was disabled, our packets were still sent to the employees and they were processed and the task was carried out. So I'm not poking fun at whoever said this, but the thing is, is that as a defender wanting to potentially block this activity or ensure that your environment isn't susceptible to communication over this medium, be careful when you come across this article and what the assumptions we draw from it because every single link was either this one or one pointing to it. In where? Thank you. Well, let's just circle back then. Hey, there we go. Awesome. Thank you whoever said that. Appreciate it. Thanks. Okay, so this is the tool. We're on a Windows 11 machine. We're configuring it to use a mail slot. This is the system that we're going to target Windows server. We're just going to create a user, not really worried about Opsac at this point. We're just demoing the usage of it. So we're going to create a user Defcon 31, appropriate, with a super secure password. We're going to execute it. Again, this was a mail slot. And then we're going to look and it was successful. Defcon 31. Now I want to pause really quick. I forgot to point out, so you can see my mouse. So you can see here, this is the target. So over here we created these different targets here. So we have mail slot and UDP. These are the ones we're going to target. And so this is what's being selected. And so in that case, it was a mail slot and it worked. Now we're going to do is that was the GUI. We're going to show off the command line usage to show that you have the same functionality. So in this case, we created a mail slot listener. So we have like the service running, you know, the implants running as a service on these different machines. But you can also use the command line agent to set up a listener if you want to receive a response or even set it up for tasking. So in this case, we just want to receive a response. So we set up a listener there. And then in this case, this is the other key component that you don't really see within the GUI because it's done in the background. But the first thing that we have to do before we send a task, when we want the response is that we have to send or we have to create a route. And so in this case, we're targeting the Windows server. We're saying that this is obligato is the mail slot. And we want to receive responses to this Windows 11 box with OB receive as the mail slot. So basically, if we task the server, and we ask for response, here's where you can send it. And then we can reference this ID and subsequent tasking. And if that ID matches a route, then it's going to use that route for response. So in this case, we're going to add group membership. So we're going to take that user that we created, and we're going to add them to local administrators. And we're asking to receive a response to our listener here. So if all goes well, we're going to execute this. And then we'll see a response. And all of this is using mail slots. And remember, this is demo one and demo two. We're going to be looking at whether or not SMV is enabled. Okay, so success. Okay, and that was that. Appreciate it. So I'm going to go ahead and cut it there, because it's really just showing some other functionality, but for time sake. And so what I want to do now is just show demo two. And this was after reading the message that Microsoft, you know, I think it's trying to download them each time. Here's I'm just open up each one and let him queue. You know, it's funny about this is I thought that the video route would be safer since I had to use multiple virtual machines and everything. But I think the live might have been better. All right, let's try it again. Okay. So again, going back to that message, SMV v1 has to be enabled in order to use mail slots. As we can see on this Windows 11 machine, SMV one protocol, stay disabled. Windows 10 doesn't be one protocol. Stay disabled. Stay disabled. Now just to kind of further demonstrate this, we're going to pull up a wire shark. I'm going to put in a little filter just so we, you know, kind of filter some stuff out. We're only going to see communication between the server and the endpoint where we're sending the tasks. We're going to pull up the GUI again. Get a local user. Really awesome password. Just want to make sure it was running. All right, now we see the traffic. So we can see the net bios traffic. And then we see the mail select communication. And so again, this was disabled. However, we do see the packets. We have the SMV headers here. SMV v1 is disabled. Yeah, we're still receiving these. And then of course, there's like, we're saying, hey, create this local user along with this password. And it's successful. So the main takeaway from this point is that, and I'm just going to queue this up. The main point for this is that we don't want to assume that SMV, or I'm sorry, mail slots won't work within our environment just because we have SMV v1 disabled. So that's the reason why I threw this in here. Next, we want to look at Windows Logon Session Compromise. So we have like a good transport. Again, you can use multiple transports, in this case, you know, mail slots. But the next thing we want to look at to provide functionality is we want to be able to compromise logon sessions. So two key things within any engagement really is that we're going to have objectives that we have to get to, whether that's specific servers or information or users. There's going to be some sort of objective that we have to meet. And within that, a lot of the times what it's going to have is that we're going to have to elevate our permissions and we're going to have to move laterally to other endpoints. And usually those two things play together. We're going to have like limited access, but then that's going to have admin access here. We're going to get to that one. There's going to be privileged users. You know, so that's kind of the game is that we elevate privileges by compromising other user sessions or credentials. So the credential route is often through dumping credentials through LSAS. I'm sure everybody's familiar with that. Or LSA secret, cast credentials, etc. And then also logon sessions, which is another method, which is basically us gaining code execution in the target user's window logon session. And just to kind of look back, remember that each logon session in Windows is now kind of isolated from each other. So there's a few mainstream techniques for this, for gaining code execution in a logon session. One is execute code in a process already running in the logon session, or we can open a handle to the process, duplicate the token, and then we can use impersonation or we can just create a process. But here's the question that I want to ask is what if we want to create a process on demand inside a target user's logon session without executing code in it or opening a handle to another process. So basically we want to have all that functionality, but we don't want to touch other processes, tokens, within an existing process of the session. So one method is we can use a task scheduler. This isn't the method we're using behind the scenes. This is just an example. And so what we would do is we could create a scheduled task to run as a target user. We can set it to only run if the user's logged in and then there's not a credential requirement. If we try to have it run whenever a user's logged in, then obviously you need credentials. The key thing on this is that when the process is created, it's going to be using the WinST is 0 in default desktop. And so if your process has any sort of windows associated with it, those will be displayed to the user. In some cases this may be desired. For instance, if you're wanting to gather credentials, you could have a fake login prompt open, you know, whatever. But in a lot of cases you may not want them to be privy to anything that's executing in the background. So this wouldn't really be viable. At least I'm not sure how you could actually specify that. But also the process chain makes it pretty obvious what created the process. We're going to look at this in the next demo, but basically task goes W, which is associated with a task scheduler. It's going to have the same parent process of the same SVC host process as the process that is created. So from an artist perspective, it's pretty obvious to see the process chain of events. Also, when it's a task scheduler, it creates a lot of events that can be observed and scrutinized. And this technique has been around for a really long time. So I'm just going to go ahead and demo that really quick. Showing that usage. Okay, so we have a domain admin logged into the machine. And that's who we're going to want to target. Right now we have admin access to the same server. These two servers are the same, just different login sessions. But we're, you know, a low privileged user. But we do have admin access to the server. So what we want to do is we want to have code execution within the login session of the domain admin. So we're just going to use process explorer to show the association of, you know, task scheduler process along with the process that's executed. I already created this one just for time sake. And so we're going to be executing this schedule task as the domain admin, only when they're logged in. And the actions is we're going to make it open calc. So if this is successful, then it should open up cmd and calc. I'm using slash k just so the process doesn't exit. So we can observe it. Okay. And as you can see, we got a little short just for time sake. But as you can see that cmd was executed within the logon session of the domain admins. We do have code execution within that logon session or that user's logon session, which is great. But as you can see, the parent process is associated with both our process and the task ghost. And so that right there is what we want to break up. We want to be able to specify who the parent is and we want it to be believable. So I'm just going to close that for now. Queue up demo four. So let's add on to our original question because there's some downsides to the task ghost. Good. There's some downsides to the task ghost and that is that it creates a lot of activity on the endpoint that we may want to break. So adding to the original question, we want to do that and not generate the obvious of that logs. We only want to display Windows to the end user if we want to and we want to specify the parent creator process. And on some levels we want to evade EDW or other like visibility. And so that's going to be the goal, demo four. So I'm going to open up process monitor. The key thing about a process monitor is that it uses Windows drivers for the collection of everything, I believe, except for the network activity. The network activity is actually EDW. So the filter that you can see here is obeservice.exe, that's our implant service or process. And then we have Explorer. That's going to be the process that we want to spoof. We want the parent to look like explore.exe. So if all goes well, we're not going to see anything around obeservice and everything's going to be associated with explore.exe. Explore.exe can be anything but that's what we're using for the demo. So we're going to start that up. We're going to go ahead and spawn a process into a user session. In this case, we're just going to make CMD execute there, but it could be anything. And now we're targeting the user where we have process monitor running. Execute it. Okay. So as we can see, nothing around obeservice. We remotely over mail slots. We sent a task to our implant and we had it execute a service or a process. And not only do we not see any sort of network activity recorded because we're using mail slots, but we are also successfully spoofing the parent process. And so it's not recorded here. Explore.exe had nothing to do with the execution of CMD. But process monitor, it believes it does. And for time take, I'm going to go ahead and fast forward a little bit of this. What we're doing in this next session is we're going to do the exact same thing, except this time we're going to use UDP. And so when we execute it this time, you can see that because we just use UDP as the transport, it was picked up. So again, if we don't use something like mail slots or like I did a talk at DerbyCon a few years ago where we use Wind Ivert to do similar things, if we don't use a transport like that and kind of hide that activity, then it can be picked up on in ATW. But using mail slots is a way to bypass that. So I'm going to go ahead and show it in Process Explorer. And just for time sake, again, we're basically just showing the same thing. And so we're going to get that set up. We're going to go ahead and get our tool ready to execute the task. Then we're going to send it off. And as we can see that unlike before, when we use Task Scheduler, it's not underneath a, you know, SPCOs. It's not associated with our OB service here. It's shown to be executed or associated with export at EXE as the parent. It's in the target user and it's even recorded here. So now the next question is, let me just get this next one queued up. So how does this work? How are we achieving this? Two things. One is that we have our service running in session zero and it's running a system. So we need two specific privileges to carry this out, SCD bug privilege. And that is for spoofing the parent creator process. And then we need SCT, CB privilege. And that is required for creating a process in a different log-on session from the caller. So this is like a really big requirement, the second part. We're going to, so to spoof the parent versus just creating a process in the log-on session and we actually want to spoof it in order to do that, we're going to open a handle to the desired parent process. Not the token. We're not stealing the token. We're just getting a handle to the process itself with create, process create process. We're going to then create a new thread attribute list to handle this with this attribute and that's kind of the secret sauce. And then we have to determine what windows API we're going to use to carry this out. We're ending up, we're going to have to use create process as a user and the reason why is because, and this is demonstrating the documentation, but if we use create process with token, it's only going to be for the specific session that it sent. So basically the create process with token won't work if you're calling it from one session and the token is a session from a different user. So remember we're in session zero and we want to gain execution in a different session. So that was not going to work. So we're going to have to use create process as a user. But we don't want to, and this is actually what typically is not, but we don't want to access or steal a token from another process. So what do we do then? Windows has graciously given us a wonderful API, WTS query user token. WTS is the Windows Terminal Services API. You can imagine on a terminal server that you're going to want to have services being able to interact with logon sessions, right? And so this API is going to get a primary access token of the logged on user for a specified session. So we can be running in zero and we can use this Windows API to then get a primary access token for any logon session that we want. In order to do this, we need to be running as NT authority system and we need to have the SCTCB privilege enabled, which is available by default if you're running it at that level. What I couldn't be fine to be documented and what would actually create a lot of frustration for me developing this is that the caller must be running in session zero. So for instance if you're, you know, download this code and you're testing it out and you're running the agent to do this and you're not in session zero, but you're in a logon session, it's going to fail or at least it did for me on everything. So that's a key component is that you have to be running in session zero as system for the WTS query user token to actually obtain the token from another logon session. The next thing is can this be detected because what we saw is that process monitor and process explorer, they didn't capture this at all. So I mean if we're testing out malware, whatever, we're using these tools, we're not going to see this actually fire. So one why and then is the information available. The next bit of information is by Pavel Yusovic. He has a really great write up over this. And so I definitely want to give a shout out to them. So for kernel drivers to register the process creation notification with this PSET create process node for our team. And again, this is in the kernel driver. This is basically a structure that you get. And I got to speed up a little bit. But you have these different things. So we have the handle parent create process ID. That is what process monitor and process explorer using. And this is the information that we're spoofing. So now it makes sense because they're using kernel drivers to gather this activity. And we're spoofing it. This is the bit of information they're getting it from most likely. The next thing that Pavel points out is that the creating thread ID is also within the struct. And the real creator process ID and parent can be obtained. But the thing about it is that this information that actually show our malware service, this information is lost at this point once, you know, this exit. So that information isn't stored in the process, apparently. So what about EWW? So we can bypass and, you know, divert, we can bypass this visibility within a kernel driver that isn't looking at the create thread process ID, but just the parent process ID. But what about EWW? So we're gonna go ahead and get it ready. We're gonna go ahead and open up Process Monitor XB2, which again Pavel created and is available on his GitHub. And it is using EWW versus like the kernel drivers that we were using within Process Monitor and Process Explorer. So we execute it. Now we're just gonna go ahead and pause it. And what we're going to see is that we do capture it. So from a defender perspective, this can be captured using EWW because it does provide that information. So that's a good sign for defenders, right? I was kind of hoping for the latter, but okay, so we can see command was executed as the user. I just want to like end on this last demo is that, you know, we do see this activity of spoofing the parent within EWW, but we do not see it unless the kernel driver that's being used by the endpoint product is specifically looking for and looking within that other parameter within the structure. I'm going to embrace this very quickly because it has a few minutes left. But the other thing is looking at anti debug and runtime awareness within your malware. We're going to look at TLS callbacks, thread hide from debugger being debugged in environment variables. Basically a bunch of different things I've used very successfully over the years. The first thing are TLS or TLS callbacks, thread local storage. So these these are executed before a thread is created. And so it's very useful because whenever a process executes, like you're going to have your main thread, well, if you implement, you know, TLS callbacks, then that is going to be executed before main. So you can actually, you know, implement whatever you want before the main function is ever called. I didn't come up with this. Obviously, this has been around for a minute, but at least for me, like actually getting this to work in the code available for it was, yeah, I really couldn't find it. But it's not necessarily malicious activity, because it's using a lot of mainstream products, projects such as chromium, which is where I reference here. But the key thing is that it's almost like a constructor ability to have a constructor and destructor for threads. So you can have execution before it's it's executed and after. So obviously, we have execution very early in the execution of the process even before main is called. So thread hide from debugger. This technique has been very successful for me. There's an attribute. There is an attribute whenever you're creating a thread where you can set it to not being like you can set it to not allow being debugged. And so when you create the thread and you say, hey, hide from debugger, don't allow me to be debugged. If you debug that thread, the entire process crashes. So even if this is like a different thread other than main or whatever else, if you try to debug that process, the entire process or that thread that entire process will crash. And this is just because for debugging purposes, obviously you'd have to have a thread running that isn't being debugged itself. So the next thing is like, well, if we detect something that is happening that we don't want to happen, how can we leverage this? And so we want to know if we're being debugged. And if so, we want to take an action. Historically, a lot of cases you've used is debugger present. We don't want to do that because it's very obvious. But we don't have to. It's very simple. All we have to do is get the address of the process environment block, PeeBee. And then we can access the values at the offset of being debugged. So it's very simple. We basically get the address to PeeBee. And then we get the offset. And then we can identify if we're being debugged or not. You can use this encoded entirely. This is fully working. But what we're showing here on the right is that we have our main function. It just simply types a number after getting some input. But above it, this is where we have our TLS callbacks function being created. So we're creating a thread. It's our anti-debug thread. So before main is called, we're going to execute this anti-debug thread. And then after that's set up, we're going to make it where it hides from the debugger. Within that, we're going to read the offset of being debugged within the PeeBee. And if we are being debugged, then we're going to add a breakpoint. So if we add a breakpoint within a thread that is configured to not being debugged, the process crashes. Appreciate it. The next thing is basically just looking at environment variables. One key thing in a lot of sandboxes is that they're not domain joined. And so we can look at the user domain and computer name, compare them. If they are not, or if they are the same, then the box is not domain joined. So simply checking for this can help you bypass a lot of like sandboxes. Because like in, you know, for what I'm doing, typically if we're executing something on a Windows endpoint, if it's not domain joined, then it's probably not something that we want to have our stuff execute on. So this can be used in conjunction with the TLS callbacks to have really early detection on, you know, the state of the machine and if we actually want to run our implant or not. So in conclusion, the implant messaging protocol that we've implemented, it has response, I'm sorry, it'll support unidirectional or bi-directional transports. And you can have optional responses. Mail slots are available even if SMBV1 is disabled. The network traffic from that activity is not, is disassociated from the server and client process. It's also supports broadcasting. One of the things in the demos that we didn't take so trying to hurry is that if you put a star or instead of the net bios name and you send it out within any implant within the domain network is going to receive that and execute. So we can send out one task and it'll propagate to everything in there. So if you want to target a specific user, we don't know where they are. We can send it out and then it'll just, it'll execute within that log-in session if and where they're logged in. Again, authentication isn't required. We just went over like the process execution stuff and spoofing the parent process. Key takeaways is does your environment detect it? Does your stack detect this? Are they looking at the correct things? Are these an ETW or their own drivers? What is the state of your network and can they defend against this? And at this point, I'll go ahead and close. Again, thank you for being here. I know it's late today. Huge economic panel obviously. So yeah, I really appreciate being here.