application/json形式のAWS WAF Bypass

はじめに 起先

技術部の桜です。 这是工程部的樱花。

今回は、application/jsonにおけるAWS WAFのバイパスを試してきました。
在本文中,我们尝试绕过 AWS WAF application/json 。

この記事ではまず、 RFC 8259(The JavaScript Object Notation (JSON) Data Interchange Format)を読む過程でWAF Bypassに使えそうだなと思った事を検証しています。
在本文中,我们首先验证了在读取 RFC 8259(JavaScript 对象表示法 (JSON) 数据交换格式)的过程中,我们认为它可以用于 WAF 旁路。

次に、上記の検証を経て気になったことを検証しています。
接下来,我们在上述验证后验证我们感兴趣的内容。

環境 环境

application/json形式のAWS WAF Bypass

上記のような構成で、セキュリティグループにより自宅IPからのHTTP, SSHアクセスのみを許可しています。
在上述配置下,安全组只允许来自主 IP 的 HTTP 和 SSH 访问。

また、EC2上でDockerを使用し、Nginx、Express×Node.js、PostgreSQLを動かしてXSSを意図的に埋め込んだ脆弱なアプリケーションを構築しています。
他们还在 EC2 上使用 Docker 来构建运行 Nginx、Express×Node.js 和 PostgreSQL 并有意嵌入 XSS 的易受攻击的应用程序。

(Nginxを動かす必要はないとは思いますが、勉強を兼ねて動かしています。)
(我不认为我需要运行 Nginx,但我正在将其作为一项研究来运行。 )

検証について 关于验证

XSSを対象にして、AWS WAFバイパスの検証を行いますが、
XSS 用于验证 AWS WAF 绕过。

実際に悪用できるかはアプリケーションの実装次第(私のさじ加減)のため、検証を行いません。
它是否真的可以被利用取决于应用程序的实现(我的判断),所以我不会验证它。

あくまで、AWS WAFのバイパスのみを検証します。
最后,我们只会验证 AWS WAF 的绕过。

今回、XSSを対象としているため、AWS WAF Web ACLにおけるAWS マネージドルール ルールグループリストの中の一つである、コアルールセット (CRS) マネージドルールグループを使用します。
由于我们以 XSS 为目标,因此我们将使用核心规则集 (CRS) 托管规则组,该规则组是 AWS WAF Web ACL 中的 AWS 托管规则组列表之一。

理由としては、XSSパターンがリクエストボディに存在しないかを調べてくれるルールがあるためです。 (他にもLFIなどを調べてくれたりします。詳しくはドキュメントを見てください。)
这样做的原因是,有一个规则可以检查请求正文中是否存在 XSS 模式。 (他们还查找 LFI 等。 有关详细信息,请参阅文档。 )

また、ルールにはバージョンがあり、AWS マネージドルールの一般的なバージョン状態によると、
规则也有版本,根据 AWS 托管规则的一般版本状态,

デフォルトバージョンは推奨されている静的バージョンを指します
默认版本是指推荐的静态版本

とありますので、今回はバージョン Default (using Version_1.10)を使用します。
所以这次我们将使用这个版本 Default (using Version_1.10) 。

以後、WAFという表現はバージョン Default (using Version_1.10)のコアルールセットが適用されているAWS WAFとします。
从现在开始,术语 WAF 是指应用了版本 Default(使用 Version_1.10)的核心规则集的 AWS WAF。

次に、検証する内容です。 接下来,让我们看看我们想要验证的内容。

まず以下の3つをそれぞれ検証し、WAFのバイパスができるかを確認します。
首先,验证以下三个选项,看看是否可以绕过 WAF。

  • 2重キーを使用する。 使用双键。
  • BOMをJSON文字列の開始タグの前につける。 在 BOM 前加上 JSON 字符串的开始标记。
  • Unicodeでエンコードを行う。 以 Unicode 编码。

WAFに検知されなかった場合はそのペイロードを使い、いくつかの言語 (PHP, Ruby, Python) で攻撃が成立しそうかをローカルで検証します。
如果 WAF 未检测到有效负载,则有效负载用于在本地验证攻击是否可能在多种语言(PHP、Ruby、Python)中成功。

検証に入る前に 在我们进入验证之前

今回の検証では以下のペイロードを使用します。 此验证使用以下有效负载:

<script>alert(1)</script>

