Find a new way to RCE on an ancient version of ManageEngine ServiceDesk
This is the way from nothing to RCE on an ancient version of ManageEngine ServiceDesk
ManageEngine ServiceDesk is a comprehensive help desk and asset management software that provides help desk agents and IT managers an integrated console to monitor and maintain the assets and IT requests generated from the users of the IT resources in an organization.
Recently, I have been assigned a task to perform the security check for a server running the ServiceDesk old version, which is not affected by any critical CVE because it is older than the versions affected.
Now, let’s begin with me.
1. Find vulnerabilities in the ServiceDesk
Downloaded its version, I focused on finding unauthenticated endpoints first. In the past, I usually found vulnerabilities by sink (search by strings like Runtime.exec
) but it can be missed, so recently I always check by source.
Quickly I detected an unauthenticated endpoint that led to LFI /fosagent/repl/download-file?basedir=4&filepath=<file>
(After rechecking, it is a known CVE).
Servlet handler is com.zoho.clustering.agent.filerepl.api.DownloadFileServlet
, getting the filepath directly from user input without checking, then returning as an attachment.
Happy tears, I quickly checked inside the folder installed ServiceDesk (SD) to find sensitive files or account leaks. But life is tough. There were some log files but none can be taken advantage of.
I tried to run nmap on this IP and detected that the server was public port 1433 of MS SQL server.
When I installed it locally, I used Postgresql by default, but the document of SD shows that it can change to MS SQL via changeDBServer.bat
file in bin
folder.
So I was trying to take advantage of MS SQL Server.
2. Finding vulnerabilities to access into MS SQL
By default, MS SQL Server when installed will be located in C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\DATA
, and the database name of SD is servicedesk.
Eager to download this file, but noooo.
It is access denied by FileNotFoundException
?? It showed FileNotFound
but in fact, it is access denied, because if it’s FileNotFound
, it will be like this
Ignore it, I found the backup function in SD when running backUpData.bat
A backup file was created in the backup folder (can be customed)
The file name will be added at the time when running the backup job. I didn’t need to brute force to find its name, because it was saved in C:\ManageEngine\ServiceDesk\bin\SDPbackup.log
I felt quite reassured when I saw the file name because it is backed up daily (but not too reassured because the backup is in the server 🙄).
Now I just need to read that file. But again, tantalizing fate made me feel anguished. I can read on my local server but not in target. As you see, the backup folder of the target was in driver D. I have never encountered this situation before so I have not tried, but until now I just knew in Windows by default, when we exploit path traversal from driver C, we can’t traverse to driver D!
The result was not surprising to me.
Now we only have a LFI vulnerability that can read files in driver C, what can we do with it?
I came back to finding vulnerabilities in SD. I detected another quite potential endpoint /fosagent/repl/take-snapshot
, servlet com.zoho.clustering.agent.filerepl.api.TakeSnapshotServlet
. Its function is snapping shot the disk, zipping and saving to C:\ManageEngine\ServiceDesk\server\default\deploy\fosagent.war\snapshots
Combined with the above LFI, we can completely read all data.
I intended to use this vulnerability to download all the disks, but after a while of running, my local server notified me that it had run out of disk space even though it had over 100GB of unused disk.
Full disk
The layoff situation is quite violent, I would be starving if I got fired, so I don’t have enough courage to run it on the target.
Until then, I was burned out so I went to the last solution, which was cracking the sa
password of the MS SQL Server. Password is saved in C:\Program Files\Microsoft SQL Server\110\Setup Bootstrap\Log\<time_of_something_random>\Datastore\ProductSettings_SqlEngine_Public.xml
I didn’t care about what is the full folder path because I could read it in C:\Program Files\Microsoft SQL Server\110\Setup Bootstrap\Log\Summary.txt
I had password
Went to ask ChatGPT but I didn’t get the expected answer.
(After publishing this post, I knew it is DPAPI, ref )
Exhausted by it, I turned around to do other things.
During that process, I had another job, it’s auditing SupportCenter of ManageEngine. I realized their code is quite similar, and when I was debugging, there was a function that helped me extract the raw password of the SQL Server so I decided to dig deeper again.
3. Getting the password of MS SQL Server
As I mentioned above, SD allows user to change the database server by running changeDBServer.bat
, its interface looks like:
After a while, I realized that when I saved the config, turned it on again and tested the connection, it was successful right away. It means it saved the password somewhere. I should think about it sooner.
Tried to debug into the checking connection process, I realized it’s true, more over it loaded the clear text password.
The function that used to load the config is com.adventnet.servicedesk.tools.ChangeDBServer#getDBDetails
.
This function read the config file like this:
So with the MS SQL Server, it was saved in C:\ManageEngine\ServiceDesk\server\default\deploy\mssql-ds.xml
But inside this file, there was no login credential.
Continued to debug, I saw the place it gets username and password is com.adventnet.servicedesk.tools.ChangeDBServer#getDBUserNameAndPassword
So the file that saved the credential is C:\ManageEngine\ServiceDesk\server\default\conf\login-config.xml
It’s great, I can find the user and password, but in the encryption version.
We can see the clear text password above, so it’s sure that it has a decrypt function somewhere. Continue to debug, I see it is org.jboss.resource.security.SecureIdentityLoginModule#decode
After that password became the clear text.
My tears dropped, I read the file to get the password in the server.
I didn’t need to know what is the encrypting algorithm, I just needed to change my password to the target’s password, then run debug again and let the server decrypt it for me.
Successfully login to MS SQL Server from remote.
4. Leverage to Admin and RCE
After accessing DB, leveraging to admin is quite easy, just took me some minutes. Created a new account and upgraded it to the SD admin. It is not so technical so I decided to skip, also it’s a test for the reader if anyone wants to try it.
When we are admin, we can perform RCE through the Custom Trigger function.
SD has 2 functions to RCE for admin by design: Custom Trigger and Custom Schedule. Different from Custom Schedule, which creates a command running schedule after a time, Custom Trigger runs when a ticket is created or edited.
Ending
Follow me for more upcoming blogs.