「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfrastructure.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>SC:システム開発]] *目次 [#jbfad9b0] #contents *概要 [#ya4d6d14] -C/C++のバッファ・オーバーフロー(BOF)系の対策 -言語使用として、全体的にBOF系に弱い。 --終端ナル(NULL)文字を忘れると、終端が認識されずBOFに繋がる。 --以下の様に、BOFを引き起こす可能性がある引数チェックされない関数が多い。 -以下の2つがある --スタックベースのバッファ・オーバーフロー ---基本こちら ---呼び出し元に戻るアドレス部分を書き換え攻撃コードに誘導する。 --ヒープベースのバッファ・オーバーフロー~ スタックベースと比べ、攻撃が成功し難い。 *詳細 [#ve4ce9d9] **データ実行防止機能(DEP) [#n726a699] -データ領域からコードを実行することを防止する。 --Microsoft Windowsに搭載されているセキュリティ機能。 --ハードウェアDEP、ソフトウェアDEPがある。 -DEP対策として、return-to-libc攻撃がある。 **コンパイラに依る対策 [#vb4ab419] 開発環境やコンパイラによってはサポートされないことがある。 ***SSP(Stack Smashing Protection) [#kd81c5b2] -スタックフレーム内のebpレジスタとローカル変数の間に~ canary(カナリア・コード)を配置することで、スタック・オーバーフローの検知を行う。 -元となった実装の名前からStackGuardやProPoliceとも呼ばれることがある。 ***ASLR(Address Space Layout Randomization) [#ca2c02b4] -[[各種領域>#l983b52e]]をメモリ上にランダムに配置。 -コレにより、return-to-libc対策になる。 ***PIE(Position Independent Executable) [#ud5d6ff9] ASLRに加え、text領域のランダム化も行う(Full-ASLRとも言う)。 ***AF(Automatic Fortification) [#b027012c] 脆弱性の原因となるような関数をコンパイル時に~ 別の安全性の高い同じ機能を持つ関数へと置換する。 **BOFを起こす関数 [#u5e6e8fb] 以下の様に、BOFを引き起こす可能性がある引数チェックされない関数が多い。 ***関数一覧 [#s9c7a7ad] |#|関数|代替案/対策|用法|備考|h |1|char *gets(char *s)&br;標準入力から一行を取り込む。|char *fgets(char *s, int n, FILE *stream);|fgets(dst , sizeof(dst) , stdin);|gets と異なり&br;・引数に最大読み込み文字数を指定する。&br;・改行文字も 1文字として数える。&br;・実際読むのはn-1で最後は終端ナル(NULL)文字になる。&br; ・終端記号は、末尾の改行を置換ではなく改行の後ろに付与&br; ・最大文字数を超えた場合でも終端ナル(NULL)文字を保証| |2|char *strcpy(char *dst, const char *src);&br;src文字列をdst文字列バッファに'\0' までコピー|void *memset(void *buf, int ch, size_t n);&br;char *strncpy(char *dst, const char *src, size_t n);|memset(dst, 0 , sizeof(dst));&br;-> strncpy(dst, src, sizeof(dst) - 1);|・コピーされる文字の長さは、src長とnのいずれか小さい方。&br;・src長がnより短い場合、終端ナル(NULL)文字を保証| |3|char *strcat(char *dst, const char *src);&br;src文字列をdst文字列バッファに'\0' まで連結|char *strncat(char *dst, const char *src, size_t n);|strncat(dst, src, sizeof(dst) - strlen(dst) - 1)|・文字列連結される文字の長さは、src長とnのいずれか小さい方。&br;・src長がnより短い場合、終端ナル(NULL)文字を保証| |4|int sprintf(char *dst, const char *format, ...);&br;可変個引数をstring.Format()的に処理しdst文字列バッファに格納。|-|sprintf(dst, ”%.{B}s”, data)|{B} = 書式指定子の精度(最大文字数)&br;= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)| |5|~|int snprintf(char *dst, size_t n, const char *format, ...);|snprintf(dst, sizeof(dst), ”%s”, data)|動作としては、fgets()に近く、実際読むのはn-1で最後は終端ナル(NULL)文字になる。| |6|int scanf(const char *format, ...);&br;標準入力から空白、タブ、改行で分割された文字列を読みstring.Format()的に処理し格納可変個引数に格納。|-|scanf(”%.{B}s”, dst)|{B} = 書式指定子の精度(最大文字数)&br;= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)| |7|int sscanf(char *src, const char *format, ...);&br;src文字列をstring.Format()的に処理し格納可変個引数に格納。|-|sscanf(src, ”%.{B}s”, dst)|{B} = 書式指定子の精度(最大文字数)&br;= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)| |8|int fscanf(FILE *fp, const char *format, ...);&br;ストリームをstring.Format()的に処理し格納可変個引数に格納。|-|fscanf(fp, ”%.{B}s”, dst)|{B} = 書式指定子の精度(最大文字数)&br;= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)| |9|getchar();, fgetc(fp);, getc(fp);&br;入力から一文字を取り込む。|-|-|使用する際にバッファ境界チェックを行う。| ***パターン [#m733e03a] -何れもdstのサイズを調査して長さを指定する。 --基本的には、n = dstのサイズ - 1(終端ナル(NULL)文字用) --指定先は、size_tか、書式指定子の精度(書式指定子の場合、更に書式指定子以外の文字列数を引く)になる。 --関数によっては(fgets、snprintf)、入力を自動的にn-1するものもあり、「- 1」が不要。 -va_listを使用する関数も基本的対応は同じ。 --vscanf → scanf --vsscanf → sscanf --vfscanf → fscanf --vsprintf → sprintf ***パラメータ検証 [#z0f8b9e7] -[[CRTセキュリティ強化>https://techinfoofmicrosofttech.osscons.jp/index.php?VC%2B%2B%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%83%E3%83%97#t697e5f8]] -Libsafe --BOFをチェックするコードを読み込ませた後に --本来呼び出されるライブラリの内容を呼び出す。 --チェック関数挿入、コンパイル不要 **まとめ [#se2ae8df] ***OS [#h8f8d15a] [[データ実行防止機能(DEP)>#n726a699]] ***[[コンパイラに依る対策>#vb4ab419]] [#z493d2c9] -[[StackGuard、canary(カナリア・コード)>#kd81c5b2]] -メモリ配置のランダム化([[ASLR>#ca2c02b4]]、[[PIE>#ud5d6ff9]]) ***プログラミング [#c56c3ab0] -[[BOFを起こす関数>#u5e6e8fb]]を適切に利用する。~ gets、strcpy、strcat等を使用しない、_sを使用。 -バッファ・コピー処理をLoopなどで書かない。 *参考 [#q547460e] -バッファオーバーフローへの対策技術入門~ https://www.saitolab.org/infra_kaisetsu/ **各種領域 [#l983b52e] ***スタック領域 [#mda2bdb9] ***[[スタック領域>https://techinfoofmicrosofttech.osscons.jp/index.php?%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%81%AE%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF]] [#mda2bdb9] ***ヒープ領域 [#y91fe190] ***[[ヒープ領域>https://techinfoofmicrosofttech.osscons.jp/index.php?%E3%83%92%E3%83%BC%E3%83%97]] [#y91fe190] ***プログラム領域 [#ca902f8f] -スタックは、下から上に積み上がる~ (下位アドレスが下に書いてある場合) -上から順に、サブルーチンの --ESP(先頭) --バッファ --ローカル変数 --canary --EBP(底) --リターン・アドレス >となる。 ***その他 [#m3127a87] -text領域~ プログラムおよび定数 -data領域~ 初期値をもつ静的変数 -bss領域~ 初期値をもたない静的変数 **Wikipedia [#a5126966] -バッファオーバーラン~ https://ja.wikipedia.org/wiki/%E3%83%90%E3%83%83%E3%83%95%E3%82%A1%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%A9%E3%83%B3 -データ実行防止~ https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E5%AE%9F%E8%A1%8C%E9%98%B2%E6%AD%A2 -Return-to-libc攻撃~ https://ja.wikipedia.org/wiki/Return-to-libc%E6%94%BB%E6%92%83