bashで組み込みコマンドの使用を明示的かつ安全に強制するにはどうすればよいですか


19

あります同様の質問は、あなたが例えば交換したい「ラッピング」シナリオ、との取引cd組み込みを呼び出すコマンドでcd

ただし、shellshockなどの観点から、bashが環境から関数をインポートすることを知っているため、いくつかのテストを行ったためcd、スクリプトから組み込み関数を安全に呼び出す方法を見つけることができません。

このことを考慮

cd() { echo "muahaha"; }
export -f cd

この環境でを使用して呼び出されたスクリプトはすべてcd破損します(などの影響を考慮してくださいcd dir && rm -rf .)。

コマンドのタイプをチェックするコマンド(便利なtype)と、関数ではなく組み込みバージョン(builtinおよびcommand)を実行するコマンドがあります。しかし、見よ、これらも関数を使用してオーバーライドできます

builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }

以下を生成します。

$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha

環境全体をクリアせずに、bashに組み込みコマンドを安全に使用させる方法、または少なくともコマンドが組み込みコマンドではないことを検出する方法はありますか?

とにかく誰かがあなたの環境を制御しているなら、おそらくあなたはねじ込まれていると思いますが、少なくともエイリアスの場合は、その\前にaを挿入することによってエイリアスを呼び出さないオプションがあります。


あなたは使用してスクリプトを実行することができenv、このように、前のコマンドを:env -i <SCRIPT.sh>
はArkadiusz Drabczyk

env関数としても再定義されていない場合のみ。これは恐ろしいです。最初に、特殊文字が役立つと考えました-を含む完全なパスで呼び出す、ソースに/使用.するなど。しかし、それらは関数名にも使用できます!あなたは、することができますあなたが望む任意の関数を再定義し、それが元のコマンドを呼び出すに戻って取得するのは難しいです。
オリオン

1
確かに、侵害されたマシンでスクリプトを実行しようとすると、とにかくねじ込まれます。または、#/bin/shこれがデフォルトの対話型シェルでない場合は、スクリプトを記述します。
はArkadiusz Drabczyk

回答:


16

