developer's diary

最近はc#のエントリが多いです

平成26年度 春期 SC試験 午後1 問1のC++の問題を復習

本日情報セキュリティスペシャリスト試験(SC)を受けました。

問題はコチラからPDFがダウンロードできます。

午後1にWebアプリケーションの脆弱性問題があって理解不足を感じたのでブログにまとめてみます。

問題の内容は以下の流れです。

  • Javaで作られた画像投稿システムを作る。
  • 画像の圧縮はC++をJNIで利用する。
  • C++で作られた「ピクセル変換プログラム」という名のプログラムのソースコードレビューを主任がする

ソースコードには2つの問題点があり、おそらく片方はBOFだろうけどももう片方の問題点の書き方が分かりませんでした。 問題点の内容としては、int型の変数にintじゃ収まらない値を設定する可能性があるという所。 しかし「これが正解だ!」という正解が思いつかず、2つの問題点両方にバッファオーバーフローってかいちゃったので、帰宅してから復習をかねて実際にコンパイルや実行やら手を使って動かしてみます。

ざっくりと確認したい部分のコードを書いてみる。

#include<stdio.h>

//0x7fffffffは2147483647(4バイト符号あり整数の最大値)
const kMaxInteger = 0x7fffffff;

typedef struct {
  int cols;
  int rows;
} vlibMat;

int main() {

  vlibMat vm = {0,0};

  vm.cols = kMaxInteger;
  vm.rows = kMaxInteger;

  resize_fileZ(vm);

  return 0;
}

int resize_fileZ(vlibMat fhBuf)
{
  int bytesOfRow, bytesOfBuff;
  bytesOfRow = 256;
  bytesOfBuff = bytesOfRow * fhBuf.rows;

  printf("bytesOfBuff: %d\n", bytesOfBuff);
  printf("kMaxInteger: %d\n", kMaxInteger);
  return 0;
}

何が起こるか。

int型(4バイト)の最大値(2147483647) * 256を変数bytesOfBuffに設定してprintf。 すると結果はマイナスに!

[root@ip-10-0-0-157 ~]# vim test.c
[root@ip-10-0-0-157 ~]# gcc test.c
[root@ip-10-0-0-157 ~]# ./a.out 
bytesOfBuff: -256
kMaxInteger: 2147483647

こういう脆弱性を 整数オーバーフローというそうです。

第10章 著名な脆弱性対策 - 整数オーバーフロー攻撃対策

どうやってチェックするかが設問に。

試験問題に、以下の代入の前にアサーションを入れるという問題があります。

//この部分に
//if ( [1] < [2] ) 
//   throw out_of_range("Image too large"); 
//を入れる
bytesOfBuff = bytesOfRow * fhBuf.rows;

問題

[1]と[2]に入れる適切な式又は変数を答えよ。なお、[1]と[2]のどちらか一方は、kMaxIntegerを含むこと。

if( kMaxInteger < bytesOfRow * fhBuf.rows )だとどうなる?

以下のロジックで動かしてみる。

  if( kMaxInteger < bytesOfRow * fhBuf.rows ){
    printf("out_of_range too large\n");
  } else {
    printf("OK\n");
  }

  bytesOfBuff = bytesOfRow * fhBuf.rows;
[root@ip-10-0-0-157 ~]# ./a.out 
OK

想定しているチェックにはなりませんでした。どうやらint*intの結果が既に整数オーバーフローした状態でした。

どうしたらよいものか。

考えてみた苦肉の策。

  if( kMaxInteger / bytesOfRow < fhBuf.rows ){
    printf("out_of_range too large\n");
  } else {
    printf("OK\n");
  }

こんな感じでいいのだろうか。

参考