.NET 開発基盤部会 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

  • C/C++のバッファ・オーバーフロー(BOF)系の対策
  • 言語使用として、全体的にBOF系に弱い。
    • 終端ナル(NULL)文字を忘れると、終端が認識されずBOFに繋がる。
    • 以下の様に、BOFを引き起こす可能性がある引数チェックされない関数が多い。
  • 以下の2つがある
  • スタックベースのバッファ・オーバーフロー
    • 基本こちら
    • 呼び出し元に戻るアドレス部分を書き換え攻撃コードに誘導する。
  • ヒープベースのバッファ・オーバーフロー
    スタックベースと比べ、攻撃が成功し難い。

詳細

データ実行防止機能(DEP)

  • データ領域からコードを実行することを防止する。
    • Microsoft Windowsに搭載されているセキュリティ機能。
    • ハードウェアDEP、ソフトウェアDEPがある。
  • DEP対策として、return-to-libc攻撃がある。

コンパイラに依る対策

開発環境やコンパイラによってはサポートされないことがある。

SSP(Stack Smashing Protection)

  • スタックフレーム内のebpレジスタとローカル変数の間に
    canary(カナリア・コード)を配置することで、スタック・オーバーフローの検知を行う。
  • 元となった実装の名前からStackGuard?ProPolice?とも呼ばれることがある。

ASLR(Address Space Layout Randomization)

  • 各種領域をメモリ上にランダムに配置。
  • コレにより、return-to-libc対策になる。

PIE(Position Independent Executable)

ASLRに加え、text領域のランダム化も行う(Full-ASLRとも言う)。

AF(Automatic Fortification)

脆弱性の原因となるような関数をコンパイル時に
別の安全性の高い同じ機能を持つ関数へと置換する。

BOFを起こす関数

以下の様に、BOFを引き起こす可能性がある引数チェックされない関数が多い。

関数一覧

#関数代替案/対策用法備考
1char *gets(char *s)
標準入力から一行を取り込む。
char *fgets(char *s, int n, FILE *stream);fgets(dst , sizeof(dst) , stdin);gets と異なり
・引数に最大読み込み文字数を指定する。
・改行文字も 1文字として数える。
・実際読むのはn-1で最後は終端ナル(NULL)文字になる。
 ・終端記号は、末尾の改行を置換ではなく改行の後ろに付与
 ・最大文字数を超えた場合でも終端ナル(NULL)文字を保証
2char *strcpy(char *dst, const char *src);
src文字列をdst文字列バッファに'\0' までコピー
void *memset(void *buf, int ch, size_t n);
char *strncpy(char *dst, const char *src, size_t n);
memset(dst, 0 , sizeof(dst));
-> strncpy(dst, src, sizeof(dst) - 1);
・コピーされる文字の長さは、src長とnのいずれか小さい方。
・src長がnより短い場合、終端ナル(NULL)文字を保証
3char *strcat(char *dst, const char *src);
src文字列をdst文字列バッファに'\0' まで連結
char *strncat(char *dst, const char *src, size_t n);strncat(dst, src, sizeof(dst) - strlen(dst) - 1)・文字列連結される文字の長さは、src長とnのいずれか小さい方。
・src長がnより短い場合、終端ナル(NULL)文字を保証
4int sprintf(char *dst, const char *format, ...);
可変個引数をstring.Format()的に処理しdst文字列バッファに格納。
sprintf(dst, ”%.{B}s”, data){B} = 書式指定子の精度(最大文字数)
= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)
5int snprintf(char *dst, size_t n, const char *format, ...);snprintf(dst, sizeof(dst), ”%s”, data)動作としては、fgets()に近く、実際読むのはn-1で最後は終端ナル(NULL)文字になる。
6int scanf(const char *format, ...);
標準入力から空白、タブ、改行で分割された文字列を読みstring.Format()的に処理し格納可変個引数に格納。
scanf(”%.{B}s”, dst){B} = 書式指定子の精度(最大文字数)
= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)
7int sscanf(char *src, const char *format, ...);
src文字列をstring.Format()的に処理し格納可変個引数に格納。
sscanf(src, ”%.{B}s”, dst){B} = 書式指定子の精度(最大文字数)
= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)
8int fscanf(FILE *fp, const char *format, ...);
ストリームをstring.Format()的に処理し格納可変個引数に格納。
fscanf(fp, ”%.{B}s”, dst){B} = 書式指定子の精度(最大文字数)
= dstの要素数 - 書式指定子以外の文字数 - 1(終端ナル(NULL)文字)
9getchar();, fgetc(fp);, getc(fp);
入力から一文字を取り込む。
使用する際にバッファ境界チェックを行う。

パターン

  • 何れもdstのサイズを調査して長さを指定する。
    • 基本的には、n = dstのサイズ - 1(終端ナル(NULL)文字用)
    • 指定先は、size_tか、書式指定子の精度(書式指定子の場合、更に書式指定子以外の文字列数を引く)になる。
    • 関数によっては(fgets、snprintf)、入力を自動的にn-1するものもあり、「- 1」が不要。
  • va_listを使用する関数も基本的対応は同じ。
    • vscanf → scanf
    • vsscanf → sscanf
    • vfscanf → fscanf
    • vsprintf → sprintf

パラメータ検証

  • Libsafe
    • BOFをチェックするコードを読み込ませた後に
    • 本来呼び出されるライブラリの内容を呼び出す。
    • チェック関数挿入、コンパイル不要

まとめ

OS

データ実行防止機能(DEP)

コンパイラに依る対策

プログラミング

  • BOFを起こす関数を適切に利用する。
    gets、strcpy、strcat等を使用しない、_sを使用。
  • バッファ・コピー処理をLoopなどで書かない。

参考

各種領域

スタック領域

ヒープ領域

プログラム領域

  • スタックは、下から上に積み上がる
    (下位アドレスが下に書いてある場合)
  • 上から順に、サブルーチンの
    • ESP(先頭)
    • バッファ
    • ローカル変数
    • canary
    • EBP(底)
    • リターン・アドレス

となる。

その他

  • text領域
    プログラムおよび定数
  • data領域
    初期値をもつ静的変数
  • bss領域
    初期値をもたない静的変数

Wikipedia


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-09-22 (火) 22:55:09 (39d)