13

C を学習しているときに、初期化されていない文字配列の要素をいくつか間違えて出力してしまいました。

配列のサイズを非常に大きく、たとえば 100 万要素のサイズに拡張して内容を出力すると、出力される内容は常にユーザーが読み取れないわけではありませんが、ランタイム情報が含まれているように見えます。

次のコードを検討してください。

#include <stdio.h>
main() {

        char s[1000000];
        int c, i;

        printf("Enter input string:\n");
        for (i = 0; ( c = getchar()) != '\n'; i++) {
                s[i] = c;
        }   

        printf("Contents of input string:\n");
        for (i = 0; i < 999999; i++) {
                putchar(s[i]);
        }   
        printf("\n");

        return 0;
}

出力をスクロールするだけで、次のようなことがわかります。

?? ?l?? ??????_dyldVersionNumber_dyldVersionString_dyld_all_image_infos_dyld_fatal_error_dyld_shared_cache_ranges_error_string__mh_dylinker_header_stub_binding_helper_dyld_func_lookup_offset_to_dyld_all_image_infos__dyld_start__ZN13dyldbootstrapL30randomizeExecutableLoadAddressEPK12macho_headerPPKcPm__ZN13dyldbootstrap5startEPK12macho_headeriPPKcl__ZN4dyldL17setNewProgramVarsERK11ProgramVars__ZN4dyld17getExecutablePathEv__ZN4dyld22mainExecutablePreboundEv__ZN4dyld14mainExecutableEv__ZN4dyld21findImageByMachHeaderEPK11mach_header__ZN4dyld26findImageContainingAddressEPKv

また、

Apple Inc.1&0$U ?0?*?H??ot CA0?"0ple Certification Authority10U ?䑩 ??GP??^y?-?6?WLU????Kl??"0?>?P ? A??????f?$kУ????z ?G?[?73??M?i??r?]?_???d5#KY?????P??XPg? ?ˬ, op??0??C??=?+I(??ε??^??=?:??? ?b??q?GSU?/A????p??LE~ LkP?A??tb
?!.t?< ?A?3???0X?Z2?h???es?g^e?I?v?3e?w??-??z0?v0U?0U ?0?0U+?iG?v ??k?.@??GM^0U#0?+?iG?v ??k?.@??GM^0?U 0?0 ??H??cd0? ?0+ https: //www.apple.com/appleca/0?+0????いずれかの当事者によるこの証明書への依存は、その時点で適用される標準的な使用条件、証明書 poli?\6?Lx への同意を前提としています。 ?팛??w??v?w0O??=G7?@?,ω??s???d?yO4?>?x?k??}9??S ?8ı??O 01 ? H??[d?c3w?:,V??!ںsO??6?U٧??2B???q?~?R??B$*??M?^c?K?P???? ????7?uu!0?0??0

私の$PATH環境変数が出力されたことさえあると思います。

初期化されていない変数の内容がセキュリティ リスクを引き起こす可能性はありますか?

更新 1

モチベーター

更新 2

したがって、これが実際にセキュリティ上のリスクであることは、回答から明らかです。これは私を驚かせます。

OSがそのメモリを初期化したプログラム以外のプログラムへのアクセスを制限できるように、プログラムがそのメモリ内容を保護されていると宣言する方法はありませんか?

4

5 に答える 5

11

ほとんどのCプログラムはmalloc、メモリの割り当てに使用します。よくある誤解は、malloc返されたメモリをゼロにすることです。実際にはそうではありません。
その結果、メモリ チャンクが「リサイクル」されるという事実により、「値」の情報を持つメモリ チャンクを取得することは十分に可能です。
この脆弱性の例として、tarSolaris 上のプログラムが/etc/passwd. tar根本的な原因は、ディスクからブロックを読み取るために割り当てられたメモリが初期化されておらず、このメモリ チャンクを取得する前に、tarユーティリティが read への OS システム コールを行ったという事実でした/etc/passwd。メモリのリサイクルと、tarのチャンク フラグメントが初期化されていない/etc/passwdため、ログに出力されました。これは、に置き換えることmallocで解決されましたcalloc.
これは、メモリを明示的かつ適切に初期化しない場合のセキュリティへの影響の実際の例です。
はい、メモリを適切に初期化してください。