このペイロードが、WAFに検知されることを確認しておきましょう。
确保 WAF 检测到此有效负载。

まず最初に正常系のリクエストです。 首先,这是一个正常的请求。

application/json形式のAWS WAF Bypass

次にWAFに検知されることを期待したリクエストです。
WAF 预计将检测到下一个请求。

application/json形式のAWS WAF Bypass

今回使用するペイロードはしっかりとWAFによって検知されていそうです。
这次使用的有效载荷似乎被 WAF 牢牢地检测到了。

検証

2重キーを使用する 使用双键

RFCには、「name部分は基本的に一意であるべき」と言った事が記載されていると、私は解釈しています。
我对RFC的解释是,它规定名称部分本质上应该是唯一的。

では、キー (name)が2つ存在する時、アプリケーションは後ろのキーの値を処理に使用するのにも関わらず、WAFは先頭のキーもしくは値を検査するのみで、後ろのキーは検査しない、といった挙動が起きないかを検証してみます。12
现在,让我们验证当有两个键(名称)时,应用程序使用下一个键的值进行处理,但 WAF 只检查第一个键或值,而不检查第二个键。 1 2

ここでは、以下2つの状況を検証します。 在本节中,我们将研究以下两种情况。

  1. 後ろのキーの値に、WAFによって検知されるペイロードを持つ場合
    如果后退密钥的值具有 WAF 检测到的有效负载
  2. 前のキーの値に、WAFによって検知されるペイロードを持つ場合
    如果前一个密钥的值具有 WAF 检测到的有效负载

1. 後ろのキーの値に、WAFによって検知されるペイロードを持つリクエスト
1. WAF 在后退密钥值中检测到有效负载的请求。

application/json形式のAWS WAF Bypass

2. 前のキーの値に、WAFによって検知されるペイロードを持つリクエスト
2. 具有 WAF 检测到的有效负载的前一个密钥值的请求

application/json形式のAWS WAF Bypass

結果は、どちらもWAFに検知されていることがわかります。
结果表明,WAF检测到两者。

キーが2つ存在する時、WAFは前・後のみを検査するという事はないため、どちらかに無害な値を入れておくことで、WAFをバイパスできるということはなさそうです。
当有两个键时,WAF 不会只检查前后两个键,因此似乎不太可能通过在其中任何一个键中放置无害值来绕过 WAF。

BOMをJSON文字列の開始タグの前につける 在 BOM 前加上 JSON 字符串的开始标记

byte order mark (BOM)をJSON文字列の前につけることは、MUST NOTです。
在 JSON 字符串之前添加字节顺序标记 (BOM) 是 MUST NOT。

「だめと言われたらやるしか無い」ということで、JSON文字列の前にBOMをつけてみます。
“如果你被告知不要这样做,你别无选择,只能这样做”,所以我会在 JSON 字符串前面添加一个 BOM。

これにより、WAFがJSON文字列をパースできないなどの理由で、検査できないなどを期待します。
例如,这会导致 WAF 无法检查 JSON 字符串,因为它无法分析它。

BOM付きJSON文字列を作成するために、以下のスクリプトを使います。
使用以下脚本创建带有 BOM 的 JSON 字符串。

bom.js

const data = `${String.fromCodePoint(0xfeff)}{"name":"<script>alert(1)</script>"}`;
process.stdout.write(data);

BOMがしっかりついているかを確認 确保 BOM 已牢固连接

