原文始发于GMO Cyber Security:見落としがちなURL正規化によるパストラバーサル
高度解析部アプリケーションセキュリティ課の金子です。
我是高级分析部应用程序安全科的 Kaneko。
パストラバーサル(またはディレクトリトラバーサル)はXSSやSQLインジェクションに並んでWebアプリケーションに対する代表的な攻撃手法のひとつです。本記事では、パストラバーサルの中でもURL正規化によるパストラバーサルに焦点を当てて攻撃の発生原理やよくある事例について解説します。関連して、PHP向けのAWS SDKで発見したS3バケットに対するパストラバーサルの脆弱性CVE-2023-51651についても紹介します。
路径遍历(或目录遍历)是针对 Web 应用程序最常见的攻击方法之一,还有 XSS 和 SQL 注入。 在本文中,我们将重点介绍路径遍历中通过URL规范化的路径遍历,并解释攻击生成的原理和常见示例。 与此相关,我们还将介绍 CVE-2023-51651,这是一个针对适用于 PHP 的 AWS 开发工具包发现的针对 S3 存储桶的路径遍历漏洞。
2種類のパストラバーサル 两种类型的路径遍历
パストラバーサルは../
のような文字列を含んだ文字列の正規化処理(normalization)を悪用して、アプリケーションが予期しない”領域”に対してアクセスを行う攻撃です。正規化処理を行う対象によって分類することが可能で、次の2種類のパストラバーサルが代表的です:
路径遍历是一种攻击,它利用包含字符串(如 ../
)的字符串的规范化过程来访问应用程序的意外“区域”。 可以根据规范化过程的目标进行分类,以下两种类型的路径遍历是典型的:
- ファイルシステムに対するパストラバーサル: 到文件系统的路径遍历:
- ・ 正規化処理の対象: ファイルパス ・ 规范化目标:文件路径
- URLに対するパストラバーサル: URL 的路径遍历:
- ・ 正規化処理の対象: URLパス ・规范化目标:URL路径
パストラバーサルの影響範囲として、ファイルシステム内の任意ファイルへの読み込みや書き込みが紹介されることが多いですが、基本的にはそれは前者のパストラバーサルが前提となっています。パストラバーサル自体の認知度は高いということもあり、XSSやSQLインジェクションの対策が適切に行われているアプリケーションであれば同様に前者のパストラバーサルの対策も適切に行われていることが多い印象があります。一方で、後者のパストラバーサルについては比較的堅牢なアプリケーションにおいても脆弱性として存在していることがあり、見落とされやすいのかもしれません。
对文件系统中任意文件的读取和写入通常被引入为路径遍历的影响范围,但基本上它是以前路径遍历为前提的。 对路径遍历本身有很高的认识,我的印象是,如果应用程序对 XSS 和 SQL 注入进行了适当的反击,那么以前的路径遍历对策通常也会得到适当的实现。 另一方面,即使在相对健壮的应用程序中,后一种路径遍历也可能作为漏洞存在,并且可能很容易被忽视。
URL正規化によるパストラバーサルのよくある発生例
具有 URL 规范化的路径遍历的常见情况
多くのHTTPクライアントではデフォルトでURLの正規化を行う実装になっています:
默认情况下,许多 HTTP 客户端都具有 URL 规范化实现:
- Webブラウザの例: Web 浏览器示例:
- ブラウザのURLバーに
https://example.com/foo/../
を入力してアクセスすると、実際にはhttps://example.com/
へのHTTPリクエストが送信される。
当您进入浏览器的 URL 栏进行访问时https://example.com/foo/../
,您实际上是在https://example.com/
向 . - JavaScript内で
fetch("https://example.com/foo/../")
を実行すると、実際にはhttps://example.com/
へのHTTPリクエストが送信される。
当您在 JavaScriptfetch("https://example.com/foo/../")
中执行时,您实际上是在向 发送 HTTP 请求https://example.com/
。
- ブラウザのURLバーに
- curlの例: curl 示例:
curl "https://example.com/foo/../"
のコマンドを実行すると、実際にはhttps://example.com/
へのHTTPリクエストが送信される。
curl "https://example.com/foo/../"
执行该命令时,实际上会将 HTTP 请求https://example.com/
发送到 。
そのため、HTTPクライアントを介するプログラムにおいて、URLパス部分にユーザの入力値が挿入される状況ではパストラバーサルが発生しやすくなります。
因此,在使用 HTTP 客户端的程序中,在将用户的输入值插入到 URL 路径部分的情况下,可能会发生路径遍历。
サーバサイドにおけるパストラバーサル 服务器端路径遍历
サードパーティAPIの呼び出しやBFFからバックエンドサーバへのAPI呼び出しなど、サーバサイドで送信されるHTTPリクエストにおいてパストラバーサル脆弱性が存在することがあります。以下はFlaskでのパストラバーサルに脆弱な実装の例です。
服务器端发送的HTTP请求中可能存在路径遍历漏洞,例如对第三方API的调用或BFF对后端服务器的API调用。 以下是 Flask 中易受路径遍历影响的实现示例。
from flask import Flask, request
import httpx
API_BASE_URL = "https://api.example.com"
app = Flask(__name__)
api_client = httpx.Client(base_url=API_BASE_URL, auth=("foo", "bar"))
@app.get("/path/to/data")
def get_data():
uuid = request.args.get("uuid", "00000000-0000-0000-0000-000000000000")
return api_client.get(f"/data/{uuid}").json() # path traversal!!!
このとき/path/to/data?uuid=../secret
にアクセスすると、パラメータuuid
の値は../secret
になり、/data/:uuid
ではなく/secret
に対してAPI呼び出しが行われます。
/path/to/data?uuid=../secret
当您访问 时,参数的值 uuid
../secret
将为 ,并且 /data/:uuid
将对 /secret
进行 API 调用,而不是 。
これによって、本来アクセスできないURLパスに対してAPI呼び出しが行うことが可能で、呼び出し先のエンドポイントによってはユーザの権限を超えてデータの取得や書き換え等の攻撃に繋がる可能性があります。上記の例は脆弱性が自明なものではありますが、実際にはユーザの入力値が間接的に混入したり、複数のAPIにまたがって処理が実行されたりして、脆弱性が発見しづらいケースもあります。
因此,可以对最初无法访问的 URL 路径进行 API 调用,并且根据调用的端点,可能会导致超出用户权限的数据获取或重写等攻击。 在上面的例子中,漏洞是不言而喻的,但实际上,由于用户的输入值被间接混入或流程跨多个 API 执行,漏洞很难被发现。
クライアントサイドにおけるパストラバーサル 客户端路径遍历
ReactやVue.js等を用いたSPAのアプリケーションでは、以下のフローで処理が実行される実装がよく見られます:
在使用 React、Vue.js 等的 SPA 应用程序中,通常会看到在以程中执行进程的实现:
- ① クライアント上でAPIサーバからデータを取得して
(1) 从客户端的 API 服务器获取数据 - ② 取得したデータに応じてレンダリングを行う (2) 根据采集的数据进行渲染
①のステップでパストラバーサル脆弱性が存在することがあり、以下はReact(とreact-router-dom)を用いた脆弱な実装の例です。
步骤 (1) 中可能存在路径遍历漏洞,以下是使用 React(和 react-router-dom)的易受攻击的实现示例。
<BrowserRouter>
<Routes>
<Route path="/users/:userId" element={<ProfilePage />} />
</Routes>
</BrowserRouter>
function ProfilePage() {
const { userId } = useParams();
const [user, setUser] = useState({});
useEffect(() => {
// ① クライアント上でAPIサーバからデータを取得
fetch(`/api/users/${userId}`) // path traversal!!!
.then((r) => r.json())
.then((u) => setUser(u))
.catch((e) => console.error(e));
}, []);
// ② 取得したデータに応じてレンダリング
return (
<>
<h1>Profile</h1>
<p>id: {user.id}</p>
<p>name: {user.name}</p>
</>
);
}
このとき/users/..%2fadminUser
にアクセスすると、パラメータuserId
の値は../adminUser
になり、①でパストラバーサルが発生して/api/users/:userId
ではなく/api/adminUser
に対してAPI呼び出しが行われます。
在这种情况下,当访问 /users/..%2fadminUser
时,参数的值 userId
../adminUser
将为 ,路径遍历将在 (1) 中发生,并且 /api/users/:userId
将对 /api/adminUser
进行 API 调用,而不是 。
これによって、CSRFに似た次のような攻撃が考えられます:
这会导致以下类似 CSRF 的攻击:
- 被害者に特定の罠URLをアクセスさせる。 诱骗受害者访问特定的陷阱 URL。
- 被害者の権限(例: セッションクッキーや認証ヘッダ)の元、パストラバーサルで任意のURLパスに対してAPI呼び出しを強制。APIのメソッドがPOSTやDELETEだった場合はデータへの作用が可能なこともあります。
在受害者的授权下(例如,会话 cookie 或身份验证标头),路径遍历会强制 API 调用到任意 URL 路径。 如果 API 方法是 POST 或 DELETE,则可以对数据执行操作。 - API呼び出しの後続の処理によってはXSS等のさらなる被害に拡大。
根据 API 调用的后续处理情况,它会扩展到进一步的损害,例如 XSS。
クライアントサイドにおけるパストラバーサルについては「Security.Tokyo #3」で発表された以下のスライドでわかりやすく言及されているため、参考として紹介します:
Security.Tokyo #3 中介绍的以下幻灯片中清楚地提到了客户端路径遍历,因此我们将将其作为参考进行介绍:
依存ライブラリが暗黙的に行うURL正規化 依赖库的隐式 URL 规范化
アプリケーション開発者がHTTPリクエストを送信するプログラムを直接実装していない場合でも、依存ライブラリが内部で行うHTTP通信で意図せずURL正規化が行われてしまうことがあります。これが原因でパストラバーサル脆弱性が発生してしまう可能性にも注意が必要です。
即使应用程序开发人员不直接实现发送 HTTP 请求的程序,URL 规范化也可能在依赖库的内部 HTTP 通信中无意中执行。 还应注意,这可能会导致路径遍历漏洞。
以下は、クエリパラメータkey
で指定されたS3オブジェクトを取得してその内容をクライアントに返却するPHPプログラムです。S3と連携するにあたってAWS SDK for PHPの公式ライブラリを利用しています。
下面是一个 PHP 程序,用于检索 key
query 参数指定的 S3 对象并将其内容返回给客户端。 为了与 S3 链接,我们使用适用于 PHP 的 AWS 开发工具包的官方库。
<?php
require "vendor/autoload.php";
use Aws\S3\S3Client;
$s3 = new S3Client([
"credentials" => [
"key" => $_ENV["AWS_ACCESS_KEY_ID"],
"secret" => $_ENV["AWS_SECRET_ACCESS_KEY"],
],
"region" => $_ENV["AWS_REGION"],
]);
$PREFIX = "images/";
$result = $s3->getObject([
"Bucket" => $_ENV["AWS_S3_BUCKET"],
"Key" => $PREFIX . $_GET["key"],
]);
echo $result["Body"];
文字列結合によってキーにはimages/
のプレフィックスが必ず付与されるようになっています。ここで、?key=../secret.txt
のようなクエリパラメータを指定した場合の挙動について考えてみましょう。このときパストラバーサルによって、キーがsecret.txt
のS3オブジェクトにアクセスするようになるでしょうか?
字符串串联可确保键以 images/
. 现在,让我们考虑指定查询参数( ?key=../secret.txt
如 . 路径遍历是否允许密钥访问 secret.txt
S3 中的对象?
S3の仕様をある程度知っている人は、「S3オブジェクトのキーやプレフィックスでは../
のような文字列は特別な意味を持たないため、パストラバーサルは発生しない」と考えるかもしれません。仕様に従えば、キーがimages/../secret.txt
のオブジェクトに対してアクセスする挙動が妥当と言えるでしょう。実際、S3バケット内はフラットな構造になっており、ファイルシステムにあるような階層の概念は存在しません。
如果您完全熟悉 S3 规范,您可能会认为 like 字符串 ../
在 S3 对象的键或前缀中没有特殊含义,因此不会发生路径遍历。 根据规范,使用 images/../secret.txt
密钥访问对象是合理的。 事实上,S3 存储桶具有扁平结构,并且没有像文件系统中那样的层次结构概念。
ところが、上記プログラムを実際に動かしたところ、キーがsecret.txt
のS3オブジェクトにアクセスする挙動が確認されました。というのもAWS SDK for PHPはS3オブジェクトにアクセス時に内部でGuzzleのHTTPクライアントが利用されており、暗黙的にURLの正規化処理が行われてしまうようになっていました。
但是,在实际执行上述程序时,确认密钥访问了 secret.txt
的 S3 对象。 这是因为适用于 PHP 的 AWS 开发工具包在访问 S3 对象时在内部使用 Guzzle 的 HTTP 客户端,并且隐式执行 URL 规范化处理。
「S3ではパストラバーサルは発生しない」と思い込んでいる開発者にとっては罠のような挙動であり、上記は依存ライブラリが暗黙的に行うURL正規化が原因のパストラバーサルの例となります。
对于假设“S3 中不会发生路径遍历”的开发人员来说,这是一个陷阱行为,上面是一个由依赖库隐式执行的 URL 规范化导致的路径遍历示例。
なお、見方によればS3の仕様に反する挙動であり脆弱性と言えなくもないため、念の為AWSのセキュリティチームに報告し、すでに最新版のバージョンにおいては上記挙動に関して修正がされています。
另外,根据观点,这是一种违反 S3 规范的行为,可以说是漏洞,所以我们向 AWS 安全团队报告了以防万一,上述行为已经在最新版本中得到了纠正。
- CVE-2023-51651: https://github.com/aws/aws-sdk-php/security/advisories/GHSA-557v-xcg6-rm5m
CVE-2023-51651:https://github.com/aws/aws-sdk-php/security/advisories/GHSA-557v-xcg6-rm5m
該当のライブラリを利用されている方は、修正バージョン以上にアップグレードすることを推奨します。
如果您使用的是此库,我们建议您升级到固定版本或更高版本。
おわりに 结论
URL正規化によるパストラバーサルに焦点を当てて攻撃の発生原理や発生例について紹介しました。「パストラバーサルはファイルシステム内の任意ファイルにアクセスできる脆弱性である」と認識していると、思いがけないところでパストラバーサルの脆弱性を作り込んでしまうかもしれません。しかし、いずれのパストラバーサルにおいても「ユーザの入力値を信用してはいけない」という基本的なセキュリティの考え方は通用するため、そのことを念頭に置きながらアプリケーションの開発を行うことがまずは大切だと思います。
我们重点介绍了通过URL规范化的路径遍历,介绍了攻击的原理和示例。 如果您认识到路径遍历是一个允许访问文件系统中任意文件的漏洞,则可能会在意想不到的位置创建路径遍历漏洞。 但是,“不信任用户的输入值”的基本安全概念适用于任何路径遍历,因此我认为首先在开发应用程序时要考虑到这一点。
GMOサイバーセキュリティ byイエラエではバグバウンティやセキュリティコンテストなどで活躍するセキュリティエンジニアが実施する「Webペネトレーションテスト <シナリオ型> / <調査型>」を提供しています。標準的なWebアプリケーション診断では検出ができないような脆弱性も検出し、リスクを評価します。また、ソースコードを共有いただくことによってより精度の高い調査を実施することが可能です。是非お気軽にご相談ください。
Ierae 的 GMO Cyber Security 进行了“网络渗透测试<シナリオ型>/ <調査型>我们提供以下服务: 它还检测标准 Web 应用程序诊断无法检测到的漏洞并评估风险。 此外,通过共享源代码,可以进行更准确的调查。 请随时与我们联系。