BOOK THIS SPACE FOR AD
ARTICLE ADSalesforce Lightning is a CRM product that you will often see as the backbone of an organization's help or support pages. It makes it really easy to set up an application that serves guides and help pages and manage permissions for these. It does a lot more that may be interesting to the organizations that utilize it, but for our purposes as security testers, we will talk about the permissions on help pages.
Much like WordPress, when you see an application using Salesforce Lightning to provide help pages and articles to a public audience, you aren’t looking at a simple static website — you’re interacting with a complex set of content delivery mechanisms that as you will shortly see, feels a lot like interacting with an API.
I don't work with Salesforce Lightning on the application side, so I can’t say for certain what causes permissions issues to seemingly be so common. However, a quick search through disclosed bug bounty reports and even what I have seen myself shows that many simple help pages are accidentally allowing unauthenticated guests to access files that you couldn’t imagine.
When you request content from Salesforce Lightning, you send a request to one of these endpoints:
/aura/s/aura/sfsites/aura/s/sfsites/aura — MOST COMMONand either via GET or POST, you provide two main parameters:
message — Essentially, your request to Lightning asking it for the content you wantaura.context — A value that indicates your environmentFor our purposes, the aura.context is a static value that you can pull from the responses of navigating to the application using Salesforce Lighting when you visit it through normal means.
message is how you take advantage of loose permissions. The following is a standard value for the message parameter that we will use as the baseline for checking these permissions issues:
{“actions”:[{“id”:”123;a”,”descriptor”:”serviceComponent://ui.force.components.controllers.lists.selectableListDataProvider.SelectableListDataProviderController/ACTION$getItems”,”callingDescriptor”:”UNKNOWN”,”params”:{“entityNameOrId”:”{ENTITY}”,”layoutType”:”FULL”,”pageSize”:100,”currentPage”:0,”useTimeout”:false,”getCount”:false,”enableRowActions”:false}}]}```Within this, I have edited the parameter value to denote that the value for entityNameOrId, {ENTITY} can be replaced with any number of values to retrieve different responses. This is all very normal and how Salesforce Lightning is meant to work — in fact, nothing we do here is an exploit or ‘hack’ at all.
Now, if we aren’t passing a payload or doing anything differently than a normal user, then where’s the security flaw, you might ask? Recall that this is a permissions issue and consider how roles might work in a help site. It may be the case that the unauthenticated area hosts simple help guides while being authenticated (sometimes this authentication may not be open registration but requires you to be a paying customer), gives you access to something akin to a forum. In this example we have two roles for consumers of the application — Guest & Customer
Two possible ways that permissions issues show up in a scenario like this:
Uploaded files by authenticated users or by the organization itself has lax permissions allowing the Guest role to access them directly even if the UI doesn’t show them.There is no Guest role. authentication built on top of Salesforce Lightning controls what you see in the app as an unauthenticated user or an authenticated user, but ultimately you have the same Lightning permissions as anyone else.We end up seeing this in the real world as well. For example, take a look at this disclosed Acronis bug bounty report:
Ok so enough of the theory, how do you actually find out if an application using Salesforce Lightning has this issue? Recall the message parameter for the Aura endpoints above. I mentioned that there were multiple values you can use within that parameter to request different information. Lets go over a few interesting ones:
user — check what user/role you are operating as. Expect to see some sort of variation on guest, but if you see anything else, you might be in luck.Knowledge__ka — get a list of help pages and articles. you probably wont find anything interesting here.CollaborationGroup— lists Salesforce “Chatter Groups.” Read more about those here. You may find groups here that were never meant to be public.ContentDocument — Files available for download. This is where you see these permissions issues provide the most value.Lets go over an example of how you could pull out sensitive information if the permissions are all messed up.
First you want to go to a website using Salesforce Lightning — you are probably in the right spot if the URL looks something like https://example.com/s/ and then every time you click somewhere your browser starts sending a bunch of requests to https://example.com/s/sfsites/aura
Next you want to capture one of these requests to /s/sfsites/aura and change the message parameter value to the following:
{"actions":[{"id":"123;a","descriptor":"serviceComponent://ui.force.components.controllers.lists.selectableListDataProvider.SelectableListDataProviderController/ACTION$getItems","callingDescriptor":"UNKNOWN","params":{"entityNameOrId":"ContentDocument","layoutType":"FULL","pageSize":100,"currentPage":0,"useTimeout":false,"getCount":false,"enableRowActions":false}}]}Send that request and expect to see something like this in return:
HTTP/2 200 OK[SNIP]
{"actions":[{"id":"123;a","state":"SUCCESS","returnValue":{"result":[{"record":{"LastModifiedDate":"2019-03-29T03:43:13.000Z","LastModifiedDate__f":"8/21/2024 09:59 PM","Description":null,"CreatedDate":"2019-05-23T23:29:17.000Z","Title":"04106154egami.png","Id":"069488590040JTJNA6","LastModifiedById":"00492800001qittKAA","SystemModstamp":"2024-09-04T08:17:04.000Z","CreatedDate__f":"9/7/2019 10:45 PM","sobjectType":"ContentDocument"}},
[SNIP]
The important info returned here is that Id value:
"Id":"069488590040JTJNA6"we can plug this into
https://example.com/sfc/servlet.shepherd/document/download/{DocumentID}and easily download the file. Go ahead and do this for all the returned files and see if you have anything sensitive. When I first started checking this, I would put the download request into Burpsuite Intruder and just go one by one checking for interesting filenames or abnormally large files via the responses, but when you get hundreds of files from one application, this isn’t very fun.
Lucky for you, I went ahead and created two tools to help make this easier.
The first is a simple Nuclei template that will determine if the application uses Salesforce Lightning by visiting the /s/ path and trying to pull the aura.context value from the response. If it is successful at that, then it will go ahead and attempt to ask for ContentDocument. Upon successfully confirming that the application will provide you with document IDs, you get alerted to a medium finding. Sorry if a medium seems too high, but I originally wrote this for my bug bounty automation, and I wanted to make sure I got an alert whenever this was found so I could check manually.
Anyways, you can find that template here:
The second tool is actually a fork I have been messing with of a tool by moniik named poc_salesforce_lightning. This tool bruteforces through a ton of values you can put into the message parameter in order to enumerate pretty much everything that Lightning will give you as an unauthenticated user and then same the results in a very large set of individual JSON files.
This tool was clearly originally designed as a fun little side project. It was uploaded, had a few changes made over two months, and then never touched again. My fork changed the name a bit for clarity and added a much-needed feature: now, when you use the—d flag to dump all the data, it will create a directory and download all the files you have access to so you can sift through them. The data dump is much more useful now.
Find this tool here:
To use the tool, clone it and start it with the following command:
python3 exploit.py -u https://example.com -dFrom here, it will try all the common Salesforce Lightning endpoints and all of the common entityNameOrId values. If it fails despite that domain definitely using Lightning, you can visit the application and retrieve the aura.context value and give it to this tool with the -a flag
Good luck hunting for these issues!