Transcript for:
Perfection (Hack the Box) - Lecture Notes

What's going on YouTube, this is Ipseg, doing perfection from Hack the Box, which starts out with hacking a web application that calculates weighted grades. The vulnerability here is like a SSTI, I don't know if it exactly is server-side template injection, but it behaves very much like one. However, the trick is there is some type of filter in place that blocks a lot of characters from being sent. However, if you send a line break, then that bypasses the regular expression that is looking for bad characters.

In this case, it's actually a waitlist. But if you send the line break, then you can send any character you want. You can trigger some code execution, get a shell on the box. And then once you get on the box, there is a piece of mail that talks about the password format and you have to extract the password hash out of a SQLite database and then use a custom rule in Hashcat to brute force the password.

So with that being said, let's just jump in. As always, I'm going to start off with an end map. So dash SC for default scripts as V enumerate versions dash VV double verbose. This gives us the TTL, OA output all formats, put in the nmap directory and call it perfection, then 10.10.11.2.53 is the IP address.

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 an Ubuntu server. We also have HTTP on port 80, the banner tells us it's Nginx, the HTTP title tells us it's a weighted grade calculator.

There's not much in the end map so let's just go take a look at the website. So going to 10.10.11.2.53 we get the weighted grade calculator. Looking at it there's not that much information we see made by secure tools but the thing that really sticks out to me is Webrec version Whenever I have something like this and it like discloses what it's made by I always go and look for exploits. I'm going to check out exploitdb. I know you can use searchplate on your box but I still like going to the web page.

And looking at this, I see the dates of like 2008, 2010, 2011. This may look like it's vulnerable because it's Ruby 1.9.1, but, and it said Webrex 170. I'm guessing this is the version of Ruby itself. Whenever I'm confused like this, I always Google like Webrex 170. Let's do like release notes and see when this was released. Because maybe it's the version of the Ruby like language itself instead of... the library and we see 170 was released in 2020 and all these exploits are well before that so we could go google looking for things maybe it's not on exploit db but let's just go keep taking a look at the website right so we go to about us we have some names we have tina smith and susan miller but i don't see a login form so i can't really like start trying for default credentials or things like that if we go to calculate weighted grade we have this form, right? So I'm just going to try to fill this out.

Let's do a grade of one weight of 20 and see what happens here. And we need to fill out all the things that's going to be annoying. Let's do ASD one.

Okay. So I'm going to go into burp suite to intercept this. So we can easily replay this if we want to and click submit. And we see, please reenter. Weights do not add up to 100. So we have to make sure all the weights go up to 100. I'm just going to replay this request so we don't waste 20 seconds typing it over again.

I'm going to send the request and I want to see where that error message is, right? So we have it right here. I'm going to search the page for slash form, go to the little gear icon, auto scroll when text changes. So now we don't have to keep scrolling to see it.

So let's make sure our weights add up to 100. So I'm just going to put all the weights at 20. And because there's five, so 20 times five is going to be 100. Send it and we see our total grade is 7%. So what I want to do here is let's see if I change this to be a 20, we have 10%. So let's try one times 20. And we have malicious input blocked. So there is some type of filter here, we can try it in the category as well.

Let's do like seven times seven. And this is just a common like service side template injection, the two double brackets. We have malicious input blocked.

And I don't even know if this works in Ruby. I'm assuming this is a Ruby cause we saw powered by Webrex one seven zero. Oh, and there's the Ruby version three zero two. So that's disclosed in the header as well. Going back, our exploit DB is closed, but we know there's no vulnerability in the Ruby language itself.

because we didn't have anything there and Webrex. So let's see, what can we do here? I want to see all the bad characters.

So what I'm going to do, get a valid request. And then I'm going to copy this to a file. So we're going to right click and then copy to file. And we're going to type, let's see, weighted dot request, save that. And then let's just take a look at it.

And I'm going to put fuzz where I want to fuzz. So we're going to go in category, just put fuzz in all capitals. And now we want to find a word list that is special characters. Let's do Fufuzzing, let's see.

Is there a special I'm just gonna grep dash I special there we go So we have this special characters dot text, okay? I think I only copied the file name. Let's copy the entire path copy. There we go. Awesome So now we can do fluff, I'm going to say dash request, and we called it weighted request, I'm going to specify the proto is HTTP.

And then the word list I want to use is this sec list one, and they're going to send it. And I'm guessing everything with 1619 is a bad character, right? That's probably going to be malicious. detected, right? So we can say filter size 1619 and we have three that are valid and the three that are valid is only valid because it's probably not URL encoding these right.

