SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

伏石ちゃんは意図に反したい

バッファオーバーフローってどんな攻撃? C言語で見てみよう【伏石ちゃんは意図に反したい】

FILE 0x07 バッファオーバーフロー

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード サンプルコード (6.4 KB)

バッファオーバーフロー攻撃に脆弱なコードとは

充希
ところで、バッファオーバーフローの脆弱性って、どうやったら生まれるんでしょうか?
先生
今時のプログラミング言語だと例示が難しいんだよなぁ。バッファオーバーフローを起こさないよう色々安全対策が行なわれているからな
充希
そこを何とか
先生
まあ、分かりやすいのは、約100年前(※)から使われている、古き良きC言語のコードだな。今でも組み込みソフトウェアの開発やデバイスドライバーの開発では、古典的なC言語が使われることもある。この例を見てくれ

※この作品は2070年が舞台という設定です

#include <stdio.h>
#include <string.h>

int main() {
    char password[10] = ""; // パスワード入力バッファ。初期値は「」
    char result[10] = "NG"; // 判定結果格納用文字列。初期値は「NG」

    printf("Input password: "); //「Input password: 」と画面に出力する 
    gets(password); // 入力内容を一行読み取り、変数passwordにセットする

    // もし、変数passwordにセットされた文字列が「1234」なら
    if (strcmp(password, "1234") == 0) {
        // 判定結果「OK」を変数resultにセットする
        strcpy(result, "OK");
    }

    // もし、判定結果が「OK」なら
    if (strcmp(result, "OK") == 0) {
        printf("Login OK"); // 「Login OK」と画面に出力する 
    } else { // そうでなければ、
        printf("Error"); // 「Error」と画面に出力する
    }

    printf("\n"); // 画面出力を改行する

    return 0;
}
先生
このプログラムは、正しいパスワード『1234』を入力したら、『Login OK』と出力される単純なプログラムだ
充希
はい
先生
実行してみると、こんなふうになる
$ gcc sample1.c -o sample1
$ ./sample1
Input password: 1234
Login OK
先生
そして、間違ったパスワードを入力したら『Error』と出力される
$ ./sample1
Input password: 12345
Error
先生
では、『1234567890OK』と入力したらどうなるだろう?
充希
『Error』では
先生
やってみろ
$ ./sample1
Input password: 1234567890OK
Login OK
充希
あれ? 何で
先生
これがバッファオーバーフローだ。OKコンピューター、解説しろ
コンピューター
はい

 再びソースコードを見てみましょう。

    char password[10] = ""; // パスワード入力バッファ。初期値は「」
    char result[10] = "NG"; // 判定結果格納用文字列。初期値は「NG」

 ここで、半角10文字を格納できる入れ物を2個用意しています。一つはpassword、もう一つはresultです。

 そして、

    gets(password); // 入力内容を一行読み取り、変数passwordにセットする

 ここで、入力内容を読み取って、passwordにセットしています。

 しかし、passwordに入る文字数は10文字です。もしここで入力内容が10文字を越えてしまうとどうなるでしょうか?

 先ほどの例のように「1234567890OK」と入力すると、passwordには10文字分の「1234567890」までしか入りません。そして、入りきらなかった分は、隣のresultにはみ出してしまうのです。その結果、resultが「OK」と書き換えられてしまいます。

 パスワードが間違っているにもかかわらず、判定結果を格納するresultが「OK」に書き換わってしまったため、

    // もし、判定結果が「OK」なら
    if (strcmp(result, "OK") == 0) {
        printf("Login OK"); // 「Login OK」と画面に出力する 

 この条件分岐において、「Login OK」と出力されてしまうというわけです。

 なお、gets()は、バッファオーバーフローの脆弱性を引き起こす代表例であり、バッファオーバーフローを解説するための十八番となっています。使いやすいことから初心者向けプログラミング演習などではよく使用される関数ですが、このようにログインを回避するなど危険な動作を起こしうるため、本番の開発では使用してはいけません。代わりに、バッファのサイズを指定できるfgets()を使用するのが定番です。それにより、指定したサイズを超えて書き込まれることを防げます。

 しかし、gets()だけがバッファオーバーフローの原因というわけではありません。例えば、文字列をコピーするstrcpy()関数もバッファのサイズを指定する引数がないことに注目してください。strcpy()関数は配列の長さではなくヌル文字を文字列の終端であると認識するため、正しくヌル終端されていない文字列が引数に渡されると、文字列の長さを誤認識してしまいます。想定より長い文字列がコピー先に書き込まれることになると、gets()と同様にバッファオーバーフローが発生します。対策としては、代わりにバッファのサイズを指定できるmemcpy()を用いることができます。

先生
ということだ
充希
つまり、これと同じようなバグが遺伝子スキャナのデバイスドライバーにもあるんですね
先生
恐らくな
充希
じゃあ、うまく遺伝子を組み換えて、ハックすれば、遺伝子認証がフリーパスになるってことですか!?
先生
あ、現実的に、一つのシステムを攻撃するためにそんな手間をかける奴なんかいないだろうが、可能性としては考えられるな。それよりは、お前のように偶然バグらせる方が可能性が高いだろう
充希
……はい

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
伏石ちゃんは意図に反したい連載記事一覧

もっと読む

この記事の著者

井二 かける(イブタ カケル)

 情報処理安全確保支援士、プログラマー、作家。「物語の力でIT・セキュリティをもっと面白く」をモットーに、作家活動、セキュリティ啓発活動を行う。主な作品はアニメ「こうしす!」、小説「こうしす!社内SE祝園アカネの情報セキュリティ事件簿」(翔泳社)、マンガ「伏石ちゃんは意図に反したい ~ハッキングから始まる高校生活~」(京姫鉄道出版)など。 Twitter:@k_ibuta@kyoki_railway

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山口 しずか(ヤマグチ シズカ)

 やりたいことはなんでもやる精神で急成長中の漫画家。2019年よりマンガアプリにて商業連載デビュー。連載の傍ら企業のPR漫画や漫画動画など媒体・ジャンルにとらわれず時代に合わせた漫画を制作中。趣味はお酒と旅行。 Twitter:@shizuckey

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/15842 2022/05/02 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング