サーバーが小さく、ユーザーから提供されたCプログラムのコンパイル時間を確認したい。プログラムはコンパイルされて実行されることはありません。
ユーザーがgcc 5.4.0を使用して任意のCをコンパイルできるようにするには、どのようなリスクがありますか?
少し奇妙なことですが、それはサービス拒否リスク、または潜在的な情報漏えいです。
Cのプリプロセッサは#include
ディレクティブで指定されたファイルを陽気にインクルードするため、誰かが#include "../../../../../../../../../../dev/zero"
を実行でき、プリプロセッサは/dev/zero
の最後まで読み取ろうとします(幸運)。
同様に、特にコンパイルの試みの出力を他の人に見せると、誰かがシステムに存在するかどうかに関係なく、さまざまなファイルを含めて、マシンについての情報を得る可能性があります。 #pragma poison
の巧妙な使用法と組み合わせると、それらはmightでなくても、ファイルの内容について学ぶことができますt完全なエラーメッセージを提供します。
関連して、プラグマは多くのプリプロセッサー、コンパイラー、またはリンカーの動作を変更する可能性があり、ソースファイルで指定されます。 おそらく誰かが出力ファイル名を指定するようなことをさせるようなものはありませんが、存在する場合、機密を上書きするために悪用される可能性がありますファイル、またはそれ自体を実行します(cronなどに書き込むことにより)。同様に危険なものがあるかもしれません。信頼できないコードをコンパイルする場合は、本当に注意が必要です。
Cは非常に強力な言語であり、Cを使用して実行できる恐ろしいことのいくつかはあなたに衝撃を与えるでしょう。たとえば、コンパイルに27分かかる16バイトのCプログラム を作成し、最終的に完了すると、 16ギガバイト実行可能ファイルにコンパイルします。そして、それは16バイトだけを使用しています。プリプロセッサとより大きなソースコードファイルを考慮に入れると、はるかに大きなコンパイラ爆弾が作成される可能性があります。
これは、サーバーにアクセスできるすべてのユーザーがサーバーに DoS 攻撃を効果的に実行できることを意味します。公平に言うと、これは、誰かがコンパイラの脆弱性を悪用することや、(他の回答者が話したように)サーバーに関する情報を取得するために機密ファイルを含めることよりもはるかに危険が少なくなります。
しかし、任意のコードをコンパイルするときに遭遇する可能性のあるもう1つの不快な点です。すべてのビルドに時間制限を設定し、バイナリファイルを保存しないようにしてください。もちろん、作成中もディスクに保持する必要があります。仮に誰かがコンパイラの爆弾をハードドライブよりも大きくした場合、問題が発生します(ビルドを完了させた場合)。
@AndréBorie は正しいです。コンパイラと対応する構成は、セキュリティの問題について十分に吟味されないため、一般的に言えば、信頼できないコードをコンパイルするべきではありません。
リスクは、バッファオーバーフローまたはある種のライブラリ実行の脆弱性が悪用され、攻撃者がコンパイラを実行した(できれば非root
!)ユーザーアカウントにアクセスできることです。 root
以外のハッキングでさえ、ほとんどの場合深刻です。これについては、別の質問で詳しく説明することができます。
VMを作成することは、アプリケーションの残りの部分に害を与えないように潜在的なエクスプロイトを含めるための優れたソリューションです。
Linuxのテンプレートを用意することをお勧めしますVMクリーンスレートコンパイラ環境で必要に応じて起動できます。
理想的には、使用するたびに廃棄することになりますが、これは必ずしも必要ではありません。 VMを十分に分離し、VMからの応答データを適切にサニタイズする場合は、とにかく行う必要があります。ハックができる最悪のことは、DoSまたは誤ったコンパイル時間の作成です。これらはそれ自体では重大な問題ではなく、少なくともアプリケーションの残りの部分にアクセスするほど深刻ではありません。
ただし、VMを毎回使用するたびに(つまり、毎日ではなく)リセットすると、全体的に安定した環境が提供され、特定のEdgeケースでセキュリティが向上します。
一部のOSでは、VMの代わりにコンテナが提供されています。これは無駄のないアプローチかもしれませんが、同じ原則が適用されます。
はい、それは危険です。しかし、人々が言ったように、それは可能です。私は https://gcc.godbolt.org/ のオンラインコンパイラの作成者であり、メンテナでもあります。次の組み合わせを使用して安全にすることは非常に有効です。
LD_PRELOAD
ラッパー( ソースはこちら )を使用して実行されます。これにより、コンパイラーは明示的なホワイトリストにないファイルを開くことができなくなります。これにより、/ etc/passwdや他の類似のものを読み取ることができなくなります(それだけではそれほど役に立ちません)。LD_PRELOAD
が悪い行動をとるのではなく、「これを試してはいけない」というエラーメッセージを表示する方法にすぎません。ソース全体は GitHub にあり、ソースは dockerコンテナーイメージ およびコンパイラーなどにあります。
私は ブログ投稿 を作成して、セットアップ全体がどのように実行されるかを説明しました。
ルートとしてコンパイラーを実行することは望ましくありませんが、これは「容易さと利便性」の理由で発生することを見てきました。攻撃者が次のようなものを含めるのは非常に簡単です。
#include "../../../../etc/passwd"
#include "../../../../etc/shadow"
コンパイラエラーメッセージの一部としてこれらのファイルの内容を取得します。
また、コンパイラーは他のすべてと同様のプログラムであり、脆弱である可能性のあるバグがあり、誰かがCプログラムをファズして問題を引き起こすのは簡単です。
ほとんどのアプリケーションセキュリティは、何よりもまず入力の検証に焦点を当てますが、残念ながらCコンパイラの「安全で有効な」入力を定義することはおそらく困難であり、停止の問題があります:)
ユーザーにコードを含むアーカイブの提供を許可すると、コンパイラーではなく、コンパイラーが使用するリンカーで問題が発生する可能性があります;)
ldは、存在しないファイルを指している場合、シンボリックリンクをたどります。つまり、test.cを出力a.outにコンパイルしたが、ディレクトリにa.outという名前のシンボリックリンクが存在しないファイルを指している場合、コンパイルされた実行可能ファイルは、ファイル(ユーザー権限の制限付き)。
実際には、攻撃者は、たとえば、コードに公開sshキーを含む文字列を含め、a.outから〜/ .ssh/authorized_keysという名前のシンボリックリンクを提供できます。 。そのファイルがまだ存在しない場合、これにより攻撃者はsshキーをターゲットマシンに埋め込み、パスワードを解読することなく外部アクセスを許可できます。