
Apache Camelの脆弱性に対する実行可能な概念実証(PoC)再現ツールです。この脆弱性では、CoAPコンシューマがルート完了後にレスポンスを構築できなかった場合、CamelCoapResourceが発生した例外を捕捉し、そのメッセージを5.00 Internal Server ErrorのペイロードとしてCoAPクライアントに送り返していました:
} catch (Exception e) {
cexchange.respond(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
| ランタイム | ディレクトリ | スタック |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-coap 4.22.1 |
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.39.0 (Quarkus 3.39.0, Camel 4.22.0) |
コンシューマーは、最終メッセージボディを byte[] ペイロードに、また CamelCoapMaxAge および
CamelCoapETag ヘッダーをそれぞれの型に変換しますが、これはルートが戻った後に、したがって
ルートのエラーハンドラーの外側で行われます。この失敗はルート内ではなくコンシューマー内で
発生するため、ルート内の onException では捕捉できません。
cd camel-spring-boot # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until [ "$(curl -s http://localhost:8080/exploit/ready)" = "Started" ]; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down
影響を受けるビルドでの出力(両ランタイムで同一):
1) Converting the body to the byte[] payload fails once the route has completed
CoAP GET coap://127.0.0.1:5683/reading
response code : 5.00 (INTERNAL_SERVER_ERROR)
response payload : Error during type conversion from type: com.example.FailingBackendStream to the
required type: byte[] with value com.example.FailingBackendStream@5eede7d7 due to
java.io.IOException: connection to prod-db.internal:5432 reset while streaming
sensor_readings for node edge-gateway-07.dc2.internal
2) The CamelCoapMaxAge header cannot be converted to its type
CoAP GET coap://127.0.0.1:5683/reading-maxage
response code : 5.00 (INTERNAL_SERVER_ERROR)
response payload : Error during type conversion from type: java.lang.String to the required type:
java.lang.Long with value not-a-number due to java.lang.NumberFormatException:
For input string: "not-a-number"
3) A route that simply fails
CoAP GET coap://127.0.0.1:5683/reading-failing
response code : 2.05 (CONTENT)
response payload : partially built response
What a remote CoAP client learned from these responses:
the backend host and port, out of the cause's message : true
class names of the cause : true
the source and target types of the conversion : true
the string form of the offending value : true
a failed route answered with a SUCCESS code : true
>>> PROVEN: ...
このような失敗のメッセージには、変換対象の値のクラス名、その値の文字列表現、そして根本原因のクラス名とメッセージが含まれる。そのため、リモートの CoAP クライアントはクラス名とパッケージ名、値の文字列表現、そして原因が保持するあらゆる情報——実際にはバックエンドのパス、ホスト名、接続の詳細を含みうる——を読み取ることができる。コンシューマーにはこれを抑制するオプションがなかった。その目的のために muteException を提供する HTTP コンシューマーとは異なる。
プローブ 3 はこの問題の後半部分である。 失敗したルートによって発生した例外はまったく送信されなかった。コンシューマーは交換が失敗したかどうかを確認せず、ルートの失敗に対して 2.05 Content と、その時点でメッセージが保持していたボディをそのまま返していた——失敗したルートに対して成功コードを返していたのである。
この再現プログラムで正しく押さえる必要があった点: コンバーターが存在しないボディでは不十分である。 その場合
getBody(byte[].class)は例外をスローせずnullを返し、コンシューマーは空のペイロードで2.05を返す——情報漏えいは発生しない。変換は「利用不可」ではなく失敗しなければならず、 だからこそプローブ 1 では読み取りの途中で例外をスローするストリームボディを使用している。ヘッダーの プローブは逆の形で、誤った形状の値によって失敗する。
この情報漏えいに到達するには、リモートクライアントが完了済みレスポンスを変換不能にできるルートが必要であり、それはルートの書き方に依存する。ここでは認証は一切なく、クライアントが送信するのは平文の CoAP GET のみである。
| 項目 | 値 |
|---|---|
| コンポーネント | camel-coap (CamelCoapResource) |
| CWE | CWE-209 (Generation of Error Message Containing Sensitive Information) |
| 深刻度 | 中 |
| 攻撃ベクトル | 完了済みレスポンスを構築できないコンシューマーへの CoAP リクエスト — byte[] への変換に失敗するボディ、または変換に失敗する CamelCoapMaxAge / CamelCoapETag ヘッダー |
| 影響 | リモートの CoAP クライアントがクラス名とパッケージ名、値の文字列表現、根本原因のメッセージを読み取る — 実際にはパス、ホスト名、バックエンド接続の詳細 |
| 影響を受けるバージョン | 4.0.0 から 4.18.5 より前、4.19.0 から 4.22.2 より前 |
| 修正済みバージョン | 4.18.5、4.22.2、4.23.0 |
| JIRA | CAMEL-25087 |
| クレジット | Zhixi "Jace" Sun、独立系セキュリティ研究者 |
アドバイザリ: https://camel.apache.org/security/CVE-2026-101259.html
コンシューマーには muteException オプションが追加された——coap、coaps、coap+tcp、coaps+tcp の各エンドポイントすべてに——そしてこれは修正された 3 つのリリースラインすべてでデフォルトが true であるため、アップグレードするだけで十分であり、設定変更は不要である。コンシューマーは引き続き 5.00 Internal Server Error を返すが、空のペイロードで返し、さらにコンシューマーの例外ハンドラーを通じて例外を報告するようになったため、ミュートしても運用者から隠されることはない。
また、交換が失敗したかどうかを確認し、ルートの失敗に対しては同じルールの下で 5.00 Internal Server Error を返すようになった(以前は 2.05 Content を返していた)。
main では apache/camel#26994 (2245feac) で修正され、camel-4.22.x には #27046 (868d5604) で、camel-4.18.x には #27048 (aaf5bbf8) でバックポートされた。
camel.version を 4.22.2 に設定して再度実行する。4.22.1 → 4.22.2 で検証済み:
1) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
2) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
3) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
>>> NOT reproduced: the error payload was empty.
プローブ3もコードを変更し、2.05 Content から 5.00 Internal Server Error になります。ルートの失敗が失敗として応答されるようになりました。
ルートが完了した時点で常にレスポンスを構築できるようにしてください。coapエンドポイントから消費する各ルートの最後のステップで、ボディを byte[] または String に変換し(convertBodyTo)、CamelCoapMaxAge と CamelCoapETag ヘッダーにはそれぞれの型の値のみを設定し、失敗を処理済みとしてマークし、レスポンスボディを明示的に設定する onException ハンドラーを追加します。これにより、変換の失敗がコンシューマー内ではなくルート内で発生し、置き換えられるようになります。
このリポジトリは教育および防御目的で公開されています。Apache Camelのユーザーが脆弱性を理解し、影響を受けているかどうかを確認し、アップグレードによって解決されることを確かめるためのものです。所有または運用していないシステムに対してこの資料を使用しないでください。