It happens that when performing XSS of the reflected type, the parameters go directly to the body of the script tag. This usually means that the exploitation is trivial: encoding parentheses will not interfere, many firewalls will not interfere, including the now defunct Chrome XSS Auditor. But CMS Bitrix for this case has its own built-in proactive filter (WAF), the principle of which, when protecting against XSS, is similar to the XSS Auditor.
When fuzzing the Mail.ru service as part of the Bug Bounty, I encountered an entry point where the GET parameter fell into the body of the <script> … </script> tag . But it was not possible to make a simple PoC, since the application was built using Bitrix, and the WAF module was activated.
Any attempts to insert some interesting code ended in replacing the entire script with a stub <! – deleted by Bitrix WAF -> .
It turned out that to neutralize this protection, it is enough to pass null byte (% 00) in the vulnerable parameter .
For demonstration, we will deploy a test application on CMS Bitrix with the WAF module activated and add the following code to one of the pages (/waf-bypass.php):
If you pass a quote (closing string) and call alert (like any other function) to the vulnerable page parameter , then WAF cuts out the entire script:
During fuzzing, it turned out that it is very easy to bypass the protection – before the closing quotation mark, enter null byte ( % 00 ) and WAF is already skipping the code.
In total, we get a full-fledged vector of exploitation:
The error lies in the post-filtering module for XSS protection. The module works similarly to XSS Auditor and tries to find script tags in the body of the page with active content that was passed in user parameters.
At the same time, for some reason, a zero byte is cut out from the parameter values, so in our case, when comparing the body of the page with the parameters, no occurrences will be detected (after all, there is \ x00 in the body, but not in the parameters).
Vulnerable line in ./bitrix/modules/security/classes/general.post_filter.php / post_filter.php , where chr (0) null byte is stripped in the addVariable method :
The search for user data in the script body itself occurs in the isDangerBody function , and here the untouched $ body value and an array of parameters are passed to the findInArray function , from which a zero byte is stripped:
Remember that WAFs are almost always workable and may have bugs in them. You should not rely on firewalls, you need to build a secure development process and regularly conduct application penetration tests .
In this particular case, to fix an error in the WAF itself, you can remove the str_replace call from the addVariable function. At the same time, just in case, it is worth adding a check for the presence of a zero byte in the content (it is not for nothing that Bitrix developers once added this call to str_replace).