It's just sending like the ampersand which if you send this and don't URL encode it, it does nothing right because it's going to treat that as a separator. So like this figure here like it doesn't show the ampersand here with replaying the data right. Same with the plus that's just going to put up the space did go through so space looks like it is a valid character.

We could try a slash and looks like slash is valid. If we wanted to, we could y'all incurred all this pretty easily. If we do echo slash, and then we pipe this over to jq.

So I'm going to do jq dash capital R, this is going to like not require it to be JSON is just read raw input, I think. And then lowercase R is going to be raw output. But if we don't do the lowercase R, it just puts it in those quotes, right?

That's how we want this to look. And if we don't do a capital R, it errors. So what we're going to do is cat the file. So if I do a cat this, and now we URL encoded that entire payload, right?

So I'm just going to go up here where my foff request was, and then If you go with a I think that's less than and then the parentheses, it's going to run this command and then treat it as a file. So this is a quick way to just manipulate your files or do like encoders because I don't think FufUFuf supports encoders. WFufuzz does, but I don't think FufUFuf does. So we throw this and I'm going to get rid of the filter size. That doesn't look like it worked, actually.

Let's see. Why did that not work? That is odd.

If I run this command, did I screw it up? I don't think I did. Oh, we don't have a cat.

We have to run the command, right? We have to cat that file. There we go.

Okay, so filter size 1619. And the only thing that's good is percent. to Fuf, which is a slash. I'm actually surprised the plus didn't get work. We do a plus and then URL encode this.

Yeah, it does not work. So what I'm guessing here is space is a valid character, but plus is not right. So when the regex was seeing it, it did not like the plus.

If we just send it without URL encoding it, it's not really sending plus it's sending space. So that's probably the discrepancy there. So there is one thing that is hard to test through burp, just because if you like highlight, you can't really convert this.

It is new line characters. So like backslash R backslash N, that's really percent zero D percent zero A. If we do man ASCII, let's see, look for return.

Where is it? Carriage return zero D. and then new line is 0a.

So let's try that. Let's do %0d%0a and then I'm going to put a semicolon which is a bad character. We still have malicious input blocked.

If I just do a new line, it actually worked. We have ASD and then a semicolon. So we have successfully bypassed the filter.

And why does this work? I don't know exactly because we haven't looked at the code. But it does generally work when like there's a regular expression.

And the regular expression is not multi line, it's just going to look at the first line, it passes that And then it moves on to the next one because they didn't specify like if it's Python dot all is normally how it happens, I think, because period won't match a line break unless you have the dot all parameter. This is Ruby. I don't know much Ruby.

So I don't know exactly what the issue is here. Once we get a shell, we can take a look at it, right. But doing a new line allows us to bypass the filter.

So let's go ahead and look up Ruby SSTI payloads. So Now that we can test this and let's see I like going to payload all the things and hack tricks and it's loading probably because burp suite is still in intercept. Nope it's not it's just taking its sweet time.

I'm gonna turn this off maybe my VM's actually going slow. Wow that is going real slow. Disable.

You can see something spiked here. Let's search for Ruby and then we have percent equals percent Okay, so let's go back to repeater and then after the 0 a we're going to do like this and then 7 times 7 percent like that and We have some error. I'm guessing we have to URL incurred this so percent is percent to 5 and There we go.

We have 49. If this had 7 times 7, we know it wouldn't be vulnerable, but since it actually processed this, it is. So let's take a look at what they suggest. We could do like file open. We could also do system.

So I'm going to try this system payload. So if we grab this, and then we send that. Let's just go hit enter. We just get true.

So it's not reading the output. result of that command was true, like the exit code. If the file doesn't exist, we get false. We could try the other way they said it. Let's just leave the cadet C pass WD.

Instead of doing system, let's just do backticks, right? Like that. And then we get the output. The other thing it had was like IOP open LS. This also works to get output as well.

because you're reading the lines. If you do system.readlines it doesn't work. I don't know Ruby. I don't know exactly why, but these two payloads would be the best to get results.

If for some reason I didn't have access to those payloads, I would probably try a sleep command or ping because if we do a sleep one, it takes now a second to load. We can do a sleep two, look at the bottom right of the screen, see 2000 milliseconds. So we know I took two seconds to load.

So let's now just get a reverse shell. So I'm going to do, let's actually make shell on a box. And the reason why I'm doing it this way is, um, I can type and talk at the same time. That'd be great. We're in something that could have like a lot of bad characters.

So if I do it this way, I can avoid all the bad characters by just doing base 64 and bad, bad characters. I just mean like quotes and things like that. So I always like using a cradle like this just because there's less bad characters.

