コンテンツにスキップ

独自コードの信頼境界

独自の Python、Bash、PHP、Go、JavaScript、Java のコードを調べるときは、危険な関数名を探すだけで終わらせない。入力元から高権限処理が触るリソースまで、データの流れを追う。

低権限ユーザーの入力が、検証、保存、IPC、root 権限での処理のどこで信頼されるかを見る。shell=True、pickle、yaml.load、シンボリックリンク、shutil.move、アーカイブ展開、相対パスは、入力の制御者と実行 UID を確かめてから評価する。

入力元
↓
変換・検証処理
↓
保存先または IPC
↓
権限付きプロセス
↓
危険な処理
↓
影響を受けるリソース

見る入力元:

  • コマンドライン引数
  • 標準入力
  • 環境変数
  • 設定ファイル
  • ログファイル
  • 一時ファイル
  • アップロードファイル
  • アーカイブの中身
  • Unix socket
  • ファイルディスクリプタ

確認する処理:

subprocess.run(...)
subprocess.Popen(...)
os.system(...)
os.execve(...)
open(...)
os.open(...)
os.pread(...)
shutil.copy(...)
shutil.move(...)
tarfile.extract(...)
tarfile.extractall(...)
zipfile.extract(...)
zipfile.extractall(...)
pickle.load(...)
yaml.load(...)
eval(...)
exec(...)
tempfile.*

これらの呼び出しがあるだけでは脆弱とは断定しない。次を確認する。

  • 引数を誰が制御できるか。
  • shell=True か。
  • パスが絶対か相対か。
  • PATH を信用しているか。
  • ファイルの owner、mode、ACL。
  • 親ディレクトリを書き換えられるか。
  • symlink を追従するか。
  • 検証後に同じ inode またはファイルディスクリプタを使っているか。
  • 実行 UID/GID。
  • 呼び出し元と呼び出し先の権限差。
  • エラー時に制限を解除する処理になっていないか。

エラー応答は副作用の不成立を示さない。TypeError や 502 のあとでも、callback、生成ファイル、ログを確認する。

成立条件:
攻撃者が制御するもの:
信頼境界:
問題のある処理:
影響:
なぜ成立するか:
修正案:
検知・ログ:
未確認:

修正案は、実際の処理に合うものだけを書く。

  • shell を使わず、argv の配列で実行する。
  • allowlist で service 名や action 名を制限する。
  • 低権限ユーザーが書けるディレクトリを、root 権限で読み込むモジュールやチェックポイントの置き場にしない。
  • 安全な一時ファイルを使う。
  • O_NOFOLLOW、owner と inode の再確認、FD ベースの処理で symlink と TOCTOU を避ける。
  • アーカイブの展開時にパストラバーサルを防ぐ。
  • pickle や torch.load 相当を、信頼境界の外から来たファイルに使わない。
  • systemd の hardening、最小権限、読み書きディレクトリの分離を行う。

検知に残るものはログと検知で見る。

印刷ジョブの制御ファイル:

control file の J 行
↓
job_name
↓
subprocess.Popen(..., shell=True)
↓
/bin/sh
↓
印刷サービスの shell

FD の受け渡しはUnix socket とファイルディスクリプタに図を置いた。

管理 UI のサービス名:

service パラメータ
↓
denylist の正規表現
↓
subprocess.run("systemctl status ...", shell=True)
↓
サービス権限で symlink を作成
↓
sudo の root log viewer
↓
2段 symlink 経由の root file read

sudo された Python の plugin:

低権限ユーザーが書ける plugin directory
↓
.pth ファイル
↓
root sudo の site.addsitedir()
↓
.pth ファイル内の import 行を実行
↓
root 所有の SUID bash

学習ジョブの checkpoint:

処理済み入力が検証を通過
↓
DataLoader
↓
共有ディレクトリ上の最新 .pt
↓
CheckpointLoader / torch.load
↓
pickle deserialization
↓
root でのコマンド実行