ケントンプソンのコンパイラハックは依然として脅威ですか?


156

ケン・トンプソン・ハック(1984)

Ken Thompsonは、1984年にコンパイラバイナリ(および* nixシステムのログインスクリプトのような他のコンパイル済みソフトウェア)を破壊する方法を概説しました。現代のコンパイルがこのセキュリティの欠陥に対処しているかどうか知りたいです。

簡単な説明:

2つの欠陥を含むようにコンパイラコードを書き直します。

  • 独自のバイナリをコンパイルするとき、コンパイラはこれらの欠陥をコンパイルする必要があります
  • 事前に選択された他のコード(ログイン関数)をコンパイルする場合、任意のバックドアをコンパイルする必要があります

したがって、コンパイラは正常に動作します-ログインスクリプトなどをコンパイルするとき、セキュリティバックドアを作成でき、将来、それ自体の新しいバージョンをコンパイルするとき、以前の欠陥を保持します- そして、欠陥はコンパイラにのみ存在しますバイナリなので、検出が非常に困難です。

質問:

私はウェブ上でこれらに対する答えを見つけることができませんでした:

  • これはジャストインタイムコンパイルとどのように関係しますか?
  • * nixシステムでログインを処理するプログラムのような関数は、実行時にコンパイルされますか?
  • これはまだ有効な脅威ですか、それとも1984年以降、これが重大な問題になるのを防ぐコンパイルのセキュリティの開発がありましたか?
  • これはすべての言語に影響しますか?

なぜ知りたいのですか?

宿題をしているときにこれに出くわしましたが、面白そうに思えましたが、これが現在の問題なのか、解決された問題なのかを具体的に理解する背景がありません。

参考資料


6
多様なダブルコンパイル戦略は、RoTTリグコンパイラの存在を検出する合理的に信頼できる方法です。
dmckee

3
NSAがこの種の攻撃に多大な労力を費やしたと思います。
ポールM

回答:


110

このハックはコンテキストで理解する必要があります。一度に発行されたのは、あらゆる種類の異なるハードウェアで実行されるUnixが支配的なシステムだったという文化です。

どのような攻撃が怖い作られたことはCコンパイラがあったことだったこれらのシステムのためのソフトウェアの中央部分。システムのほとんどすべては、最初にインストールされたときにコンパイラを通過しました(ハードウェアが異種であるため、バイナリ配布はまれでした)。誰もが常にものをコンパイルしました。人々は定期的にソースコードを検査しました(多くの場合、ソースコードをコンパイルするために調整を行う必要がありました)。

最近では、ハードウェアの互換性がはるかに高くなっているため、システムの日々の運用におけるコンパイラの役割ははるかに小さくなっています。侵害されたコンパイラは、もはや最も恐ろしいシナリオではありません。ルートキットと侵害されたBIOSは、検出して取り除くのがさらに困難です。


27
または、ほとんどの人はソースから何かをコンパイルしていないので(たとえば、Windows上で)あなたの平均トロイの木馬は(私が妥協コンパイラは道やり過ぎであることを合意しています):)十分でしょう
アンドレス・F.

16
@ArjunShankar:非フリーの専有バイナリ専用コンパイラは、このバックドアを必要とせず、持つこともできません。このバックドアは、ソースコードから自分でコンパイルするコンパイラにのみ適用されます。
-ruakh

12
デスクトップを除いて、Unixおよびそのすべてのバリアントは、依然として主要なオペレーティングシステムです。
ロブ

7
@ruakh:「これ」に重点を置いて理解していないかもしれませんが、たぶん反対します。このバックドアが非フリーの専用コンパイラを所有する会社に導入され、このコンパイラを使用して同じコンパイラの新しいバージョンをコンパイルする場合、このバックドアは元のシナリオよりもはるかに悪い影響を与えます。すべてに感染するために必要な攻撃ベクトルは1つだけです。
オリテナ

8
誰かがubuntuビルドサーバーを危険にさらし、ソースを変更せずにコンパイラを置き換えると想像してください。これが見つかるまで少し時間がかかるかもしれませんが、その時までに、ubuntuイメージは、侵害されたコンパイラが組み込まれた状態で(侵害されたログインアセンブリまたはあなたが持っているものとともに)人々に押し出されます。これはまだ完全に妥当な懸念事項だと思います。
ジミー・ホッファ

