I recently completed the PC target on HackTheBox and thought it would be good to share a write-up of how I went about getting user and root access to the machine. Overall, I thought this was a great machine. Surprisingly, it tested my mental thinking when it came to pentesting. Unfortunately, I lost a lot of time due to not doing a full/complete reconnaissance process on the box, but it was a good learning experience. Let’s get into it

Recon time

After running our initial nmap scan, we can see that ports 22 (ssh) and 50051 (grpc) are open. I like to run nmap with the “-oA” flag since it gives you all output formats.

nmap -sV -sC -O -Pn -p- 10.129.117.8 -oA nmap_results

On port 22, nothing interesting or out of the ordinary jumped out at me. I tried some low-hanging fruit such as default login creds, but nothing took. Ran the ssh NSE scripts that come with nmap as well and did not find anything interesting. Also ran ssh-audit.py, saw a couple of CVEs that could lead me somewhere, and decided to come back to those later after exploring port 50051.

Figure 1

Going into this, I didn’t know the gRPC ran on a default port of 50051, so that was a bit of learning I needed to do on the fly. Since nmap didn’t return what service was running on that port, I was a little lost. I decided to try opening that port via the browser to see what I could find

20230620062749.png

Looking back on this, I probably should have just done a simple nc -v 10.129.177.8 50051, but I’ll remember that for next time. With this output, I went down the road of decoding/deserializing via CyberChef spending +2 hours trying to understand what the heck this was… 😅

Lo and behold, ChatGPT is to the rescue! 🙌🏼🔥 I figured, since ChatGPT is good at analyzing text and making a great guess at what it is, maybe if I put the serialized data in there it might tell me what it thinks it is. And yes, ChatGPT responded that the serialized data might be gRPC - back on the right track. (Though I do feel a little bad using ChatGPT so quickly, I will say it helped me focus on where I needed to go. Like I’ve said before, conducting better recon would have helped a ton here. Something to make note of going forward for myself).

After establishing that 50051 was a gRPC protocol, I started down the rabbit hole of understanding how gRPC works. I found two really useful tools during this research: grpcurl and grpcui. Both tools helped to explore and interact with the protocol, leading to an enumeration of the programmed functions, LoginUser, RegisterUser, and getInfo.

Figure 2

You can run the methods by just running “Service/Method”. By sending empty messages, we can start to understand the arguments needed by the returned error responses

I found grpcurl to be a little clunky when trying to experiment with function calls, so I started using grpcui. In the LoginUser function, I found the default creds of admin:admin to successfully login. You could also successfully register a user and login with that, receiving the token you need to utilize the “getInfo” function.

I decided to play around with the getInfo function looking for some kind of SQL Injection based attack. And as I started playing around, I go an error message back:

Figure 3

Perfect. This error tells me that I’m running a Python-based gRPC API using SQLi as the DB. The id argument is used directly in what seems to be an execute() function in the Python3 SQlite library. Unfortunately, the execute() function doesn’t like that I’m using colons to end the statement. This makes things a bit harder, but this tells me that I needed to try a UNION based injection to chain SQL commands together.

This lead me to run an Integer/String based extract name SQL query to enumerate the table.

Figure 4

And as you can see below, I was able to see how the accounts table is structured.

Figure 5

Now all I needed to do was to list the usernames with passwords. After running SELECT password FROM accounts I was able to deduce that there was an already existing username and password pair before I created admin:admin using RegisterUser() gRPC function.

Figure 6

Figure 7

(I don’t know why, but I forgot to get a screenshot of SELECT username FROM accounts, but since the username column had the UNIQUE constraint, it was harder to extract what the username was. This might be due to my lack of knowledge in SQL, but I was successful by using hex(substr(tbl_name,1,1)) to extract each hex value of the username, which came out to be sau).

After extraction, time to try an ssh login using the creds. And boom. We have user access 😎

Figure 8

Privilege Escalation

Now that we have user access, it’s time to get privilege escalation to root. After some basic recon of the system, I see an interesting port via netstat only listening on 127.0.0.1, port 8000. Port 53 was also open and could be DNS, but I figure focusing on 8000 would be the way to go since it seemed to be a WebApp.

Figure 9

(Apologies, but I forgot to get screenshots for the rest of this walk-through 😅 In my next walk-throughs, I will try to be more thorough) Doing ps -ef showed me that port 8000 seemed to be a Python application called PyLoad, a download manager written in Python. I created a ssh tunnel through my Kali machine and was able to access the webapp. I tried brute forcing the login/page discovery and SQL injection again with no luck.

At this point, I went down the wrong path. I started to give up on PyLoad and see if priv esc was elsewhere by running linpeas.sh. To save some time writing this and without having to describe all that I did (and time wasted), I went back to the Pyload application and did more recon based on tips sent in the form post for the PC machine on HackTheBox. After just a simple pyload exploit search on Google, I came across CVE-2023-0297: Pre auth RCE in pyload, which the pyload webapp that was running is vulnerable to.

After reading all of the details of how to execute the exploit, I could simply send a POST message via curl to execute commands as root user on the box. I had trouble creating a bash one-liner to either create a reverse shell to Kali or change the password to the root user, so I ended up creating a .sh file in the /tmp directory that created a backdoor, admin privileged account called frank.

Figure 10

And just like that - I was in. Machine pwnd ✅

Figure 11

Figure 12

Conclusion

Overall, this was a fun box itself. What was not fun for me was quickly giving up and moving on, without giving myself enough time to do proper research and recon. But that’s something to work on going forward.

Thanks for reading my write-up! If you have any questions, comments, or suggestions, feel free to message me on Twitter(@bytefl0w) or send an email to [email protected]. Stay tuned for more writeups and content coming soon!