アップデート:

OSがそのメモリを初期化したプログラム以外のプログラムへのアクセスを制限できるように、プログラムがそのメモリ内容を保護されていると宣言する方法はありませんか?

答えはイエス (最後を参照) とノーです。
ここで間違った見方をしていると思います。より適切な質問は、たとえば、malloc要求に応じてメモリを初期化したり、解放時にメモリをクリアしたりせず、代わりにリサイクルするのはなぜですか?
答えは、API の設計者が明示的に初期化 (またはメモリのクリア) を行わないことを決定したことです。1) メモリの大きなブロックに対してこれを行うと、1) パフォーマンスに影響し、2)必ずしも必要ではない (たとえば、アプリケーションで対処できない場合がある)または、公開されているかどうかを実際に気にするデータを含むアプリケーションのいくつかの部分)。そのため、設計者は、意図せずパフォーマンスに影響を与える可能性があるため、これを行わないことを決定し、これを決定するためにボールをプログラマーに落としました。
では、これを OS にも引き継ぐと、なぜページをクリアするのが OS の責任になるのでしょうか? OS からタイムリーにメモリが渡されることを期待していますが、セキュリティはプログラマ次第です。

Linux でmlockを使用して、機密データがスワップに保存されないようにするために使用できるメカニズムがいくつか提供されていると述べました。

mlock() と mlockall() はそれぞれ、呼び出しプロセスの仮想アドレス空間の一部またはすべてを RAM にロックし、そのメモリがスワップ領域にページングされるのを防ぎます。munlock() と munlockall() は逆の操作を実行し、呼び出しプロセスの仮想アドレス空間の一部またはすべてをそれぞれロック解除します。これにより、指定された仮想アドレス範囲内のページが、カーネル メモリ マネージャーによって必要に応じてもう一度スワップ アウトされる可能性があります。メモリのロックとロック解除はページ単位で行われます。

于 2012-08-23T15:41:05.780 に答える
8

はい、少なくともデータが外部ユーザーに送信される可能性があるシステムでは。

Web サーバー (および iPod でさえも) に対する一連の攻撃があり、他のプロセスからメモリの内容をダンプして、OS のタイプとバージョン、他のアプリのデータ、さらには物事の詳細を取得します。パスワードテーブルのように

于 2012-08-23T15:32:19.263 に答える
4

メモリの領域で機密性の高い作業を実行し、そのバッファをクリアしない可能性は十分にあります。

malloc()将来の呼び出しでは、ヒープへの呼び出しまたはヒープのチェック (ユニット化されたバッファー/配列宣言を介して) を介して、クリアされていない作業を取得できます。(悪意を持って) 検査したり、うっかりコピーしたりする可能性があります。memset()したがって、機密性の高いことをしている場合は、ビニングする前 (または同様の方法)、およびおそらく使用/コピーする前に、そのメモリをクリアするのが理にかなっています。

于 2012-08-23T15:34:53.410 に答える
1

C標準から:

6.7.8 初期化

「自動保存期間を持つオブジェクトが明示的に初期化されていない場合、その値は不確定です。」

不定値は次のように定義されます。

 either an unspecified value or a trap representation.

トラップ表現は次のように定義されます。

特定のオブジェクト表現は、オブジェクト タイプの値を表す必要はありません。オブジェクトの格納された値がそのような表現を持ち、文字型を持たない左辺値式によって読み取られる場合、動作は未定義です。そのような表現が、文字型を持たない左辺値式によってオブジェクトのすべてまたは一部を変更する副作用によって生成される場合、その動作は定義されていません41)。このような表現はトラップ表現と呼ばれます。

このような値にアクセスすると、未定義の動作が発生し、セキュリティ上の脅威が生じる可能性があります。

このホワイト ペーパーでは、初期化されていない変数に対する攻撃から、システムの悪用に使用できることについての洞察を得ることができます。

于 2012-08-23T15:45:39.510 に答える
0

セキュリティが心配な場合、最も安全な方法は、使用するすべての変数を常に初期化することです。バグを見つけるのに役立つ場合もあります。メモリを初期化しないのにはいくつかの正当な理由があるかもしれませんが、ほとんどの場合、すべての変数/メモリを初期化することは良いことです。

于 2012-08-23T15:38:32.757 に答える