python-fire: (1) PAGER+shell=True RCE in console_io.More (2) bash $(...) runs when sourcing --completion from maliciously named .py file. PoC verified.
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 45/100
調査の方向性
fire/console/console_io.py と More() から始め、次に fire/completion.py と _BashScript() を調査し、bash_completion_template も確認します。提供されている pseudo-TTY と sourced completion の両方の PoC を再現し、その後、攻撃者が制御する PAGER と名前によって shell コマンドを実行できないことを示す回帰テストを追加し、影響を受けるテストスイートを実行します。
索引モデルが issue の本文から書いたものです。
説明
Summary
Two related issues in python-fire (library + python -m fire entrypoint): (1) OS command injection when an external pager is spawned; (2) arbitrary shell command execution when a user sources a generated Bash completion script, if the CLI name (often derived from a .py filename) contains Bash command substitution or other shell metacharacters.
Repository: https://github.com/google/python-fire
Issue A: PAGER + subprocess.Popen(..., shell=True)
File: fire/console/console_io.py, function More(), approximately lines 81–100.
Behavior: When check_pager is true (default), stdin/stdout are TTYs, and PAGER is set, the value from os.environ['PAGER'] is passed to:
subprocess.Popen(pager, stdin=subprocess.PIPE, shell=True)
Because shell=True, the string is interpreted by /bin/sh. Metacharacters (;, |, `, $(), etc.) allow arbitrary commands to run in the same security context as the Fire-based process.
Trigger: Any code path that calls console_io.More() with the default pager behavior—e.g. fire.core.Display() used for help text, traces, and other paged output—when the process has a malicious or attacker-controlled PAGER and an interactive terminal.
Verification (PoC): With PAGER='touch /tmp/fire_verify_pager', run under a pseudo-TTY (e.g. script -qefc 'python -c "from fire.console import console_io; import sys; console_io.More(\"x\", sys.stdout)"' /dev/null). The side-effect file appears, confirming shell interpretation of PAGER.
Issue B: Bash completion script — unsanitized name / identifier
File: fire/completion.py, function _BashScript(), template bash_completion_template and .format(...) around lines 179–187.
Behavior: The Bash script embeds name and identifier with only a weak transform:
identifier = name.replace('/', '').replace('.', '').replace(',', '')
Characters such as $, (, ), `, ;, newlines, etc. are not removed. The template includes lines such as:
_complete-{identifier}()complete -F _complete-{identifier} {command}
with command=name. When the generated script is sourced by Bash, command substitution in identifier or name (e.g. $(touch marker)) is evaluated.
Trigger: python -m fire sets name from os.path.basename(path) (fire/__main__.py, import_from_file_path). A file named like $(touch _marker).py therefore yields a completion script that runs touch (or worse) when the victim runs source on the output of -- --completion.
Verification (PoC): Create a minimal module file literally named $(touch _fire_verify_completion_marker).py, run python -m fire '<path>' -- --completion > comp.sh, then bash -c 'source comp.sh'. The marker file is created (Bash may also error on an invalid function name, but substitution still runs).
Note: A subshell payload must not contain / in the basename (invalid filename on Unix); use e.g. $(touch _marker) with a relative target.
CWE mapping
- Issue A: CWE-78 (OS command injection)
- Issue B: CWE-78 / insufficient neutralization of shell metacharacters in generated shell code
Who can exploit
- Issue A: Anyone who can control the environment of a process that runs Fire and reaches
More()on a TTY withPAGERset (e.g. misconfigured services, wrappers, CI jobs, compromised.env, multi-tenant job runners). The user running the CLI can also setPAGERthemselves; the higher risk is untrusted or inherited environment for automated or privileged contexts. - Issue B: An attacker who can place or name a
.pyfile on disk (or otherwise influence thenamepassed tofire.Fire(..., name=...)) and convince a victim to generate and source Bash completion from that module (e.g. cloned repo, malicious path, social engineering). Supply-chain / “run this install script” scenarios are plausible.
What the attacker gains
- Issue A: Arbitrary code execution as the Fire process user: read/write secrets the process can access, lateral movement on the host, data destruction (CIA triad: High).
- Issue B: Arbitrary code execution as the user who sources the completion script in Bash—typically the developer’s or operator’s interactive account.
Prerequisites / limits
- Issue A requires an interactive TTY for the default pager path (
IsInteractive(output=True)); non-TTY falls back to writing withoutPAGER. - Issue B requires the victim to execute the generated script in Bash (e.g.
source); reading the file alone is not enough.
Suggested severity (informal)
- Issue A: often assessed High locally (e.g. CVSS ~8.x) when env is attacker-influenced; lower if only self-controlled env.
- Issue B: High when sourcing untrusted completion is realistic; depends on social/engineering and workflow.
- 主要言語
- Python
- スター
- 28.2k
- フォーク
- 1.5k
- PR マージ指標
- 30日以内にマージされた PR はありません
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
google/python-fire のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
google/python-fire#693 ·
-
Release 0.7.2? オープン
難易度 3/5 1〜2日 初心者へのやさしさ 38/100
google/python-fire#698 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 58/100
google/python-fire#672 · コメント 5 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
google/python-fire#659 · コメント 1 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 45/100
google/python-fire#643 · コメント 4 件 · リアクション 5 件 ·
google/python-fire の issue をすべて見る
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
learningequality/ricecooker#747 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
BSData/horus-heresy-3rd-edition#3171 ·
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
run-llama/llama_index#23199 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
KhronosGroup/glTF-Blender-IO#2769 ·