見出し画像

【セキスペ】H28年秋期 午後Ⅰ BOF問題について考える

セキスペこと、情報セキュリティスペシャリスト(現:安全確保支援士試験)の問題を解いていると興味深い問題を見つけたのでメモ

万が一、勉強中の方がこのページに行き着いた場合も考えて、ある程度しっかりまとめてみます。

どんな問題?

https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2016h28_2/2016h28a_sc_pm1_qs.pdf
こちらより抜粋

画像4


画像1

この問題に対して、

(1) 下線部②について、利用者認証を回避される引数はどれか
(2) 実際にBOF(バッファオーバーフロー)が発生するのはどの行か
(3) どのように改修するのが適切か

という設問に答えていく。

下準備

ここでは一先ず、「どんなユーザIDもパスワードは必ず"PASS"」ということにする。(とんでもないシステムだが)

// ユーザIDからパスワードを取得する
void getPass(char *pass, char *uid)
{
   strcpy(pass, "PASS");
}

分かりやすい様に、メイン処理にデバッグモニタ的な出力を追加する。

int main(int argc, char **argv)
{
   static char *uid;
   static char *pass;
   
   uid = new char[UID_SIZE + 1];
   pass = new char[PASS_SIZE + 1];
   
   cout << "入力されたID: " << argv[1] << endl;
   cout << "入力されたPW: " << argv[2] << endl;
   cout << "----------------" << endl;
   getPass(pass, argv[1]);
   strcpy(uid, argv[1]);
   cout << "ユーザID: " << uid << endl;
   cout << "パスワード: " << pass << endl; // ここが必ず PASS になるはず・・・
   
   if (strlen(pass) == 0 || strcmp(argv[2], pass) != 0) {
       cout << "認証失敗" << endl;
   } else {
       cout << "認証成功" << endl;
   }

}

プログラムが意図した動作になっていることを確認

画像3

以降はこのプログラムを利用する。

利用者認証を回避される引数はどれか

この場合、利用者認証を回避するためには

if (strlen(pass) == 0 || strcmp(argv[2], pass) != 0)

を満たす必要がある。
となると、何らかの手法で変数 pass の中身を書き換える必要がある。

この際に利用されるのが「「バッファオーバーフロー」」である。

C / C++言語は通常、変数の内容をヒープ領域へ格納する。
実際にこのプログラムの実行時のヒープ領域を確認する。

画像6

uid       ⇔  0x867A68
pass     ⇔  0x867A80

となっている。
ココで大事なポイントが

①プログラム内でnew宣言された変数は必ずヒープ領域内に存在している
②変数 uid の取りうる領域を超えたデータを書き込むことで
   変数 pass の領域へ侵入することが出来る。

という2点である。

上記の②をBOF攻撃に利用するため、
第一引数から変数 uid へ値をコピーするステップを利用する。

0x867A68 から 0x867A80 までは24バイト離れているため、入力値は

( 適当な 24 バイト分の文字 ) + ( 書き換えたい内容 ) 

とすると、変数 pass の領域へ侵入することが出来る。

画像5

メモリを確認すると領域が埋められていることが分かる。
※アドレスの差は、割り当てられるヒープ領域がプログラム実行毎に変化するため。

画像7

よって、正解は「第一引数の末尾」と「第二引数」が一致している

第一引数: 011(繰返し) 1111111101
第二引数: 11111101

が正解である。

BOF(バッファオーバーフロー)が発生するのはどの行か

上の項目でほぼ答えを出してしまったが、23行目の

strcpy(uid, argv[1]);

にてBOFが発生している。
ここで留意すべきなのが15行目、すなわち不正なデータが入力された段階ではBOFは発生していないということである。

つまり、不正なデータに対して何の対処もされていない場合にのみBOFは成立する。ということが言える。

次の設問ではその対処法についての理解を問われる。

どう改修するのが適切か

設問にて提示されている選択肢は以下の5点である

画像7

正攻法としては、
入力値が、変数 uid が確保している領域 new char[UID_SIZE + 1] を超えてしまうとBOFが成立する事を踏まえて、
Ⅰ. ア、エは入力値が丸々ヒープ領域内にコピーされてしまう為、確保している領域を超える可能性がある。
Ⅱ. オは、確保する領域を増やしてもそれを上回るデータ入力があれば意味をなさない。
ということから、入力値の制御として適切であるイ、オが正解となる。

BOFが成立する条件を知っているかどうかではあるが、
知らなくてもある程度絞り込める方法があるのでご紹介。

最初の問題文中の

"利用者IDとパスワード"は、いずれも半角英数字、最小6文字最大8文字の文字列と仕様で定められている。

に記載されていように、ID、PWは8文字以上である場合は無条件で不正な値となる。
つまり、8文字( プログラム上は終端文字を加えた9文字 )以上の値はコピーする必要がなく、切り捨てが発生する方が仕様上正しいと言える。

おまけ

プログラムを実行する度にMcAfeeが絡んできた卍
お試ししたい時はアンチウィルスソフトを切ったほうが良いかも

画像8


この記事が気に入ったらサポートをしてみませんか?