The one thing you have to be careful on when doing base 64 we'll have to make sure we URL encode the payload because that plus is going to be treated as a space and not how we want it right. So let's do a echo then base64-d then bash. Okay URL encode.

NCLVNP 9001, send this, and we get a shell. So let's upgrade our shell. So I'm gonna do python3-c import pty pty spawn bin bash and then ctrl z sdty raw minus echo and then foreground hit enter twice and then we can export and I cannot type today.

Term is equal to xterm so we can clear the screen and Now let's take a look at what we have. And the first thing I generally look for is some type of credentials stored in the web app, like it talks to a database normally. However, I don't believe there's a database behind this web app, but the one thing I am curious about is how that SSTI worked, right?

How we bypassed the filter. So I'm just going to look at main.rb and let's see, this is looking at a post on weighted grade calc. So I think it's right where we want to be.

And we're looking at this and we see else if params category one, and then we have this regular expression. So this is matching a to Z lowercase uppercase. 0 through 9 and a space and then matching as long as it starts with and ends with that string up until a line break. So the %0d that is a return character and I guess return is not part of this line break in Linux only backslash n is right so that's why when we had the return it doesn't match and um oh we also match slash I don't know if I said that so um There's no really bad characters.

It's a white list, not a black list or a deny list. And then we get code execution why so we're just checking here. I don't see anything there.

Oh, it's doing an ERB dot new. And then we're just passing in our parameters. Think of like ERB dot new as like an eval because it's just like embedded Ruby.

So it's just doing a script. And whenever you do the less than percent equals, it's executing. So I don't know if this is technically SSTI or not. Maybe it is.

Maybe erb.new is like for templates and things like that. But that's why you get code execution, because you can think of this as eval, I guess. So let's see. What do we have here? If we look at our user, we can see we are a member of sudo.

So if I do sudo dash l, it wants a password for Susan. So let's see. What do we have?

We have user.txt. We have this migration thing. By cat let's actually do um sqlite do we have it yep pupil dot dump and then we have a bunch of hashes let's see we can do echo dash n wc dash c we have 64 characters is that like a sha1 sum echo test sha1 let's do awk print 1 so we only grab the first character that's probably too small Uh, WC-C 41 probably SHA-256 some I would think. Yep. There we go.

It says 65, not 64. Cause there's a line break in there. I bet if I did an echo dash N, uh, that did not work. Uh, yeah.

So it did that just because of the line break. So let's see, we have to figure out what Susan's password is. I'm just going to do a find on the box to see what files Susan is a owner of.

So I'm gonna do find slash dash user Susan. Let's see. We can also add a LS and then let's hide error messages because there's gonna be a lot of files we can't open. And let's see.

We have a lot of things in own. I'm gonna hide everything in proc because I don't care about proc. I forgot the dash V. So let's see, we have home Susan, and that is about it.

So we just have things in the home. Let's take a look at the group. So we'll do group Susan. And let's see, we have a bit more. So she owns that Ruby app.

And then there's also a piece of mail. So let's take a look at this. So I can cat var mail Susan. And we see due to our transition to Jupyter grades because of the pupil path data breach, we should migrate our credentials. And we have the format first name, then the first name backwards, and then a randomly generated integer between one and is that a billion?

So my question right now is how do they do this? because that could be like one or you could do uh let's see like this so i don't know how it's formatted um i'm gonna guess it's form of 10 digits but i'm not positive so we have to go over or first we have to extract all the um credentials out of this pupil path database and then we can go over to the kraken and try cracking it um so let's do that In order to get all the table names, I'm just going to run that dump command again. And I want to extract the name and password.

Actually our user is Susan so we could probably just do it with Susan's hash but I'm going to extract all the hashes just because right. So we're going to run that sqlite command again and then I'm going to do select name password from users and that is ugly since it did that line wrapping but we have it there. If we wanted to we could do stty-a rows 28 columns 1 as TTY rows 28 call 110. Is it calls? There we go.

So now if I did that SQL lite command again, we can do select name, password from, was it users? Yup. There we go.

So fixing the TTY just means I can go all the way left and right. So it just behaves a bit better. Now for hashcat hashcat when you specify usernames does like it delimited in a semicolon. So we could just do a said s pipe, semicolon, G like that. And now we have it in hashcat format.

But what I want to do is just grab Susan's. So I'm just going to grab this, we're just going to work with Susan to see if we can get her password real quick. So let's go over to the Kraken CD hashcat. And then I'm going to go in hashes. And we can call this perfection.