74

そのスピーチの目的は、対処する必要がある脆弱性を強調することでも、認識しておく必要がある理論上の脆弱性を提案することでもありませんでした。

目的は、セキュリティに関して言えば、誰も信頼する必要がないようにすることですが、残念ながらそれは不可能です。あなたは、常に信頼する必要があり、誰か (:「信頼する信頼に反省」ので、タイトルを)


あなたが彼のデスクトップのハードドライブを暗号化し、自分でコンパイルしなかったソフトウェアを実行することを拒否する偏執的なタイプであっても、オペレーティングシステムを信頼する必要があります。また、オペレーティングシステムを自分でコンパイルする場合でも、使用したコンパイラを信頼する必要があります。そして、さえあれば、あなた自身のコンパイラをコンパイルし、あなたはまだ信頼する必要があることをコンパイラに!そして、それはハードウェアメーカーにも言及していません!

あなたは誰も信頼して逃げることができません。それが彼が理解しようとしていたポイントです。


2
動作が実装定義または不特定の動作に依存しないオープンソースコンパイラがある場合、さまざまな独立して開発されたコンパイラ(信頼されているかどうかに関係なく)を使用してコンパイルし、すべての異なるコンパイルバージョンを使用して1つのプログラムをコンパイルしますそのオープンソースは、すべてのコンパイラがまったく同じ出力を生成する必要があります。もしそうなら、それは、トロイの木馬が1つにいる唯一の方法は、それがすべて同じである場合であることを示唆するでしょう。それはかなりありそうにないでしょう。しかし、.netの多くを使った私の
覗き見の

9
@supercat:あなたはポイントを逃しているようです。あなたはケン・トンプソンが提示したハックは回避できると言っています。彼が選んだ特定のハックは重要ではないと言っています。それは単なる例であり、常に誰かを信頼しなければならないという彼のより大きなポイントを示しています。だからこそ、この質問はいくぶん無意味です- それは完全に木のための森を見逃しています。
BlueRaja-ダニーPflughoeft

9
@supercat:異なる設計決定、最適化などのために、異なるコンパイラが非自明なプログラムに対して同じバイトコードを生成する可能性は非常に低いです。これは疑問を提起します-バイナリが同一であることをどのように知っていますか?
アンキットソニ

1
@AnkitSoni:私の答えはより詳細になります。適切に作成されたオープンソースのコンパイラ/リンカーを異なるコンパイラに供給すると、同じ動作をする異なる実行可能ファイルが生成されます。実際に実行可能ファイルが同じように動作する場合、オープンソースのコンパイラ/リンカーのコードが実行可能ファイルを通過すると、実行可能ファイルは同じ出力を生成します。ファイルを比較するには、ファイルをフロッピーディスクにコピーし、アンティークコンピューターを使用して比較します。
supercat

2
この会話の一部は、テストしたものに対して、バイナリ/ハードウェアが期待どおりに動作することを意味していませんか?まだテストしておらず、気づいていない何かが残っている可能性があります。
バートシルバース

53

番号

最初に説明したように、攻撃は決して脅威ではありませんでした。コンパイラは理論的にはこれを行うことができますが、実際に攻撃を実行するには、コンパイラをプログラミングする必要があります

  • コンパイルされているソースコードがコンパイラのものである場合を認識し、
  • ハックを挿入するために任意のソースコードを変更する方法を見つけます。

これには、コンパイラが破損することなく変更できるように、ソースコードからコンパイラがどのように機能するかを把握する必要があります。

たとえば、リンク形式が、コンパイルされたマシンコードのデータ長またはオフセットを実行可能ファイルのどこかに保存するとします。コンパイラは、これらのうちどれを更新する必要があるのか​​、エクスプロイトペイロードを挿入する場合はどこでそれを把握する必要があります。コンパイラの後続バージョン(無害バージョン)はこの形式を任意に変更できるため、エクスプロイトコードはこれらの概念を効果的に理解する必要があります。

これは、高度な自己指向プログラミングであり、ハードAIの問題です(最後に確認したように、最先端技術は、そのタイプによって実際に決定されるコードを生成していました)。見てください:これを行うことができる人間はほとんどいません。プログラミング言語を学び、最初にコードベースを理解する必要があります。

