imCMS 4.3.7 - Multiple Vulnerabilities

Photo by cottonbro from Pexels

I usually do some research and write an article at the end of the year, but due to the time it takes to process multiple vulnerabilities I usually miss my deadlines (By like six months this time). The notes have to be structured from the mess that is my spread out scribbling, the vulnerabilities have to be reported to the vendor. Then fixes have to be agreed upon if that is needed, and a publishing date has to be discussed in case the vendor needs extra time (meaning more than 90 days) to release and communicate with users/customers of the product. I often publish earlier than 90 days, but only if the vendor agrees that this is okay.

Anyway, so here I am again. I started looking into this CMS system in November but didn’t actually speed up and find the more juicy stuff until around Christmas and then a lot more as I write this now in January. I first stumbled on imCMS many years ago when I found a municipality website that used it and it caught my attention simply because I had never heard about it before then.

So what is imCMS?

imCMS, or as we prefer to call it I’m CMS, is a project that has been developed during more than 10 years. It is a java-based CMS system, with tag-based templates, and using MySQL DB (even MS SQL works). The system is used in more than hundred installations in Sweden, most frequently within the public sector.

Now that we know what kind of system this is I’ll just dive into the vulnerabilities. It should be noted that I have only taken a quick look at versions before 4.3.7 but it is very likely that many of the earlier ones are vulnerable as well.

Server-Side Request Forgery (SSRF)

This is actually the first vulnerability that made me want to give this system some extra attention years ago. Saw the code at one point and figured I’d take an extra look at this one day. The system has a servlet called “ImageHandling” that fetches local or remote images to display to the user. Fiddling with the local images never resulted in anything in the end, but using the remote method worked perfectly and results in an SSRF.

https://github.com/imCodePartnerAB/imcms/blob/4.3.7/server/src/com/imcode/imcms/servlet/ImageHandling.java#L195

Working as intended, basically.

GET /imcms/imagehandling?url=https://192.168.50.111/test.php

Checking the log at the remote system yields the expected entry. I didn’t have any local or otherwise isolated system to demonstrate the issue on further but I think this is good enough, the fun has only begun.

[26/Jan/2021:11:51:48 +0000] “GET /test.php HTTP/1.1” 200 34 “-” “Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36”

The getExternalFile function that is the cause of this issue should preferably just be removed completely. Sure you can try to restrict it so that it can’t reach internal resources but there’s always that risk that someone will figure out a way to bypass it and realize that it’s still vulnerable.

Denial of Service

This next vulnerability is directly related to the SSRF one in that it uses the exact same function to fetch remote files. I noticed while reviewing the code that the getExternalFile function creates temporary files where it dumps the data that is fetched from the remote host.

File file = File.createTempFile("external_file", ".tmp");            InputStream input = null;
OutputStream output = null;

And it only stops and deletes the file if there’s an exception. However the files does not always seem to be deleted even when the request gets a timeout from either end. If the disk is full and throws an exception it will try to delete the file once but dropping large files and then just leaving them there efficiently fills up the disk and starts throwing errors in the logs.

So by placing a script on a remote host that “never stops sending”, we can fill up the disk space of the server.

<?phpwhile(true)
{
echo "a";
}

Then we make ask imCMS to please fetch our file for us.

GET /imcms/imagehandling?url=https://192.168.50.111/test.php 

As expected the connection just sits there, chewing away at the data until the disk is full, and this is with one thread and one connection open only. If I added more threads and connections I imagine this would be a lot worse for the poor server.

root@user-imcms:/tmp/tomcat8-tomcat8-tmp# ls -lah
total 6,4G
drwxr-xr-x 2 tomcat8 4,0K .
drwxrwxrwt 21 root 4,0K ..
-rw-r----- 1 tomcat8 6,4G external_file17675052495731732726.tmp

Sometimes the file was actually removed. Looking at the logs revealed that an exception was thrown when the disk space ran out and the file was still being written to; resulting in imCMS attempting to clean up after itself.

com.imcode.imcms.servlet.ImageHandling - No space left on device

At the time of writing the above test has rendered the site useless and wont respond. Nothing in the logs, and the process appears to be running still. Restarting tomcat appears to have done the trick though and it now responds again.

By solving the SSRF the recommended way this problem will also go away. In the case of not solving the SSRF then the file size that can be fetched should at the very least be limited to avoid the file filling up the disk.

Arbitrary File Read 1

