利用编码攻击

1172 2
HK.JH 2022-2-13 23:44:58 来自手机 | 显示全部楼层 |阅读模式
1. 特定场景解码
客户端和服务端都使用各种不同的编码在系统之间传递数据。当他们想要真正使用这些数据时,这通常意味着他们必须先解码。用什么解码取决于数据出现的场景。例如,URL中的查询参数通常是服务器端解码,而HTML元素的文本内容需要客户端解码。

在构造攻击时,你应该考虑你的 payload 被注入的确切位置。如果你可以根据这个上下文推断你的输入是如何被解码的,那么你就可以用另外一个经过编码的payload代替他。

2. 解码的差异
注入攻击的特征通常容易识别到,如HTML标签、JavaScript函数或SQL语句。由于一般用户从来都不使用这些攻击特征,网站都会进行过滤,阻止包含这些可疑特征的请求。

然而,过滤器也需要对这些输入解码,以检查它是否安全。从安全角度来看,检查输入时执行的解码与后端服务器或浏览器最终使用数据时执行的解码相同,这一点至关重要。任何差异都可以使攻击者通过应用不同的编码偷偷地将有害的 payload 绕过过滤器。

3. URL编码混淆
在url中,一系列保留字符具有特殊含义。例如,符号(&)用作分隔符来分隔查询字符串中的参数。那么产生一个问题,基于url的输入可能因为不同的原因而需要包含这些字符。考虑一个用户搜索查询的参数。如果用户搜索“Fish & Chips”会发生什么?

浏览器会自动对可能导致解析器歧义的任何字符进行URL编码。这通常意味着用%字符和它们的2位十六进制代码替换它们,如下所示:

[...]/?search=Fish+%26+Chips
这确保了&号不会被误认为分隔符。尽管空格字符可以被编码为%20,但通常用加号(+)代替,如上例所示。

任何基于URL的输入在分配给相关变量之前都会在服务器端自动进行URL解码。这意味着,就大多数服务器而言,查询参数中的%22、%3D和%3E等序列分别等同于“、<和>字符。换句话说,你可以通过URL注入URL编码的数据,他通常仍然会被后端应用程序正确地解析。

偶尔,你可能会发现WAF等在检查输入时无法正确地对URL进行解码。在这种情况下,你可以简单地通过编码任何被列入黑名单的字符或单词,将 payload 偷运到后端应用程序。例如,在SQL注入攻击中,你可能会对关键字进行编码,因此SELECT变成%53%45%4C%45%43%54等等。

4. URL双重编码混淆
出于这样或那样的原因,一些服务器会对接收到的任何URL执行两次URL解码。这本身并不一定是个问题,只要任何安全机制在检查输入时也会对其进行双重解码。否则,这种差异使攻击者能够通过简单地对恶意输入进行两次编码,从而将其偷运到后端。

假设你试图通过查询参数注入一个标准的XSS PoC,例如<img src=x onerror=alert(9)>,在本例中,URL看起来像这样:

[...]/?search=%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E
在检查请求时,如果WAF执行了标准的URL解码,它将很容易识别出这个众所周知的 payload 。请求永远无法到达后端。但是如果你对注入进行双重编码呢?实际上,这意味着%字符本身会被%25替换:

[...]/?search=%253Cimg%2520src%253Dx%2520onerror%253Dalert(1)%253E
由于WAF只解码一次,它可能无法识别请求是危险的。如果后端服务器随后对该输入进行双重解码,则成功注入 payload 。

5. HTML编码混淆
在HTML document中,需要对某些字符进行转义或编码,以防止浏览器将它们错误地解释为标记的一部分。这是通过以&号为前缀,以分号结束的编码格式替换掉特殊字符。例如,&colon; 表示冒号字符。或者,可以使用字符的十进制或十六进制,在本例中是 &#58; 和 &#x3a; 分别表示。

在HTML中的特定位置,例如元素的文本内容或属性的值,浏览器在解析document时将自动解码这些引用。当在这样一个位置内注入时,偶尔可以利用这一点来混淆客户端攻击的 payload ,将它们隐藏起来,绕过服务器端防御。