AIの問題が解決したとしても、小さなコンパイラーをコンパイルすると、巨大なAIライブラリーがリンクされたバイナリーが生成されることに気付くでしょう。

類似攻撃:ブートストラップ信頼

ただし、攻撃の一般化は重要です。基本的な問題は、信頼の連鎖がどこかで始まる必要があり、多くのドメインでは、その起源が検出しにくい方法で連鎖全体を破壊する可能性があるということです。

実生活で簡単に脱落できる例

Ubuntu Linuxなどのオペレーティングシステムは、ダウンロードされた更新パッケージをリポジトリの署名キーと照合して(公開キー暗号化を使用)、更新のセキュリティ(整合性)を確保します。ただし、これは、署名キーが正当なソースによって所有されていることを証明できる場合にのみ、更新の信頼性を保証します。

署名キーはどこで入手しましたか?オペレーティングシステムのディストリビューションを初めてダウンロードしたとき。

信頼の連鎖のソースであるこの署名キーが悪ではないことを信頼する必要があります。

あなたとUbuntuダウンロードサーバー間のインターネット接続をMITMできる人なら誰でも、これはあなたのISP、インターネットアクセスを管理する政府(中国など)、またはUbuntuのホスティングプロバイダーかもしれませんが、このプロセスをハイジャックしたでしょう。

  • Ubuntu CDイメージをダウンロードしていることを検出します。これは簡単です。要求が(公開されている)Ubuntuミラーのいずれかに送られ、ISOイメージのファイル名を要求することを確認してください。
  • 独自のサーバーからリクエストを処理し、Ubuntuの代わりに攻撃者の公開キーとリポジトリの場所を含むCDイメージを提供します。

その後、攻撃者のサーバーから更新を安全に取得します。更新はルートとして実行されるため、攻撃者は完全に制御できます。

オリジナルが本物であることを確認することにより、攻撃を防ぐことができます。ただし、これには、ダウンロードしたCDイメージをハッシュを使用して検証する必要があります(実際にこれを行う人はほとんどいません)。ハッシュ自体は、たとえばHTTPS経由で安全にダウンロードする必要があります。また、攻撃者がコンピュータに証明書を追加できる場合(企業環境で一般的)、または認証局(中国など)を制御する場合、HTTPSでも保護されません。


47
これは誤りです。コンパイラは、コンパイルされていないとき、非常に具体的な内容で、独自のソースコードから非常に特定のソースファイルをコンパイルされたときを決定するために持っているすべての一切のコンパイラを!
カズ

14
@Kaz-ある時点で、コンパイラまたはログインプログラムに対するボード上の変更が、バックドアのコンパイラ認識/ログイン認識を無効にするポイントに到達する可能性があり、その後の反復でバックドアが失われます。これは、特定の病気に対する免疫を付与するランダムな生物学的突然変異に類似しています。
ラッセルボロゴーブ

12
あなたの答えの前半には、カズが説明する問題がありますが、後半はとてもいいので、とにかく+1しています!
-ruakh

7
非常に独自のソースのみを認識する邪悪なコンパイラは、簡単に構築できますが、実際には比較的価値がありません。すでにこのコンパイラのバイナリを持っている人は、このバイナリを使用してバイナリを再作成しません。攻撃がより長い期間成功するためには、コンパイラーはより多くのインテリジェンスを必要とし、それ自体のソースの新しいバージョンにパッチを適用し、snswerで説明されている問題に遭遇します。
user281377

5
特定のコンパイラのレコグナイザーは非常に一般的であり、新しいバージョンに直面しても壊れない可能性があります。たとえば、gccを取り上げます。gccの多くのコード行は非常に古く、あまり変更されていません。名前のような単純なものはほとんど変わりません。認識がおかしくなる前に、注入されたコードがそうなる可能性があります。そして実際には、これらの問題はどちらも大部分が理論的なものです。実際には、マルウェアの作成者は、コンパイラ開発の(遅い)ペースに遅れずについていくことに問題はありません。
イーモンネルボンヌ

25

まず、このハックのお気に入りの記事はStrange Loopsです。

