
Uh right now we have Jaden Kaye with curb roasting in C and obsc perspective. Thank you. >> So hey I'm Jaden or I also go by the handle red to desync. I'm here to talk about doing ker hosting in C and in particular the obssec perspective around building your own tool. [clears throat] So what is the purpose of this talk? So really this talk is about EDR in OBSC perspectives from building your own custom C# tooling. For this I'm going to be using curb roasting as an example as it's one of the simplest AD attacks you can uh perform. So hopefully at the end of this talk you'll understand if I was to go build
my own custom C# tool for Windows what sort of things should I think about if I care about OPSSE or EDR evasion. What components do uh exist on a Windows client endpoint that an EDR has that can collect what type of telemetry? How do other tools do this? What is the most common method of doing it? And how do defenders actually detect them with these sort of detections? Are there other ways we can do it? Uh when should I use them? Do they open me up to being detected in a different way? So firstly I'll give a quick overview of what I mean by Kerbrris. Uh then go into what is Kerberosting the actual attack
and then I'll review probably the most common C# tool that everyone uses called Rubious. I'll first go through the indicators of compromise on the server network side. So really just talking about the most obvious signatures that can be used to detect uh Rubious is doing a curb roasting attack. After that, I'll do a quick overview of different EDR components that exist on a uh Windows endpoint and how each of these different components apply to us. What do we need to think about and how can we try to bypass them? Finally, I'll give some closing thoughts and my sort of process of how I would go about trying to build my own tool and to how
to bypass a particular product X. So firstly, what do I mean when I say Kerbrus? Uh if you don't know, Kerbras is a like a very common authentication protocol that is used within active directory environments. Uh behind it, it mainly uses tickets for authentication. Uh one of them proves who you are and that you belong in this domain. This is called a ticket granting ticket. Another is what you use to authenticate to a service or server which is called a ticket granting service. Let's say for example Alice wants to access some service on server B. Alice first needs to obtain a TGT to allow her onto domain. Then with that TGT she then uses that to obtain a TGS and provide
that to the service running on server B to say this is give me access to the service goes I'm Alice. An easier way to sort of think about this might be thinking about it in terms of a theme park. So, we could say that the front office at a theme park would be the uh key distribution center or domain controller. It's what's responsible for handing out tickets. You would go up there, ask for your day pass to get me access into the theme park itself. That's your TGT. Once you're in the park, you decide you want to go on some ride. To go on that ride, you need a special ride ticket. To get the ride
ticket, you would go back to the front office, show them your day pass. Hey, I'm allowed to be here. can you please give me a ticket to go on this ride? It will then provide you that ride ticket. You can go to that ride operator, hand over your ticket, and he'll let you on. So, this is a diagram showing just a very brief overview of how the protocol works. Essentially, the client will send a what's called an asre request to the key distribution center or domain controller, the one that's responsible for everything authentication. If you prove that you know your own credentials and stuff like that, it will then provide you with an asrep response
uh as rest response providing the TGT. With that TGT, the client can then decide to access a service by again providing its TGT to the domain controller and specifying what service it wants to access. This is done via what's called the service principle name. I'll go over that a bit later. In response, the uh key distribution center would then send back the service ticket or the TGS. Then the client now finally wanting to access that service goes that service and provides a TGS and the service will say yes or no and provide access. So in that example, how would the uh the ride operator or the service know that this TGS is valid? How do I know I
didn't just make this up out of thin air and just provide it? It's not checking in with a domain controller. It needs some way to know that it's valid. The way it does this is that the key distribution center will encrypt part of it using the account services password. When you present that service ticket to the service, it can then decrypt that ticket with its own password and validate it to make sure it is actually a valid ticket. So how do we know exactly what account and services like tie together? The way it works is based on the thing called a service principle name. This is assigned to a specific active directory account where there is a property called the
service principal name property that will have this listed in it specifically. So for example, let's just say I want to access the MSSQL server running [clears throat] on server.qu.local. The service principle name could be written as MSSQL/server.corp.local saying the service is MSSQL. It is located on server server.corp.local. This SPN would then be assigned to a particular account. For example, we could assign it to the MSSQL service control user. So cool. With that sort of understanding what is ker roasting? Well, if we think about this, if we knew what the account password was that's responsible and has that SPN set, we could just create our own tickets. This is what's called a silver ticket attack where you know the
required information just forge your own tickets and get access pretend to be say a domain admin to the service or also if we know the account password we can just access the account itself and gain whatever access it has. So how could we try and do this? We could just obtain a TGS ticket, figure out a password hash format, pass that on to something that can crack password hashes, and then if that works and we get the password, just create our own tickets. This is what Kerberosting is. That is somehow obtaining the password from the TGS offline. Is this like something that we should be trying to do? Is this like a valid attack? The only way that this would be
uh useful and viable is if for some reason the service account has a weak password. If you configure it correctly and it's uh installed and managed correctly, these passwords should be long and randomized and impossible to crack in a reasonable time frame making the attack mute. However, you will find very often either some engineer or some weird software has created a service account with either a weak password or a default password that makes it very easy to crack. Also, you can technically be successful gain access to a service or an account, but that account or service might mean nothing. The service might not be running anymore, or the account itself might have lower privileges than you
had. So really it is very highly context dependent. You could get a domain administrator from it or you could get nothing. So how is this done on Windows and C? The main way that pretty much all pentesters do it is through a tool called Rubious. This is a tool that was created by Spectre Ops many years ago. Uh it does basically anything active directory or keris related. uh can do many more things than just curb roasting, but curb roasting is the main one of the main things it can do. Yeah, as I said is the go-to tool for pretty much all pen testers and if you look up the guide on how to do curb roasting,
Rubious will be the first thing that pops up because of that is very well known to defenders and they are very good at tracking. If you just try and use it stock standard, throw it at a domain, you'll get caught almost immediately. At the end of the day, what this will provide for you is that password hash related to that TGS ticket that you can then throw into your favorite uh hash cracking software. So your hashcat or John a ripper and try and crack it. So here's an example. So in the first line I'm saying rubious kerost. Uh no wrap there is just saying don't wrap text cuz it makes it really pain in the
ass to copy. Uh once it's done that, what it's first going to do is it's searching in my domain. Is there any accounts or specifically user accounts that have a service principle name set? I'll go through a bit that in a bit more detail in a second. In our case, it found one. It found the MSSQL service control user has an SPN set to that one I said before, the MSSQL server.local. It went and grabbed a TGS for that account uh for that service and generate us the password hash as you can see on the bottom line with that hash. I then grabbed hashcat told it this is a hash generated from a TGS ticket and I provided it a word list
of passwords. As you can see it was able to uh to successfully crack it being my lead pass at one. So cool. How does Rubious actually do this in code? So, what I'll be doing is showing how Rubious used to do a standard coarse attack. About I think six months ago, they slightly changed the way they do it. Uh I'm guessing to try and be a bit more OBSC, but for this example, since it's simpler, I'll just use the way that it used to work. In simple terms, as I said, what it would do is find users with SPN set, specifically using a C class called a directory searcher class. This it makes it very easy to do any active directory
searching with LDAP and LDAP queries. Once we've done that, we found users and we found each SPN. What we do is request a TGS using another built-in uh C# class called the Kerous request security token. With that, we decode the ticket inside of it, which is encoded in the ASN1 format. Then do some weird math. pick out different pieces here to put into some nice format that we can pass on to hashcat. So, as you can see on the first line, we're saying what's called the root LDAP path. If you think of active directory as an actual directory, what we're saying is go to the very start of the directory, the very root of it, and
search for anything below that. What we want to specifically look for under everything is only what's called the SAM account type of user which is that random number there. The most important thing here is find any account with a service principle name. Here we're just using the wild card to mean any service principle. Ignore the user account what's called KRB TGT. That is the one that's used to create TGT tickets. Technically, you can do this attack against KBT, but if I've never seen it, and if you screwed that up and set a weak password, you're screwed anyway. And the last one is just to use account control to make sure that the account is actually enabled cuz there's no point
doing this if the account's disabled. What we do is use a directory object in directory searcher to search through and connect to that root path. and the uh directory searcher. We set the filter that I just specified. Run that. Get me all the results. Go through all the results. Tell me the service principle name, the same account name uh just for us to be able to know. So you can print it out nicely. Most importantly, actually request the service ticket. As you can see, using the cur uh kerous request security token class. Do that request store the response bytes which is the tgs do request. then pass it on to another function that I won't show
you that just reads the ticket and then puts it into a nice pretty format for hash cracking. So if we run it, that's what we get. Pretty much the same thing as Rubious just in smaller, more digestible chunks. Tells me, yep, we found one that's the MSSQL service control user. This SPN found this is a hash that you can use. Cool. So now that we have that, what are some of the easy ways that a defender would be able to immediately just pick out that this is Ruby doing really bad things? So probably one of the most easiest ways to detect it would be through the LD query it uses itself. Uh you can see that's a very specific
query. As I said, we have that first one that states a user. The second one that says the service principle name equals anything. Uh and thirdly that it can't be kgt and that the account must be enabled. Uh probably one of the most obvious and bad signs that you'll see here is the wild card used in service principal name. As in general a way that you can detect LDAP traffic is through either a lot of requests at a very short amount of time or a request that grabs a large amount of data that's very broad. So, how could we slightly change this to mean the same thing but not use the wild card and not make it look so obviously
asking for everything? Well, one way we can do that is just do what's called lexical comparison, which is a fancy way of saying number uh letter comparison. So, compare A to B is a greater or less than B. So here I switch that particular LDAP filter to be an or statement and I say grab me any objects where the service principle name is greater than or equal to a random service principle name that I created that looks legitimate. Here I'm saying http on some random server.corp.local that matches the domain looks reasonable or if it's less than that service principle name I set. You'll notice here if there is no SPN set, it will never match either of these
conditions. It will never be greater than and it will never be less than this specific SPN. But if an SPN exists, it's going to be greater than or equal or less than or equal. So it will match. Doing this sort of thing means you could create what looks like highly specific massive LDAP queries that actually are very meaningless when you think about it and really just means the same thing. Alternative alternatively, what you could do is just not use the term service principle name at all in this LDAP filter if that's something you're concerned about or if a particular EDR is picking up on LD query or LDUP filter contains service principle name doesn't look right.
So another way that we could think about it as I was talking before we're looking overly broad in the way that we search for users. Uh one particular way is that we're starting at the very root of the domain. That is where we have that ser uh the domain path domain lap path where we're saying start the top. But what we could do is if we knew where most likely uh users or service accounts are going to exist. For example, we could have a domain where you have an organizational unit called service accounts. That means we could restrict the scope of where we're searching to that specific OU or we could go U by OU looking for these
different users to make each query seem more specific. Also, when we did this request, we are specifying a whole bunch of properties to return to us. I only showed you same account name and service principle name, but there's also a whole bunch of other ones like last lo on time, description, given name, all these different properties that are filling up the amount of actual LDUP traffic and volume that we are sending and receiving that we don't really care about. So what we can do is restrict that and limit the amount of properties we obtaining to only ones we care about, reducing the overall volume. So here I've done and implemented effectively those things. I say in my
root uh sorry at the LD path only look in the organizational unit of service accounts instead of searching at the root of the entire domain. I'm then saying don't look for SPN's equal to wild card. I'm doing that trick of the lexical comparison to say less than or equal to which means anything really. [clears throat] I'm then putting as part of my l query only return to me certain properties that I care about. In this example, we have same account name, description, the SPN cuz we need that, but also things like when created, when changed, last on. The reason you want to know this is if a defender is purposefully trying to trip you up, they
might put in honeypot accounts, which would have some anomalies in here that you could see, or it would also help you get context to know whether or not there's a point in coing this account.
One other way that you could get tripped up when doing this is if you use encryption types that are what's called like downgraded uh you so when you use Rubious it is possible to specify the encryption type to attempt to use where we have either RC4 and TLM very easy to crack uh but is also not very common anymore and then we also have AES which takes longer to crack but is default now hopefully and you will see it used much more in active directory environments If you're if you want to try and increase your success of having a kerbo account uh of kerberosting you should use RC4 encryption. If you want to increase your obstac always try and aim
for AES encryption whenever possible to do this manually to actually specify exactly which encryption types to use despite the defaults that are set on an account. You have to manually implement the kerous protocol which adds some complexity.
When you use Rubious, it will by default request tickets as fast as humanly possible. This can be detected via high spike in LDUP traffic and Kerbrous uh traffic as all of a sudden this particular user has requested 20 tickets in 5 seconds and I've never done that before. One idea that would be smarter to do this is either split up your requests by a long period of time. So 10 minutes or longer I would say if you can I would split up to different host user combinations. So if you do somehow have initial access as different users on different machines I would split up the curve hosting attempts on different hosts to stop the correlation of
traffic. Although the smarter thing to do would be always to only target accounts that would actually somehow give you something in the domain. So rather than blindly just curve hosting everything hoping [clears throat] later that it is useful figure out first do your reconnaissance figure out okay if I get access to a service or this account I can get further access why so it's a worthwhile thing doing and as I said before be very mindful to not to try not to trigger honeypot accounts usually if it sounds too good to be true such as a ker roastable domain admin is and as soon as you touch it in any single way it'll will trigger a million alerts and you're screwed.
So with that, we'll look more specifically on the uh Windows endpoint part and what sort of EDR components exist that could be monitoring what we're doing and what we should think about. So knowing what type of EDR product uh EDR components there are and the sort of telemetry that's been collected can help us think about either do we need to do something to bypass it? are we okay with what we're doing it or should we try something else if we do that how are we going to get detected via that way so the first thing to think about is user mode drivers these are sort of starting to die out a bit more but in particular
these like to monitor wind32 API calls by putting in uh inline hooks into the different Windows DLS and monitor if you call any of them next thing and probably one of the biggest things in particular forn net is ETW think of ETW is a generic log store of different so a provider could create its own log store write stuff into it where another application can come in and read from it that's a great source of telemetry for EDR products teams anything like that cuz they can just grab that data and pass it on there is a different form of ETW called ETW threat intelligence this is a specific form of ETW that occurs on the kernel side and
really you can't really do anything about it but it doesn't log too much about specific net operations just more general OS operations. Then there's also this thing called network filter drivers. This uh is a kernel side driver that allows to monitor different IO operations. So if you try to do anything in relation to files, so open a file, close a file, modify a registry, it will be able to see exactly what you're doing, including the file name, potentially file contents, and just general who is doing what. There is also an uh AMZ the anti-malware scan interface. This is sort of like a in time antivirus check on different code. In our case we're talking about
net code just to see hey is this malicious or not? Should I kill it? You what what should I do? Then there's also kernel callback arrays which are specific functions that can be called whenever certain operations are performed. So on process creation or thread creation. And then we have yeah the file system mini filters which can be used to review all the different files you create. Uh there is also the thing that you should consider that the domain controller will also probably be watching and monitoring the LDAP traffic. Although I would say you're more likely to get burned on the LDAP query on the endpoint than domain controller purely because there's just so much traffic. But that's up to
interpretation. So when we're talking about network filters, what do what does that mean to us? Well, we're using two particular protocols. We're using LDAP to do LDAP queries and we're using Kerbrus to request Kerbrous tickets. The traffic uh the traffic will be seen on the endpoint in terms of what process is making what calls to what port. So what we need to be mindful of is does my process and my executable make LDAP queries? Is that normal? Is that expected? And should my process or whatever method I'm using to perform kerburous actions, should that be doing kerburous uh requests. So with LDAP, we need to be really mindful of exactly where we are. So if
we're running it from our executable, it will be from our executable. If we are doing this in memory in another process that we should think about does that process do LDAP queries? In particular, there are certain Windows binaries that are known to do LDAP queries. Uh one interesting example I saw was Excel, but at the end of the day really as long as it does LD queries, you're safe. and something you're thinking about is maybe I should try and inject into a process that does LDA queries and then run my C# tool to make it blend in. But let's just say I need to I don't want to use LDAP at all. Is there any
way that I can avoid using LDAP? There is one common method which is called the active directory web services. This is a specific almost web servicesy thing that runs on domain controllers on a specific TCP port uh 9389. It's based on XML and SOAP and uses it's a proprietary version of wrapper of the net message framing protocol. However, it should be noted that using this can also be detected uh as it's only it's not used very often in other processes. It's I've seen it mostly used in PowerShell. So, if you were to go use uh this particular port, you could be detected by it. Although I've seen I haven't seen that as often. So what about Kerbras? Uh when we use
the wind32 APIs and the way that I showed it before in C, we are requesting tickets via Elsas. So the kerous traffic will come out of Elsass which is standard and normal. However, this means we are actually uh interacting with the OS itself and potentially generating more telemetry and could be detected easier. So how could we do this? We could manually implement kerburous ourselves. However, what this means is that the network filter will see kerburous traffic coming from our process which might be very anomalous. So if we were going to do this, we should be mindful that maybe we should uh use a process that is known to do kraus traffic. It'd be very impossible
if not it'd be very hard to get into itself and make these manual calls. But web processes uh uh web browsers are known to do this. So pivoting into a web browser might be a smart idea. So ETW so in our example there are two specific ETW providers that we need to care about. One is then ETW provider. This logs pretty much everything in net code. So this will log your function calls, your parameters, potentially your output, basically everything in NET is being logged in stuff like the .NET assembly manifest itself will appear can in part appear in ETW logs. LDAP also has one itself that will uh be seen whenever we use the Win32 APIs to do the
LDAP query. Uh so what that means is on the client endpoint all of our LDub traffic can potentially be seen via ETW and then monitored elsewhere. The one thing in particular to keep in mind here is that because we don't control LSAs, ETW and ETWI events are happening in Elsass are just going to happen. We can't do anything about that. And additionally, we can't do anything about ETWI unless we do some weird kernel exploit. So, this is an example of a uh log that we could see about our LDP traffic. As you can see, it does collect a lot of information. what process we're running in, what what is its PID, what is the LDAP query that we're actually
performing like the LD filter, what is the root path, uh what is some of the stuff that we're also requesting. So, how can we bypass this? The simplest way to bypass it is to simply disable the right to it. So at the location that would be the call in NTL to actually disable uh to actually write the event we go write some bytes there called like bite patching just to say hey instead of doing that just immediately return. Uh there's a variation on this that uses hardware break points where just before the call actually gets to ndll stop it and make it return so it never touches the function directly. When you do this correctly it works very
well. However, doing ETW bypassing is a very malicious activity in and of itself, and so you can get caught by attempting to do this exactly itself. A potentially smarter way to think about it would be be careful of what you're using innet. So your function names, your variable names, what output you're putting. So instead of having a function called kerosting, you might have a function called nice summer. And also remember that our .NET assembly has a manifest metadata that's around it. And if that's set to version 0000 with no copyright information, that can look a bit suspicious in of itself. And it takes 5 seconds to set up. So why not set it up? So here's an example. Just a manifest.
Just put in random information in it. I've got assembly version 1.0.04. I've got a copyright. I've got a product, a company, and a description. So look a little less suspicious if it does appear in ETW. And this is uh just a very basic bypass. So what this is doing is doing what I was saying before. Find a uh find first the location of NDLL in memory using get module handle or load library in this case. Uh we then use get procress to find the location of a specific function that's called to write to ETW. In this case ETW event write with that location in our process. We make that memory read write executable meaning we can write
override some of its contents. We find the exact entry point into ETW event write and write the return instruction. So red. So as soon as you hit that instruction, you're just going to jump straight back out and not do anything. So now we can talk about Amy. So as I was saying before, AMZ is really this thing that allows a process to register and speak to an AMZ provider and just go, hey, is this code clean? Should I allow this to run or not? Uh I have seen this work either like on a whole assembly level or seen it work on parts of net assembly. So it might not get caught immediately during your running
of your .NET assembly, but as soon as it does something, you can then get caught. Uh what this really relies on is the antivirus registering itself uh using and then providing a specific interface that the net runtime can use. The definitions of this uh interface reside within mz.dll and generally when you run this and check hey is this clean or not you'll just get a very simple response yes it's clean or not. There are different codes you can get technically, but most of the time you only really care about zero or not zero. Similar to bypassing ETW, we can do pretty much the exact same thing. Hook uh the function within AMZ.dll that will go and do the scanning. instead go to
that point, force a return result of zero in register and then immediately return making it so that AMZ is never actually properly used and our program just thinks oh it's clean. Let's just let it run. Uh you can also do the same sort of thing with hardware breakpoints doing the same thing just before the NCDL function is run at all stop there make it look like it's a clean result and just return [clears throat] however again this can be uh caught as being malicious itself as you're purposely trying to almost disable any virus on your program. So you can very much end up in this catch 22 situation where you've got to get your AM bypass
to bypass AMZ to be able to bypass AMZ. [snorts] Uh, a potentially smarter idea or something that I always try to do is rewrite my code so it doesn't get detected by AMC as I've seen it mostly used as like a static code analyzer as a point in time. So if you get detected by Azy, uh just rewrite your code. Really change your methods, your variable names, your control for graph, add different functions, add different classes, do different things to hopefully not get detected through AMY. Uh so here is the way that we bypass Amy. So again, we find the location of MZ.DL within our process using load library. Once we do that, we find the
location of MC scan buffer. This is one of the first function. Uh this is a function that would then uh pass the buffer on to then get scanned by like scanned properly for the antivirus and then return a result of clean or not. Uh with that location, we make it rewrite executable again. So we can actually write a bite patch in and here is just some assembly. All it really is doing is put the put a zero value into a register that would be used as a return result and then once you do that immediately just return so the program thinks oh cool it's clean and then yeah finally just actually copy that patch. I'll quickly mention this uh just
because it is complete but really all this when we're talking about file system mini filters what we care about here is if we write a file to disk we are probably going to get caught. So if we decided to instead of just printing out the hash as is if we decide to write the hash to a file on disk that could very easily get detected particularly if you were to write it kerar roast ticket.txt txt if you try and drop it to disk you're pretty much screwed. So really don't touch disk if possible. Uh so finally the closing thoughts. So if I was to uh go against a particular EDR product I want to perform attack X
and I want to build my own custom C tool. What should I do? If possible try and get a copy of the EDR. that would be the simplest solution. Be able to check whether or not what you're doing is going to work. Uh find a tool that does it and try and remove the obvious indicators of compromise that everyone knows about. So in our example, service principle name equals star is a pretty obvious one that will get you caught. Uh keep in mind other obvious ways that will get detected. So requesting tickets too fast. Uh doing uh downgrading as accounts to use RC4 encryption, stuff like that. run your tool, does it get detected? Can you see an alert? Sometimes you'll
get a very detailed alert that says, "We detected suspicious LDAP traffic based on this pedd query that was based on this process." Other times you might get slightly more generic. We detected suspicious LDAP query. We detected suspicious reconnaissance. Uh so depending on that, you can try and move forward and try and figure out a path to bypass it. if not something I have used before is looking at examples of different EDR rules uh that exist on GitHub or what are other detections that people have specifically built try and see does my tool do exactly what that is detecting okay that might be what's sort of happening here maybe I can change it and maybe that will get passed obviously
you can try and do something completely different so when I was talking about the doing LDAP you could switch from LDAP to ADWS Although keeping in mind that that might bring in its own detection. Uh uh something to always keep in mind is that each edi product is different. Each customer might have custom configurations built to detect certain things. So even though it might make sense, oh this works for this product, this is a method I should always use, might not actually be true. You might need to tailor exactly which way you're approaching each problem based on each specific EDR product. And [clears throat] obviously once that is done, you finally got your tool bypassed, you just profit and do your
attack. Thank you.