Reflected DOM XSS at ServiceNow - CVE-2022-39048
Hey everyone, I hope you all are doing good. This is a blog post of my another finding.
I started doing more research on ServiceNow after finding CVE-2022-38463. After spending some time at recon, I found an endpoint - ‘/assessment_redirect.do’ which has a parameter ‘sysparm_survey_url’ and value was reflecting in response in JavaScript.
We have this JavaScript code:
<script eval="true">
// For security issue, we need to control the domain and redirect to "assessment_take2.do" ui page. If url is trying to redirect to external domain, we will force to redirect to "assessment_list.do" page.
var unwrapped_url = "VALUE-OF-sysparm_survey_url";
var urlWithoutProtocol = unwrapped_url.replace(/(^\w+:|^)\/\//, '');// remove url protocols like "https://, http://"
var redirect_page = extractHostname(urlWithoutProtocol);
if (redirect_page === 'assessment_take2.do')
document.location.href = urlWithoutProtocol;
else
document.location.href = "assessment_list.do";
</script>
In above code snippet, value of ‘sysparm_survey_url’ parameter is reflecting in variable : unwrapped_url and then it is removing the ‘http://’ or ‘https://’ using regex:
unwrapped_url.replace(/(^\w+:|^)\/\//, '')
Then it is using a function ‘extractHostname()’ and this will split the value of unwrapped_url at ‘/’ and then return the value.
function extractHostname(url) {
var hostname;
//find & remove protocol (http, ftp, etc.) and get hostname
if (url.indexOf("//") > -1)
hostname = url.split('/')[2];
else
hostname = url.split('/')[0];
//find & remove port number
hostname = hostname.split(':')[0];
//find & remove "?"
hostname = hostname.split('?')[0];
return hostname;
}
here this function is checking if url has ‘//’ then split the url and return value at 2nd position starting from 0 else it will split and return the value at 0 position.
For example: If url is ‘aman//rawat’ then it will return ‘rawat’ and if url is ‘aman/rawat’ then it will return ‘aman’
then it is checking the value of ‘redirect_page’ variable. If value of ‘redirect_page’ is equal to ‘assessment_take2.do’ then it will redirect user to value of ‘sysparm_survey_url’
var redirect_page = extractHostname(urlWithoutProtocol);
if (redirect_page === 'assessment_take2.do')
document.location.href = urlWithoutProtocol;
else
document.location.href = "assessment_list.do";
redirecting to ‘urlWithoutProtocol’ using document.location.href makes this vulnerable to XSS because we created a payload to bypass the check in if statement and then we can get the XSS.
Payload: 'javascript:alert()//assessment_take2.do'
So, we give the above payload in parameter: ‘sysparm_survey_url’ and then it will bypass the check where ‘redirect_page’ variable must be equal to ‘assessment_take2.do’ because of extractHostname() function, value of ‘redirect_page’ will be ‘assessment_take2.do’.
And then it is redirecting to ‘urlWithoutProtocol’ using ‘document.location.href’ and value of ‘urlWithoutProtocol’ is ‘javascript:alert()//assessment_take2.do’ where ‘assessment_take2.do’ will be treated as comment and JavaScript will be executed.
Recommended Fix
Update ServiceNow instance to version - Tokyo Patch 1a, Patch 2, San Diego Patch 7b, Patch 9, Rome Patch 10 HotFix 2b, Quebec Patch 10 HotFix 10b.