この特定のハックは、確実に(*)今日、主要なオープンソースOSプロジェクト、特にLinux、* BSDなどのいずれかで行われる可能性があります。ほぼ同じように動作することを期待しています。たとえば、opensshを変更するために悪用されたコンパイラを含むFreeBSDのコピーをダウンロードします。それ以降、opensshまたはコンパイラをソースごとにアップグレードするたびに、問題が続きます。攻撃者が最初にFreeBSDのパッケージ化に使用したシステムを悪用したと仮定すると(おそらく、イメージ自体が破損しているか、攻撃者が実際にパッケージャーであるため)、そのシステムがFreeBSDバイナリを再構築するたびに、問題を再注入します。この攻撃が失敗する方法はたくさんありますが、それらはケンの攻撃が失敗する方法と根本的に違いはありません(**)。世界はそれほど大きく変わっていません。

もちろん、同様の攻撃は、所有者がJava、iOS SDK、Windows、またはその他のシステムなどのシステムに簡単に(またはより簡単に)注入することができます。特定の種類のセキュリティ欠陥をハードウェアに組み込むこともできます(特に乱数生成を弱める)。

(*)しかし、「確かに」とは、「原則的に」という意味です。この種の穴が特定のシステムに存在することを期待する必要がありますか?いいえ。さまざまな実際的な理由で、それはありそうもないと考えています。時間が経つにつれて、コードが変更および変更されるにつれて、この種のハックが奇妙なバグを引き起こす可能性が高くなります。そして、それはそれが発見される可能性を高めます。あまり巧妙ではないバックドアを維持するには、陰謀が必要です。もちろん、「合法的傍受」バックドアがさまざまな電気通信およびネットワークシステムにインストールされているという事実はわかっているため、多くの場合、この種の手の込んだハッキングは不要です。ハックはあからさまにインストールされます。

だから、常に、徹底した防御。

(**)ケンの攻撃が実際に存在したと仮定します。彼は、それどのように行われるかについて議論しました。私の知る限り、彼は実際にそれをやったとは言わなかった。


2番目の脚注について、ケンは「ビルドして配布しない」
8bittree

15

これはすべての言語に影響しますか?

この攻撃は、主に自己ホスト型の言語に影響します。これは、コンパイラーが言語自体で記述されている言語です。C、Squeak Smalltalk、およびPyPy Pythonインタープリターはこの影響を受けます。Perl、JavaScript、およびCPython Pythonインタープリターはそうしません。

これはジャストインタイムコンパイルとどのように関係しますか?

それほど多くない。ハックを隠すことができるのは、コンパイラの自己ホスト型の性質です。自己ホスト型のJITコンパイラーは知りません。(たぶんLLVM?)

* nixシステムでログインを処理するプログラムのような関数は、実行時にコンパイルされますか?

通常ではありません。しかし、問題はそれがいつコンパイルされるかではなく、どのコンパイラーによってコンパイルされるかです。ログインプログラムが汚染されたコンパイラによってコンパイルされた場合、そのプログラムは汚染されます。クリーンコンパイラによってコンパイルされた場合、クリーンになります。

これはまだ有効な脅威ですか、それとも1984年以降、これが重大な問題になるのを防ぐコンパイルのセキュリティの開発がありましたか?

これはまだ理論上の脅威ですが、あまりありそうにありません。

軽減するためにできることの1つは、複数のコンパイラを使用することです。たとえば、GCCによってコンパイルされたLLVMコンパイラは、バックドアを通過しません。同様に、LLVMによってコンパイルされたGCCはバックドアを通過しません。そのため、この種の攻撃が心配な場合は、コンパイラを別の種類のコンパイラでコンパイルできます。つまり、悪意のあるハッカー(OSベンダーですか?)は、お互いを認識するために両方のコンパイラーを汚染する必要があります。はるかに難しい問題。


最後の段落は厳密に言えば真実ではありません。理論的には、コードはコンパイルされているコンパイラを検出し、バックドアを適切に出力できます。もちろんこれは現実の世界では実用的ではありませんが、本質的にそれを妨げるものは何もありません。しかし、その後、元のアイデアは実際の実際的な脅威ではなく、信頼の教訓でした。
スティーブンバーナップ

公正なポイント。結局のところ、ハックはログイン用のバックドアとコンパイラー用のmodを運ぶため、別のコンパイラー用のmodも運ぶことができます。しかし、その可能性はますます低くなります。
ショーンマクミラン