如果仔细观察前面示例中的XSS payload ,会注意到 payload 被注入到HTML属性中,即onerror事件处理程序。如果服务器端仅仅过滤alert() payload ,如果你用HTML编码一个或多个字符,它们可能不会发现这一点:

<img src=x onerror="&#x61;lert(1)">
当浏览器加载页面时,它将解码并执行注入的 payload 。

5.1 填充多个零
有趣的是,当使用十进制或十六进制HTML编码时,可以在编码中填充任意数量的零。一些WAF和其他输入过滤器不能充分考虑这一点。

如果你的 payload 在HTML编码后仍然被阻止,你可能会发现你可以通过在编码中加上几个0来逃避过滤器:

<a href="javascript&#00000000000058;alert(1)">Click me</a>
6. unicode转义混淆
Unicode转义序列由前缀\u和字符的四位十六进制代码组成。例如,\u003a表示冒号。ES6还支持使用花括号的新形式的unicode转义: \u{3a}。

在解析字符串时,大多数编程语言都会解码这些unicode转义。这包括浏览器使用的JavaScript引擎。当注入到一个字符串中时,可以使用unicode混淆客户端 payload ,就像我们在上面的例子中对HTML转义所做的那样。

例如,假设你试图利用DOM XSS,其中将输入作为字符串传递给eval()接收器。如果你的初始尝试被阻止,试着转义一个字符如下:

eval("\u0061lert(1)")
由于它在服务器端保持编码格式,可能不会被检测到,直到浏览器再次解码它。在字符串中,可以像这样转义任何字符。但是,在字符串之外,转义某些字符将导致语法错误。例如,()。

同样值得注意的是,es6风格的unicode转义也允许前面填充零,所以使用我们在HTML编码中使用的相同技术,有些WAF可能很容易被绕过。例如:

<a href="javascript\u{0000000003a}alert(1)">Click me</a>
7. Hex(16进制)转义混淆
当注入字符串时,另一个选项是使用hex转义,它使用以 \x 为前缀的十六进制表示字符。例如,小写字母a用 \x61表示。

就像unicode转义一样,只要输入的值是字符串,就会在客户端解码:

eval("\x61lert")
注意,有时还可以使用前缀 0x 以类似的方式混淆SQL语句。例如,0x53454c454354 可能被解码成SELECT关键字。

8. 八进制转义混淆
八进制转义的工作方式与十六进制转义几乎相同,除了字符引用使用base-8而不是base-16的编号系统。它们以一个单独的反斜杠作为前缀,这意味着小写字母a由\141表示。

eval("\141lert(1)")
9. 通过多种编码混淆
需要注意的是,你可以编码组合来将 payload 隐藏在多层混淆之后。如下:

<a href="javascript:&bsol;u0061lert(1)">Click me</a>
浏览器首先HTML解码 &bsol; 为反斜杠。这样做的效果是将后面的u0061字符串转换为unicode编码 \u0061:

<a href="javascript:\u0061lert(1)">Click me</a>
然后进一步解码,形成一个有效的XSS payload :

<a href="javascript:alert(1)">Click me</a>
显然,要以这种方式成功地注入 payload ,你需要确切地了解对输入执行的解码方式和解码顺序。

10. 通过SQL CHAR()函数进行混淆
虽然严格来说这不是一种编码形式,但在某些情况下,你可以使用CHAR()函数来混淆SQL注入攻击。它接受一个十进制或十六进制编码并返回匹配的字符。十六进制编码必须以0x作为前缀。例如,CHAR(83)和CHAR(0x53)都返回大写字母S。

通过连接返回值,你可以使用这种方法来混淆被阻止的关键字。例如,即使SELECT被列入黑名单,下面的注入最初看起来是无害的:

CHAR(83)+CHAR(69)+CHAR(76)+CHAR(69)+CHAR(67)+CHAR(84)
但是,当应用程序将其作为SQL处理时,它将动态构造SELECT关键字并执行注入的查询。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行