And I'm just going to paste that. And now let's take a look at the man page for hashcat. Because we're actually going to use a attack mode here.

And we normally don't use attack modes in hatch cat, because we're just cracking off a dictionary. We want to manipulate something. So we got the modes, we got the straight, there's the one we normally use. but I'm going to use the brute force.

You could also use like the word list and mask. That's going to like combine the brute force with the mask. So if you wanted to have a word list of multiple names, you could, I tried doing a lot of that, but I couldn't get a rule file to do what I wanted to, because we have to do the username, then an underscore, then the username backwards. Right.

And I tried a long time. Let's see if I can remember this real quick. Let's just do echo Ipsec. And then we can say dot slash hash cat is it STD out and then dash J for a rule. So if I just do dash J, I want to append a underscore, right?

So this is how I was playing around with rules. So I could get that working. And then Fuf is reflect the word backwards.

But every time I did that, I had this underscore here. I couldn't figure out for the life of me how I can reflect the word and delete a character, right? The bracket is delete the first character. So I was hoping that would delete the reflected character If you're curious all this if we google like hashcat Um, probably rules will bring us to the page we want rule based attack So we can see how a lot of the rules works here, right?

So that's where I was getting it from um, but all these rules like either require knowing the position. And there's no way I could figure out how to get the length of a word's position. This whole memorize functionality looked helpful. But if we look at the plus note, it indicates it's in hashcat legacy, not the new one. So I couldn't like memorize a word then replay it.

Maybe someone in comments can help me but I just couldn't figure out how to get it in the format I wanted to with just a rule file. So I resorted to the brute force because we can specify characters here right so let's do hash cat and then we'll do attack mode three and then let's go into hashes perfection and then we can say susan underscore nasus underscore and that was a billion so i'm going to do nine digits so one two That should be nine digits. And then if we run this, it's probably going to tell us we match multiple hashes.

We want to use mode 1400 because it's just a SHA-256. I guess I don't know what SHA-3256 is. But here we go. It is going to start running. And let's see how long does it expect to take?

Oh, it's already done. So we got recovered one out of one that was like near instant. Um, I think if we switch to attack mode six for some reason it goes a lot slower. So we see that took 15 seconds on my computer I can do Uh, let's try going to attack mode six.

So we'll call this combinator dict I guess or I misspelled that I'm gonna do susan nasus like that. Um, actually, let's get the word list real quick. Let's see What did it crack? dot slash hashcat bin 1400 hashes perfection show. So here's the password.

Let's just see if this works real quick. And then I'm going to go look at hashcat. So if we do a sudo dash L, paste in the password, looks like we can sudo so I'm gonna do sudo su. And now we're rude, right? So I just want to show why did not switch to attack mode six.

So we got that combinator dict file. So if we did this correctly, let's see, we should be able to do mode six like that. And then we specify like this, right?

We want to Remove the pot file. Hashcat pot file. There we go.

So we'll see how long this takes. I don't think it's going to take just 15 seconds. I don't know why doing it this way is slower, but it is.

Or maybe we just got lucky how it hit the digits. That is also very, very possible. So I'm just going to let this run and we're going to run it twice to see if it's the same on combinator right. Because there's only one word I think it's only going to use one of my GPUs. I don't know if it did that before but I'm going to pause the video and we'll see how long this one takes.

I know I said we'd let this crack finish but it's been a couple minutes and I am only like eight percent of the way through so i'm gonna kill this i'm gonna look at the speed we're at uh 274,000 hashes a second on one gpu with the combinator mode we're going to run what we did before with um let's see what is it this right here and see what speed this goes so 274,000 hashes a second we'll see how quick this is Wow, a lot faster, right? This is like exponentially. So we didn't just get lucky.

Using attack mode six with just one word in the word list makes it go really slow. The brute force mode with one word makes it go a lot quicker. I'm just guessing it's like less processing when it does it this way.

I'm not exactly sure where all that IO is coming from. But as you can see, if you use the combinator mode, you need to have a pretty big arm. Word list.

I'm actually kind of curious if we duplicated this a bunch, if it goes any quicker. Probably not because it's probably gonna use the same number each time, but it may use more GPUs. We got to move that pot file again.

Let's see how quick is this? So at least we're, oh, we still only just use one GPU. So that does not speed it up any.

So yeah, if you do this and you just have one word, you could use combinator. It works, but definitely use the brute force mode when you can over combinator because it's quicker or at least hybrid wordless combinator. So with that being said, that is the video.

Hope you guys enjoyed it. Take care and I'll see you all next time.