ジャストインタイムでのコンパイルはおもしろいかもしれません。特定のピースがJITコンパイルされている場合にのみコードに脆弱性があると、気付かない場合があります。(純粋な理論)
GameDeveloper

12

これが起こる可能性は理論的にはあります。ただし、David A. WheelerのDiverse double-compilingを使用して、特定のコンパイラ(使用可能なソースコードを含む)が侵害されているかどうかを確認する方法があります。

基本的に、疑わしいコンパイラと独立して開発された別のコンパイラの両方を使用して、疑わしいコンパイラのソースをコンパイルします。これにより、SC scとSC Tが得られます。次に、これらのバイナリの両方を使用して疑わしいソースをコンパイルします。結果のバイナリが同一である場合(さまざまなタイムスタンプなど、正当に異なる可能性のあるさまざまなものを除く)、疑わしいコンパイラは実際に信頼を悪用していませんでした。


それまたは信頼できるコンパイラは、ユーザーが思ったほど信頼できません。しかし、言語の2つの独立した実装では、同じバックドアが含まれる可能性は無視できます。
ダミアンジェリック

または、それらを比較するために使用しているdiffツールも侵害されました;)
iCodeSometime

@kennycocただし、「これらの2つのファイルが同一か」比較ツールを作成することは、すべてのことを考慮すると難しくありません(たとえば、syscall参照が与えられると、バイナリマシンコードで2〜16時間で実行できるはずです)。
バティーン

3

特定の攻撃として、それはかつてないほど脅威であり、ほとんど脅威ではありません。

これはジャストインタイムコンパイルとどのように関係しますか?

それがどういう意味かわかりません。JITterはこれに耐性がありますか?いいえ。より脆弱ですか?あんまり。開発者として、あなたのアプリは、それが行われていないことを検証できないという理由だけで、より脆弱です。まだ開発されていないアプリは基本的にこれとすべての実用的なバリエーションの影響を受けないことに注意してください。コードよりも新しいコンパイラについてのみ心配する必要があります。

* nixシステムでログインを処理するプログラムのような関数は、実行時にコンパイルされますか?

それは本当に関係ありません。

これはまだ有効な脅威ですか、それとも1984年以降、これが重大な問題になるのを防ぐコンパイルのセキュリティの開発がありましたか?

コンパイルの本当のセキュリティはありませんし、そうすることはできません。それが本当に彼の話のポイントであり、ある時点で誰かを信頼しなければならないということです。

これはすべての言語に影響しますか?

はい。基本的に、いつか、あなたの指示はコンピューターが実行するものに変えなければならず、その翻訳は間違って行われる可能性があります。


-2

David Wheelerには良い記事があります:http : //www.dwheeler.com/trusting-trust/

私、ハードウェア攻撃がもっと心配です。FLOSSソースコードを備えた完全にVLSIの設計ツールチェーンが必要だと思います。これは、ツールによって挿入されるバックドアのないマイクロプロセッサを構築できるように、自分で変更およびコンパイルできます。ツールは、チップ上のトランジスタの目的も理解できるようにする必要があります。その後、完成したチップのサンプルを取り出して顕微鏡で検査し、ツールが持っているはずの回路と同じ回路を持っていることを確認しました。


3
-1、回答の大部分が質問に対処できません。

-3

エンドユーザーがソースコードにアクセスできるシステムは、このタイプの攻撃を隠さなければならないシステムです。それらは今日の世界ではオープンソースのシステムになるでしょう。問題は、すべてのLinuxシステムで単一のコンパイラーに依存しているものの、攻撃はすべての主要なLinuxディストリビューションのビルドサーバーに到達する必要があることです。コンパイラーのリリースごとにコンパイラーのバイナリーを直接ダウンロードしないため、少なくとも1つ前のコンパイラーのリリースでは、攻撃のソースはビルドサーバー上になければなりませんでした。それまたはバイナリとしてダウンロードした最初のバージョンのコンパイラが危険にさらされている必要があります。


2
あなたの答えは質問の表面をひっかいていますが、実際に尋ねられていることに対処していません。

-4