The administrator for imCMS has a number of interesting functions at their disposal. One such function called FileAdmin is to view a number of files in imCMS like css and images. The files that can be read through this function is limited to a specific folder and files and from the looks of it you are not intended to get access to anything else.

Directory view of FileAdmin

A request to view one of the files under the folder looks like this.

Request to view file via FileAdmin

Changing the dir1 and dir2 parameters didn’t yield any interesting results. I simply got an empty response back from the server. The files1 parameter, however, gave a much more promising response when I tried to fetch the /etc/passwd file.

files1 manipulated

Which results in the following response.

/etc/passwd file content

Allowing the application to read files is dangerous as it is, but at the very least one should validated the input and make sure it sticks to the folders it’s supposed to and that it does not allow “../” or full paths.

Arbitrary File Read 2

While messing around in FileAdmin I found that files can also be edited. Via this second method the file can only be read if the tomcat user has permission to edit the file, which is a bit more limited.

style.css being read in FileAdmin

That doesn’t prevent us from reading the server.properties file with the database password though. Attempting path traversal was a success.

Again resulting in a restricted file being read.

server.properties read from FileAdmin_edit.jsp

Arbitrary File Read 3 (limited)

While this is an arbitrary file read in a sense, it’s also not. The file is being read but is interpreted as a Java properties file, and the output value is then run through Int.Parse. Meaning the data has to be a number to be returned. We can exploit this to read a value from server.properties if said value is a number. So if the password is 1234 we can read it. Limited, but still interesting to mention. One interesting aspect about this is that it’s completely unauthenticated, so could have been a lot worse.

https://github.com/imCodePartnerAB/imcms/blob/4.3.7/server/src/com/imcode/imcms/servlet/Help.java

The name and lang parameters are used to look for a help file and a key inside it, but can be manipulated to return something else. Further down in the code the value is parsed as an Int and then returned as a redirect.

https://github.com/imCodePartnerAB/imcms/blob/4.3.7/server/src/com/imcode/imcms/servlet/Help.java#L33

Returned value in Location header

Cross-Site Scripting (XSS)

I kept finding XSS vulnerabilities so my bet is that there are more to be found here. I’m going to list a few though. This first one is actually in the FileAdmin_edit.jsp file mentioned earlier. The file parameter is vulnerable with the restriction that it has to end with a valid file name, else it will return an error that the file can not be edited. It should be noted that this page requires the user accessing it to be in the administrative group.

GET /imcms/imcms/eng/jsp/FileAdmin_edit.jsp?file=%3Cimg%20src=x%20onerror=alert(1)%3Eindex.jsp
XSS in FileAdmin_edit.jsp

Cross-Site Scripting 2 (XSS)

Another one which is not very unlike the previous one, was found in one of the sample pages under /imcms/docs/apisamples. The file mail_send_file_document.jsp is vulnerable via the id parameter.

/imcms/docs/apisamples/mail_send_file_document.jsp?id=%3Cimg%20src=x%20onerror=alert(1)%3E

The result is the same as the previous so I’ll save you the screenshot.

Information Disclosure

imCMS has a servlet that simply outputs some information. It works as intended but gives away system information unauthenticated, which is unnecessary. Interestingly it says that the version is 4.3.8 although the one installed is 4.3.7. Looking in their repository tells me that 4.3.8 might just be a typo in a config file somewhere.

Version servlet

Unvalidated Redirect

The login page uses the parameter next_url to redirect the user after a successful login has been made. This can be exploited to redirect the user to an arbitrary site. This means that if an attacker can get an administrator to click a prepared link then the redirect can take the administrator to a malicious page once the login occurs. For instance, the administrator gets the link via a message saying something convincing like “there’s an error on this page can you please take a look?”. The admin enters their credentials and logs in, but is redirected to another website with an identical login page which again asks them to login. Not noticing that it’s a different URL they have been taken to they think the password was incorrect and enters it again. The page saves the credentials for the attacker to keep and then redirects back to the original page; where the administrator is already logged in and thus thinks this second login attempt succeeded.

The below example would take a user to Google after authentication. If external redirects are really needed here it should at least ask the user if they want to continue to the destination, or at least have an allow list of URLs that can be redirected to.

http://192.168.50.135:8080/imcms/login/?next_url=https://google.com

Cross-Site Request Forgery (CSRF)