Olivier Dはほぼ正しいですが、POSIXLY_CORRECT=1実行する前に設定する必要がありますunset。POSIXには特別なビルトインの概念があり、bashはこれをサポートします。unsetそのような組み込みの1つです。検索SPECIAL_BUILTINでのbuiltins/*.cリストについては、bashのソースでは、それが含まれsetunsetexportevalsource

$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset

ローグは、unset今あなたが未設定の場合は、環境から取り出されたcommandtypebuiltinその後、先に進むことができるはずですが、unset POSIXLY_CORRECTあなたは非POSIXの動作や高度なbashの機能に依存している場合。

ただし、これエイリアスに対応していません。したがって\unset、インタラクティブシェルで動作することを確認するために使用する必要があります(またはexpand_aliases、有効な場合は常に)。

妄想のために、これすべて修正するはずです、私は思う:

POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do 
    [[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]}; 
done < <( \help -s "*" )

whiledodone[[言葉を予約されており、注意を必要としません。)私たちが使用している注意してくださいunset -f未設定の機能を確認するために、変数と関数が同じ名前空間を共有するが、両方が同時に(ETANライスナーのおかげで)場合に存在することが可能です2回アンセットすることでもうまくいきます。あなたはすることができ、bashがあなたが読み取り専用機能を設定解除し、bashの-4.2は、bashの-4.3があなたを防ぐん含め防ぐことはできません読み取り専用機能をマークしたがとき、それはまだ特殊な組み込みコマンドを称えるPOSIXLY_CORRECT設定されています。

読み取り専用POSIXLY_CORRECTこれはブールまたはフラグのではない、本当の問題ではない存在が読み取り専用あなたがPOSIXに頼ることができますが、値が空または0あなたは、単にする必要があります場合でも、特徴として、それが存在しているそうだとすれば、POSIXモードが有効になります問題のある関数を上記とは異なる方法で設定します。おそらくカットアンドペーストを使用します。

\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done

(およびエラーを無視します)、または他のスクリプトバティックに従事します。


その他の注意事項:

  • functionは予約語です。別名を付けることはできますが、関数でオーバーライドすることはできません。(エイリアスを回避する方法として受け入れられないfunctionため、エイリアスはやや面倒です)\function
  • [[]]予約語であり、別名を付けることはできます(無視されます)が、関数でオーバーライドすることはできません(関数はそのように命名できます)
  • (( 関数の有効な名前でもエイリアスでもありません

興味深い、ありがとう!私はbashがデフォルトで他を上書きから保護しないことを奇妙に思ってunsetいます。
ファルストロ

これには-f議論が必要ではありunsetませんか?そうでない場合、ビルトインと同じ名前の変数と関数の両方が定義されてunsetいる場合、最初に設定解除する変数を選択します。また、不明瞭な機能のいずれかが設定されreadonlyている場合、これは失敗しませんか?(それは検出可能であり、致命的なエラーを引き起こす可能性があります。)また、これは[見かけの組み込みを逃します。
エタンReisner

1
\unset -f unset読み取りループで行われることを考えると、意味がないと思います。if unset\unset組み込み関数の代わりに通常は解決される関数ですが\unset、POSIXモードが有効である限り安全に使用できます。明示的に呼び出すこと\unset -f[.、と:あなたの正規表現を除外し、それらとして、しかし良い考えかもしれません。また、ループ内に追加-fし、ループの前ではなく、後にします。(後)は、後続のコマンドでエスケープを安全に無視することもできます。\unset\unset POSIXLY_CORRECT\unalias -a\unset -f unalias
エイドリアンギュンター

1
@AdrianGünterTry:、[[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]これにより、変数が設定されていない場合は示されたエラーで非対話式スクリプトが終了し、変数が設定されている場合(空または任意の値)続行されます。
Mr.spuratic

1
「使用する必要があります\unset」...最初の文字だけでなく、エイリアスの展開を回避するために、任意の文字を引用符で囲むことに注意してください。un"se"t読みにくいとはいえ、同様に機能します。「各単純コマンドの最初の単語は、引用符で囲まれていない場合、エイリアスがあるかどうかを確認するためにチェックされます。」– Bash Ref
ロビンA.ミード

6

とにかく誰かがあなたの環境を制御しているなら、おそらくあなたはおそらくねじ込まれていることに気づきます

はい、その。未知の環境でスクリプトを実行するとLD_PRELOAD、シェルプロセスがスクリプトを読み取る前に任意のコードを実行することから始まる、あらゆる種類の問題が発生する可能性があります。スクリプト内から敵対的な環境から保護しようとするのは無益です。

Sudoは、10年以上にわたってbash関数の定義のように見えるものをすべて削除することにより、環境をサニタイズしてきました。Shellshock以来、完全に信頼されていない環境でシェルスクリプトを実行する他の環境がそれに続きました。

信頼できないエンティティによって設定された環境でスクリプトを安全に実行することはできません。したがって、関数定義を心配することは非生産的です。環境をサニタイズし、その際にbashが関数定義として解釈する変数をサニタイズします。


1
私はこれに完全に反対します。セキュリティは、「サニタイズ」または「サニタイズなし」を中心としたバイナリの提案ではありません。搾取の機会を取り除くことです。そして残念なことに、現代のシステムの複雑さは、適切にロックダウンする必要がある多くの搾取の機会があることを意味します。多くの悪用の機会は、PATH変数の変更、組み込み関数の再定義など、無害に見えるアップストリーム攻撃に集中しています。
デジェイクレイトン

@DejayClayton私はあなたのコメントに完全に同意します。最初の文を除いて、それが私の答えとどのように矛盾するかわかりません。悪用の機会を削除することは役立ちますが、攻撃の些細な調整によって機能し続けることができる場合、その半分だけを削除するわけではありません。
ジル 'SO-悪であるのをやめる'

私のポイントは、単に「環境をサニタイズ」して、さまざまな攻撃ベクトルについて心配するのをやめることができないということです。場合によっては、「スクリプト内から敵対的な環境から保護する」こともあります。「関数定義」の問題を解決したとしても、誰かが「cat」または「ls」という名前のカスタムスクリプトをディレクトリに配置し、次に「cat 「/ bin / cat」および「/ bin / ls」の代わりに「」または「ls」が効果的にエクスプロイトを実行しています。
デジェイクレイトン

@DejayClayton環境をサニタイズすることは、環境とは無関係の攻撃ベクトルには役立たないことは明らかです。(たとえば/bin/cat、chroot を呼び出すスクリプトは、何でも呼び出すことができます。)環境をサニタイズすると、正気になりますPATH(当然、正しく実行していると仮定します)。私はまだあなたの主張を見ていません。
ジル 'SO-悪であるのをやめる'

PATHはエクスプロイトの最大の機会の1つであり、多くの疑わしいPATHプラクティスがセキュリティブログでも推奨アドバイスとして文書化されていることを考慮し、またインストールされたアプリケーションがPATHを並べ替えてそのようなアプリが機能することを確認すると、どのように見えるかわかりませんスクリプト内での防御的なコーディングは悪い考えです。正しいPATHとみなすものは、実際には、あなたが遭遇していないエクスプロイトに対して脆弱である可能性があります。
デジェイクレイトン

1

unset -f組み込み関数、コマンド、およびタイプを削除するために使用できます。


2
申し訳ありませんが、unset() { true; }その世話をします。
ファルストロ

1
くそー!また、定義済み関数のリストも組み込み関数に依存しています。あきらめる!
odc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.