出力が提供されたソースファイルの内容以外に依存してはならないコンパイラ/ビルドシステムのソースコードがあり、他のいくつかのコンパイラがあり、すべてが同じコンパイラハックを含んでいないことがわかっている場合ソースコード以外に依存しない実行可能ファイルを取得するようにしてください。

コンパイラ/リンカーパッケージ(Groucho Suiteなど)のソースコードが、出力が不特定の動作や入力ソースファイルの内容以外に依存しないように記述されているとします。独立して生成されたさまざまなコンパイラ/リンカーパッケージ(Harpoスイート、Chicoスイート、Zeppoスイートなど)のコードをリンクし、それぞれに異なる実行可能ファイルのセットを生成します(G-Harpo、G-Chico、およびG-Zeppo)。これらの実行可能ファイルが異なる命令のシーケンスを含むことは予想外ではありませんが、機能的に同一である必要があります。ただし、すべてのケースで機能的に同一であることを証明することは、扱いにくい問題になる可能性があります。

幸いなことに、結果の実行可能ファイルを1つの目的(Grouchoスイートの再コンパイル)にのみ使用する場合、このような証明は必要ありません。G-Harpo(GG-Harpoを生成)、G-Chico(GG-Chico)、およびG-Zeppo(GG-Zeppo)を使用してGrouchoスイートをコンパイラする場合、結果の3つのファイルすべて、GG-Harpo、GG-Chico 、およびGG-Zeppoは、すべてバイト単位で同一である必要があります。ファイルが一致する場合、それらのいずれかに存在する「コンパイラウイルス」はすべてのファイルに同一に存在する必要があることを意味します(3つのファイルはすべてバイト単位で同一であるため、それらの動作が異なる可能性はありません仕方)。

他のコンパイラーの年齢と系統によっては、そのようなウイルスがコンパイラーに存在する可能性がないことを保証できる場合があります。たとえば、2007年にゼロから作成されたコンパイラに1980年代に作成されたMPWのバージョンを介してアンティークMacintoshを使用すると、1980年代のコンパイラは2007コンパイラのどこにウイルスを挿入するかを知りません。今日のコンパイラーは、それを理解するのに十分なコード分析を行うことが可能かもしれませんが、そのような分析に必要な計算レベルは、単純にコードをコンパイルするために必要な計算レベルをはるかに超えており、気付かれることはあまりありませんでしたコンパイル速度が主要なセールスポイントであった市場で。

作成する実行可能ファイルのバイトが送信されたソースファイルの内容以外に依存しないコンパイルツールを使用している場合、Thompsonからの十分に優れた耐性を実現できると仮定します。スタイルのウイルス。残念ながら、何らかの理由で、コンパイルの非決定性は一部の環境では正常と見なされるようです。マルチCPUシステムでは、2つのスレッドのどちらが最初に作業を終了するかによってコード生成の特定の側面を変えることが許可されている場合、コンパイラがより速く実行できる可能性があることを認識しています。

一方、コンパイラ/リンカーが、出力がソースファイルとユーザーによって上書きされる可能性のある「コンパイル日」のみに依存する「標準出力」モードを提供すべきではない理由がわからない。そのようなモードでコードをコンパイルするのに通常のコンパイルの2倍の時間がかかったとしても、「リリースビルド」をバイト単位で完全にソースマテリアルから再作成できることには、かなりの価値があることをお勧めします。リリースビルドは「通常のビルド」よりも時間がかかります。


2
-1。あなたの答えが質問の核となる側面をどのように扱っているかわかりません。

@ GlenH7:多くの古いコンパイルツールは、ビットが同一の入力を与えると、一貫してビットが同一の出力を生成します(「公式」コンパイル時間を報告するために微調整できるTIMEなど)。このようなツールを使用すれば、コンパイラウイルスからの保護をかなりうまく行うことができます。人気のある開発フレームワークの中には、コードを「確定的に」コンパイルする方法を提供しないものがあるということは、古いツールでウイルスから保護できた技術を新しいツールで効果的に使用できないことを意味します。
supercat

これを試しましたか?1.論文でリードします。2.短い段落を使用します。3.「機能的に同一」(最初の段階の結果)と「ビット同一」(2番目の結果)の違いについてより明確にします。4. David A. WheelerのDDC論文を引用します。
ダミアンジェリック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.