This will include a few more things than just CSRF actually. It’s a combination attack using CSRF, and Arbitrary File Upload. I was considering splitting them up as I have done in the previous findings but this one is better demonstrated with a little PoC. Burp Suite has a very handy feature where you can tell it to generate a CSRF PoC for you, which is very lovely. The request itself is nothing special, but you will notice that there is nothing here that suggest there’s any protection against CSRF. Since this application uses the Spring Framework it could also utilize the CSRF token implementation that exists in it.

FileAdmin uploading a shell

The above request can be turned into a CSRF PoC easily with Burp Suite Pro (Which I don’t have on this computer and thus I cannot show you the option in the menu currently, but it’s there, I promise). Pasting code in this editor is horrible so I’ll show a snippet as a screenshot instead.

CSRF PoC generated by Burp Suite Pro

If an attacker puts the above PoC in a csrf.html file and hosts it somewhere, then gets an administrator to visit the page; the shell will be dropped on the server.

Shell uploaded successfully

The shell is then accessible via the browser.

Arbitrary File Upload

This is another Arbitrary File Upload like the one above, and this one is also vulnerable to CSRF. This one was found in the TemplateAdd servlet. The different thing about this one is that the file can be placed anywhere (as long as we have permission of course) thanks to path traversal in the same function and a feature that lets us overwrite files (meaning if tomcat for some odd reason were to be run as root we would be able to overwrite any file, like /etc/passwd). In this case we could actually overwrite the server.properties file and reconfigure the site but that is a bit risky as I’m pretending that I can’t read any other files from just this vulnerability, and thus can’t possibly know the contents of the current properties file (risking ruining the site if I do and alert the administrator).

For this next trick I’ll just put an evil file in the /tmp folder.

TemplateAdd servlet path traversal.

The file turns up in the tmp folder as expected. Notice the overwrite option that we have in the above sample. I saw somewhere in the code that there is a hint of file extension restrictions implemented into imCMS, but then it doesn’t seem to be used by default at least. It would be preferable if it was secure by default and if administrators want to upload dangerous files then they need to configure it specifically to do so.

root@user-imcms:/var/lib/tomcat8/webapps/imcms# cat /tmp/test.jsp 
evil code

Path Traversal

Another Path Traversal with file reading, although this one only allows reading of arbitrary image files. This is due to the code below trying to parse it as an image and send it to the client.

https://github.com/imCodePartnerAB/imcms/blob/4.3.7/server/src/com/imcode/imcms/servlet/ImagePreview.java#L125

So if there are any secret images on the server, at least we can access those

http://192.168.50.135:8080/imcms/servlet/ImagePreview?path=/images/../../../../../../../tmp/secret.jpeg&format=jpeg
Secret image accessed through traversal

Gotta keep them potatoes safely hidden away.

Stolen potato data. Photo by Pixabay from Pexels

Timeline

2021–01–25: Vendor responded that they will take a look at it

2021–01–26: More details sent to vendor to help with recreating issues

2021–01–26: Vendor responds that they will reply next week with more comments on the issues. At first glance the Arbitrary File Read vulnerabilities are non-issues according to them.

2021–03–02: CVE IDs assigned

2021–03–02: Report to vendor that IDs have been assigned. They respond that they will book a meeting with me next week and comment on the issues.

2021–03–23: cert.se contacted for advice on how to handle potential users of the product, how to alert them etc. cert.se replies that they have contacted vendor and had a good conversation. cert.se tells me that vendor will get back to me shortly.

2021–03–31: Vendor contacts me and wants to book meeting for coming week. I get back with a suggested time.

2021–04–06: Very good meeting with vendor. Small talk and talk about fixes. So far no wishes to move deadline of disclosure. Will keep in touch.

2021–04–21: Request from vendor to move date of publishing from 25th of April to 9th of May.

2021–05–03: Vendor sends an e-mail wanting to discuss retesting of findings. Very pleasing to see that they are taking this so seriously.

2021–05–07: Request from vendor to move date of publishing due to delay in rolling out patches. Will sync next week to set a new date for publishing.

2021–05–10: Retested findings after vendor issued patches. Sent report to vendor. Waiting for vendor to have time to discuss bypasses of fixes.

2021–06–08: New retest scheduled. New date for publishing of this article set to 2021–06–09.

2021–06–09: Last minute retesting to make sure important fixes had been applied (seems they have been).

The End

Cheers!

I program, hack, and write odd stories. I am an independent security consultant.