node bom.js | xxd
00000000: efbb bf7b 226e 616d 6522 3a22 3c73 6372  ...{"name":"<scr
00000010: 6970 743e 616c 6572 7428 3129 3c2f 7363  ipt>alert(1)</sc
00000020: 7269 7074 3e22 7d                        ript>"}

Wikipedia バイト順マーク各符号化形式(符号化スキーム)ごとのバイト順マーク部分を見ると、UTF-8におけるBOMは0xEF 0xBB 0xBFと記載されています。
如果您查看维基百科的 各符号化形式(符号化スキーム)ごとのバイト順マーク 字节顺序标记,则 UTF-8 中的 BOM 0xEF 0xBB 0xBF 被描述为 。

xxdコマンドの結果を見るとJSON文字列の前にefbb bfがいるので、意図した結果となっていそうです。
如果你看一下 xxd 命令的结果,JSON 字符串前面有一个 efbb bf ,所以它似乎是预期的结果。

ではbom.jsの出力をコピーして、リクエストのBody部分に貼り付けます。
现在,复制bom.js的输出并将其粘贴到请求的“正文”部分。

application/json形式のAWS WAF Bypass

結果はWAFに検知されてしまいました。 结果由 WAF 检测到。

Unicodeでエンコードを行う Unicode 编码

  • RFC 8259 (The JavaScript Object Notation (JSON) Data Interchange Format #Strings)より引用」
    引自 RFC 8259(JavaScript 对象表示法 (JSON) 数据交换格式 #Strings)”

    All Unicode characters may be placed within the quotation marks, except for the characters that MUST be escaped: quotation mark, reverse solidus, and the control characters (U+0000 through U+001F).
    所有 Unicode 字符都可以放在引号内,但必须转义的字符除外:引号、反向实线和控制字符(U+0000 到 U+001F)。

Unicodeを使用したバイパスを行います。3
使用 Unicode 绕过。 3

エンコードはCyberChefを使って行います。
编码是使用 CyberChef 完成的。

https://gchq.github.io/CyberChef/#recipe=Escape_Unicode_Characters(‘%5C%5Cu’,true,4,true)&input=PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg

-- エンコード 前
<script>alert(1)</script>

-- エンコード 後
\u003C\u0073\u0063\u0072\u0069\u0070\u0074\u003E\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029\u003C\u002F\u0073\u0063\u0072\u0069\u0070\u0074\u003E

application/json形式のAWS WAF Bypass

無事バイパスできていそうです。 似乎已经成功绕过了。

ではPHP, ruby, pythonでペイロードがどのように解釈されるかを確認してみましょう。
让我们看看 PHP、ruby 和 python 如何解释有效负载。

decode.php

<?php
$data = '{"name":"\u003C\u0073\u0063\u0072\u0069\u0070\u0074\u003E\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029\u003C\u002F\u0073\u0063\u0072\u0069\u0070\u0074\u003E"}';
$result = json_decode($data);
$name = $result->name;
print $name; // <script>alert(1)</script>

decode.rb 解码.rb

require 'json'

data = '{"name":"\u003C\u0073\u0063\u0072\u0069\u0070\u0074\u003E\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029\u003C\u002F\u0073\u0063\u0072\u0069\u0070\u0074\u003E"}';
parsed =  JSON.parse(data)
puts parsed["name"] # <script>alert(1)</script>

decode.py

import json
data = '{"name":"\u003C\u0073\u0063\u0072\u0069\u0070\u0074\u003E\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029\u003C\u002F\u0073\u0063\u0072\u0069\u0070\u0074\u003E"}'
parsed = json.loads(data)
print(parsed["name"]) # <script>alert(1)</script>

結果はすべて<script>alert(1)</script>と解釈するので、Unicodeでエンコードを行う事はかなり使えそうです。
所有结果都解释为 <script>alert(1)</script> ,因此 Unicode 中的编码似乎非常有用。

検証を経て 验证后

一度わかりやすく表にしてみます。 我将尝试使它成为一个易于理解的表格。
実装依存の場合がありますが、バイパスが成功していれば結果は○とします。
这可能取决于实现,但如果绕过成功,结果将是○。

方法 結果 结果
2重キーを使用する 使用双键 ×
BOMをJSON文字列の開始タグの前につける 在 BOM 前加上 JSON 字符串的开始标记 ×
Unicodeでエンコードを行う Unicode 编码

これらの結果から、ペイロードを難読化(と言うと大げさな気がしますが)のように、解釈されにくくする事がWAFのバイパスで有効と言えそうです。
基于这些结果,绕过 WAF 似乎可以有效地使有效载荷难以被解释,例如混淆它(尽管这似乎有点夸张)。

イメージ 图像

application/json形式のAWS WAF Bypass

ただし、URLエンコードは対応されています。 但是,支持 URL 编码。

URLエンコード1回 1 URL 编码

application/json形式のAWS WAF Bypass

URLエンコード2回 URL 编码两次

application/json形式のAWS WAF Bypass

では、WAFはある文字として認識できないが、アプリケーションはある文字として認識できるようなエンコード方式などがあれば更にバイパスが出来るのではないでしょうか。
然后,如果有一种编码方法允许 WAF 识别某个字符,但应用程序将其识别为某个字符,则可以进一步绕过它。

WAFとアプリケーション解釈が変わるような方法を探す
寻找改变 WAF 和应用程序解释解释方式的方法

gzip, deflateの利用 使用 gzip 和 deflate

ここではPHP, Ruby, Pythonでの検証は行わず、Express×Node.jsのみに焦点をあてます。
我们不会用 PHP、Ruby 或 Python 进行测试,而只关注Express×Node.js。

検証環境では、Expressがapplication/jsonを解釈出来るように、express.json()を使用しています。
在验证环境中,我们 express.json() 使用 to allow Express application/json 来解释 .

server.js

app.use(express.json());
app.use(express.urlencoded({ extended: true}));

express.json()のドキュメントを読むと、以下のような事が書いてあります。
express.json() 如果您阅读文档,您会发现以下内容:

  • 「Express APIリファレンスexpress.json()より引用」
    “引自 Express API 参考 express.json()”

    This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.
    这是 Express 中内置的中间件功能。它使用 JSON 有效负载解析传入请求,并且基于正文解析器。

express.json()は、Expressにおいて、JSON形式のリクエストをパースしてくれるミドルウェアのようです。
express.json() 似乎是在Express中解析JSON格式请求的中间件。

実はこのexpress.json()のドキュメントには興味深いことが書いてあります。
事实上 express.json() ,这个文档中有一个有趣的东西。

supports automatic inflation of gzip and deflate encodings.
支持 gzip 和 deflate 编码的自动膨胀。

gzipとdeflateの自動展開をサポートしているようです。
它似乎支持 gzip 和 deflate 自动提取。

また、この機能はinflateプロパティで操作できるようですが、デフォルトでtrueです。
此外,此功能似乎在属性中 inflate 操作,但 true 默认情况下。

では、これを使いバイパスを行うことは出来ないかを検証してみます。
现在,让我们验证是否可以使用它绕过它。

検証: gzipを用いてWAFをバイパスする 验证:使用 gzip 绕过 WAF

検証するためには、gzipを用いて圧縮したペイロードを作る必要があります。
为了验证这一点,我们需要使用 gzip 创建一个压缩的有效负载。

これはBurpSuiteのHackvertorという拡張機能がおすすめです。
为此,我们推荐 BurpSuite 的 Hackvertor 扩展。

まず、Repeaterに{"name": "<script>alert(1)</script>"}をBodyに持つContent-Type: application/jsonのリクエストを送ります。
首先,向 Repeater 发送 {"name": "<script>alert(1)</script>"} 一个请求,其正文 Content-Type: application/json 为 。

次に、Content-Encoding: gzipを追加して、Hackvertorgzip_compressタグでペイロードを囲います。
然后, Content-Encoding: gzip 添加以将有效负载 gzip_compressタグ 括 Hackvertor 起来。

application/json形式のAWS WAF Bypass

ここまで出来たらリクエストを送信しましょう。 一旦你做到了这一点,就发送你的请求。

application/json形式のAWS WAF Bypass

バイパスが出来ていそうです。4 似乎已经绕过了。 4

検証: deflateを用いてWAFをバイパスする
验证:使用 deflate 绕过 WAF

検証: gzipを用いてWAFをバイパスすると基本的に手順は一緒ですが、以下の2点を変更してください。
验证:如果使用 gzip 绕过 WAF,步骤基本相同,但请修改以下两点。

  • Content-Encodingをdeflateにする。
    将 Content-Encoding 设置为 deflate。
  • Hackvertorで、deflate_compressタグを使用する。
    在 Hackvertor 中, deflate_compressタグ 使用 .

application/json形式のAWS WAF Bypass

こちらもバイパス出来ていそうです。 看来这也可以绕过。

パースの実装依存を利用する 使用 Parse 实现依赖关系

JSON文字列のパースの結果は言語によって違う部分があります。
解析 JSON 字符串的结果因语言而异。

例えば、rubyのJSON.parse()は、\ssとして解釈をします。5
例如,Ruby JSON.parse() \s 解释为 . s 5

decode.rb 解码.rb

require 'json'

data = '{"name":"<\script>alert(1)</\script>"}';
parsed =  JSON.parse(data)
puts parsed["name"] # <script>alert(1)</script>

ただし、他の言語 (Python, PHP)ではエラーになったり、うまく解析出来ません。
但是,在其他语言(Python、PHP)中,可能会发生错误或无法很好地解析。

decode.php

<?php
$data = '{"name":"<\script>alert(1)</\script>"}';
var_dump(json_decode($data)); // NULL

decode.py

import json
data = '{"name":"<\script>alert(1)</\script>"}'
parsed = json.loads(data)
print(parsed) # SyntaxWarning: invalid escape sequence '\s'

では、実装次第で攻撃に繋げることが出来そうであるため、<\script>alert(1)</\script>でWAFバイパスが出来るかを検証してみます。
然后,根据实现的不同,它似乎会导致攻击,因此让我们验证 <\script>alert(1)</\script> 是否可以使用 绕过 WAF。

検証: パースの実装依存を利用する 验证:使用 Parse 实现依赖项

application/json形式のAWS WAF Bypass

結果はJSON.parse()がエラーを吐くので、Internal Server Errorになりました。
JSON.parse() 结果是 ,因为 Internal Server Error 发出错误。

エラーログ 错误

SyntaxError: Bad escaped character in JSON at position 11 (line 1 column 12)
    at JSON.parse (<anonymous>)
    ....
    ....

ただし、このエラーはDockerで動かしているアプリケーションが吐いているものなので、WAFに検知はされていません。
但是,由于此错误是由在 Docker 上运行的应用程序发出的,因此 WAF 不会检测到它。

このことから、実装次第で攻撃につなげることは可能だと言えそうです。
由此看来,根据实现情况,似乎可能会导致攻击。

まとめ 总结

では今までの結果を表にまとめてみましょう。 让我们在表格中总结到目前为止的结果。
実装依存の場合がありますが、バイパスが成功していれば結果は○とします。
这可能取决于实现,但如果绕过成功,结果将是○。

方法 結果 结果
2重キーを使用する 使用双键 ×
BOMをJSON文字列の開始タグの前につける 在 BOM 前加上 JSON 字符串的开始标记 ×
Unicodeでエンコードを行う Unicode 编码
gzip, deflateで圧縮したペイロードを送る
发送使用 gzip 或 deflate 压缩的有效负载
パースの実装依存を利用する 使用 Parse 实现依赖关系

本来WAFに検知されるようなペイロードでも、エンコードなどを使用してWAFに怪しいと認識をさせなければ、かなり簡単にWAFをバイパス出来るという結果になりました。
即使有效负载最初是由 WAF 检测到的,如果 WAF 没有通过使用编码等方式将其识别为可疑,也很容易绕过 WAF。

最後に 最后

弊社では、今回のように診断技術を向上させるための検証を行っています。
我们正在进行验证以改进诊断技术,如本案例所示。

脆弱性診断を行う予定がございましたら、ホームページよりお問い合わせが可能ですので、ぜひ一度弊社にお声掛けいただけますと幸いです。
如果您计划进行漏洞评估,您可以通过我们的网站与我们联系,因此,如果您能与我们联系,我们将不胜感激。


  1. AWS WAF Bypass: invalid JSON object and unicode escape sequences #JSON duplicate keysにて、既に紹介されています。 ↩︎
    AWS WAF 绕过:无效的 JSON 对象和 unicode 转义序列 #JSON 重复的密钥。 ↩︎

  2. SECCON Beginners CTF 2021【Web】json 作問者writeupでも取り上げられています。 ↩︎
    SECCON Beginners CTF 2021 [Web] json 作問者writeup. ↩︎

  3. AWS WAF Bypass: invalid JSON object and unicode escape sequencesによって紹介されています。 ↩︎
    AWS WAF 绕过:无效的 JSON 对象和 unicode 转义序列。 ↩︎

  4. CVE-2021-45468: Imperva Cloud WAFにおいて、Content-Encoding: gzipを使用したHTTP POSTでWAFがリクエストを評価しないといったことが起きていたようです。 ↩︎
    CVE-2021-45468:在 Imperva Cloud WAF 中, Content-Encoding: gzip 使用 HTTP POST 时 WAF 似乎未评估请求。 ↩︎

  5. Flatt Security Developers’ Quiz #6で解法の一例として紹介されています。 ↩︎
    Flatt 安全开发人员测验 #6で解法の一例として紹介されています。 ↩︎

原文始发于DARK MATTER:application/json形式のAWS WAF Bypass

版权声明:admin 发表于 2024年7月9日 上午10:09。
转载请注明:application/json形式のAWS WAF Bypass | CTF导航

相关文章