ページ 1 / 1
課題です
Posted: 2013年6月01日(土) 11:41
by 勉強なう
以下のプログラムはxinetdから呼び出され、パスワードを知っているユーザのみがメッセージ投稿・表示を行えることを意図して作られています。ただ、このプログラムにはいくつか脆弱性が存在します。発見した脆弱性と攻撃方法、またその修正方法について解説してください。
コード:
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <crypt.h>
6 #define SALT "$1$54lt$"
7 #define HASH SALT"4OOZtZMXwyHi.bwq2QS6U0"
8 char *get_line()
9 {
10 char buf[256];
11 gets(buf);
12 return strdup(buf);
13 }
14 int main()
15 {
16 char *name=NULL, *passwd=NULL, *msg=NULL, buf[256];
17 int trial_num, pass = 0;
18 setbuf(stdout, NULL);
19 for(trial_num = 0; trial_num < 10;trial_num++){
20 printf("USER: ");
21 name = get_line();
22 printf("PASS: ");
23 passwd = get_line();
24 if(strcmp(HASH, crypt(passwd, SALT)) == 0){
25 pass = 1;
26 break;
27 }
28 snprintf(buf, sizeof(buf), "NG(%s)\n", name);
29 printf(buf);
30 }
31 if(pass){
32 printf("MSG: "); msg = get_line();
33 snprintf(buf, sizeof(buf), "echo [%s]%s >> /tmp/memo.log", name, msg);
34 system(buf);
35 system("cat /tmp/memo.log");
36 }
37 return 0;
38 }
このコードの脆弱性として自分が見つけたものは、11行目のバッファーオーバーフローと24行目の初期化されてない変数です。
質問
①上であげた2つの脆弱性はあっているのか?
②また上であげたものがあっているならどのような攻撃方法をされるのか・
③上の2つ以外に脆弱性はありますか?
Re: 課題です
Posted: 2013年6月01日(土) 16:16
by かずま
勉強なう さんが書きました:
③上の2つ以外に脆弱性はありますか?
snprintf の返却値が sizeof(buf)以上の場合をチェックして
いないので、name や msg が指す文字列が 255バイト以下でも
buf には部分文字列しか入らないことがあります。
例えば、/tmp/me というファイルができるかもしれません。
他のユーザが使ったら、すでに /tmp/memo.log があって
書き込みできないでしょう。
strdup が NULL を返す場合もないとは言えません。
Re: 課題です
Posted: 2013年6月01日(土) 19:52
by 勉強なう
その脆弱性によって攻撃されてしまうのでしょうか?
②はわからないでしょうか?
Re: 課題です
Posted: 2013年6月01日(土) 23:23
by へにっくす
勉強なう さんが書きました:その脆弱性によって攻撃されてしまうのでしょうか?
②はわからないでしょうか?
貴方の挙げた2つについて②をいいますと、
それぞれUSER、PASS、MSGが表示された時、256バイト以上入力することが攻撃にあたりますね。
とりあえず私も。。
strdupは、文字列の複製なので、必要無くなったらfreeで解放する必要があります。
_strdup、_wcsdup、_mbsdup - MSDN
それをしていないので、メモリが圧迫されシステムが不安定になるかもしれません。
(要するに何も攻撃されなくとも、通常の運用で落ちる可能性がある)
Re: 課題です
Posted: 2013年6月01日(土) 23:42
by かずま
勉強なう さんが書きました:
その脆弱性によって攻撃されてしまうのでしょうか?
このプログラムが正常に終了しないことも脆弱性の一つでしょう。
攻撃とはどういうことを言っていますか?
システムを落とすこと?
読めないファイルを読みだすこと?
仮にこのプログラムが root の権限で動いていたとしましょう。
このプログラムのパスワードを知っているユーザが MSG: に対して
; shutdown -h now; echo abc
と入力したら
system("echo [user]; shutdown -h now; echo abc >>/tmp/memo.log");
でシステムが落ちます。
ユーザ入力をそのまま system() で実行するのは危険です。
ユーザ入力をそのまま printf() の書式に使うのも脆弱性の一つです。
USER: に対して %s%s%s と入力したら、
printf("NG(%s%s%s)\n"); を実行して、おかしなことになります。
勉強なう さんが書きました:
②はわからないでしょうか?
gets のバッファオーバーフローなら、スタック上にある get_line() の
リターンアドレスを壊してどこに飛んでいくかわからない。
バッファオーバフローで書き込んだところに飛ばせば、
そこに書かれた攻撃者のプログラムを実行できます。
最初の get_line() の gets() で EOF だと、passwd は 未初期化の buf
のコピーを指しますが、こちらは被害は少ないでしょう。
Re: 課題です
Posted: 2013年6月02日(日) 00:52
by 勉強なう
貴方の挙げた2つについて②をいいますと、
それぞれUSER、PASS、MSGが表示された時、256バイト以上入力することが攻撃にあたりますね。
>>24行目の方も256バイト以上の入力でいいんでしょうか?
Re: 課題です
Posted: 2013年6月02日(日) 01:16
by 勉強なう
かずま さんが書きました:勉強なう さんが書きました:
その脆弱性によって攻撃されてしまうのでしょうか?
このプログラムが正常に終了しないことも脆弱性の一つでしょう。
攻撃とはどういうことを言っていますか?
システムを落とすこと?
読めないファイルを読みだすこと?
仮にこのプログラムが root の権限で動いていたとしましょう。
このプログラムのパスワードを知っているユーザが MSG: に対して
; shutdown -h now; echo abc
と入力したら
system("echo [user]; shutdown -h now; echo abc >>/tmp/memo.log");
でシステムが落ちます。
ユーザ入力をそのまま system() で実行するのは危険です。
ユーザ入力をそのまま printf() の書式に使うのも脆弱性の一つです。
USER: に対して %s%s%s と入力したら、
printf("NG(%s%s%s)\n"); を実行して、おかしなことになります。
勉強なう さんが書きました:
②はわからないでしょうか?
gets のバッファオーバーフローなら、スタック上にある get_line() の
リターンアドレスを壊してどこに飛んでいくかわからない。
バッファオーバフローで書き込んだところに飛ばせば、
そこに書かれた攻撃者のプログラムを実行できます。
最初の get_line() の gets() で EOF だと、passwd は 未初期化の buf
のコピーを指しますが、こちらは被害は少ないでしょう。
③のことで
すごい知識ですね!! 感激しました。
自分はそんなスキルないので全部理解できないので、
もう少しまとめてもらえないでしょうか?
「どこの脆弱性をどのようにコードを書き換えればいいのか?」
面倒なこと言ってすいません。
Re: 課題です
Posted: 2013年6月02日(日) 10:15
by へにっくす
勉強なう さんが書きました:貴方の挙げた2つについて②をいいますと、
それぞれUSER、PASS、MSGが表示された時、256バイト以上入力することが攻撃にあたりますね。
>>24行目の方も256バイト以上の入力でいいんでしょうか?
初期化していないとはどの変数ですかね。
コード:
24 if(strcmp(HASH, crypt(passwd, SALT)) == 0){
HASH、SALTは定数ですしpasswdはその前のget_line()でセットしています。
なので24行目は「変数が初期化していない」とは言えないと思います。
(かずまさんがpasswdについて述べられていますが、結局はget_line関数の中の話ですので)
修正方法はまず自分で考えてみてください(質問内容には書かれていないので)。
たとえばget_line関数で使用しているgetsはVC++ならgets_sに置き換えるとかね(もちろんこれだけではだめですよ?)。
Re: 課題です
Posted: 2013年6月02日(日) 10:49
by 勉強なう
へにっくす さんが書きました:勉強なう さんが書きました:貴方の挙げた2つについて②をいいますと、
それぞれUSER、PASS、MSGが表示された時、256バイト以上入力することが攻撃にあたりますね。
>>24行目の方も256バイト以上の入力でいいんでしょうか?
初期化していないとはどの変数ですかね。
コード:
24 if(strcmp(HASH, crypt(passwd, SALT)) == 0){
HASH、SALTは定数ですしpasswdはその前のget_line()でセットしています。
なので24行目は「変数が初期化していない」とは言えないと思います。
(かずまさんがpasswdについて述べられていますが、結局はget_line関数の中の話ですので)
修正方法はまず自分で考えてみてください(質問内容には書かれていないので)。
たとえばget_line関数で使用しているgetsはVC++ならgets_sに置き換えるとかね(もちろんこれだけではだめですよ?)。
HASHとSALTは変数じゃないんでしょうか?
get_lineについて調べましたが、自分ではわかりそうにないので、できればどこをどのように修正するか教えてもらえないでしょうか?
Re: 課題です
Posted: 2013年6月02日(日) 11:24
by へにっくす
勉強なう さんが書きました:HASHとSALTは変数じゃないんでしょうか?
6行目と7行目で#defineで定義してますよね?
こういうのは変数でなく「定数」です。
C言語のdefineについて
コンパイルするときに#defineで定義したものは置換しますので、実際にはこう書いているのと同じです。
コード:
24 if(strcmp("$1$54lt$""4OOZtZMXwyHi.bwq2QS6U0", crypt(passwd, "$1$54lt$")) == 0){
勉強なう さんが書きました:get_lineについて調べましたが、自分ではわかりそうにないので、できればどこをどのように修正するか教えてもらえないでしょうか?
こんな感じになるかな(あくまでも一例です)
コード:
char *get_line()
{
char buf[256]={0}; // 初期化を忘れずに(初期化されてないと質問内容にあったのでここぐらいは答えてほしかったなあ^^;)
gets_s(buf, sizeof(buf) - 1); // これで256文字以上入力すると、CRTが無効な引数を検出する。
return strdup(buf); // 入力していない場合は空文字列の複製が返る
}
あとはCRTが無効な引数を検出した場合に呼び出す関数を設定します。
_set_invalid_parameter_handler - MSDN
Re: 課題です
Posted: 2013年6月02日(日) 12:27
by 勉強なう
へにっくす さんが書きました:勉強なう さんが書きました:HASHとSALTは変数じゃないんでしょうか?
6行目と7行目で#defineで定義してますよね?
こういうのは変数でなく「定数」です。
C言語のdefineについて
コンパイルするときに#defineで定義したものは置換しますので、実際にはこう書いているのと同じです。
コード:
24 if(strcmp("$1$54lt$""4OOZtZMXwyHi.bwq2QS6U0", crypt(passwd, "$1$54lt$")) == 0){
勉強なう さんが書きました:get_lineについて調べましたが、自分ではわかりそうにないので、できればどこをどのように修正するか教えてもらえないでしょうか?
こんな感じになるかな(あくまでも一例です)
コード:
char *get_line()
{
char buf[256]={0}; // 初期化を忘れずに(初期化されてないと質問内容にあったのでここぐらいは答えてほしかったなあ^^;)
gets_s(buf, sizeof(buf) - 1); // これで256文字以上入力すると、CRTが無効な引数を検出する。
return strdup(buf); // 入力していない場合は空文字列の複製が返る
}
あとはCRTが無効な引数を検出した場合に呼び出す関数を設定します。
_set_invalid_parameter_handler - MSDN
ありがとうございました。
11行目のバッファオーバーフローを防ぐためにはそのような方法もあるのですね。
①fgets関数などでもふせげるでしょうか?
②ということはこのコードの脆弱性は11行目のバッファオーバーフローの脆弱性だけということですか?
ほかにもあればその部分と修正方法、どのように攻撃されてしまうのか教えてくださいorz
Re: 課題です
Posted: 2013年6月02日(日) 14:22
by へにっくす
勉強なう さんが書きました:①fgets関数などでもふせげるでしょうか?
②ということはこのコードの脆弱性は11行目のバッファオーバーフローの脆弱性だけということですか?
ほかにもあればその部分と修正方法、どのように攻撃されてしまうのか教えてくださいorz
①fgetsでは代わりになりません。
コード:
fgets(buf, sizeof(buf) - 1,stdin);
この場合は、256文字以上入力した場合エラーにはならず、255文字とりだして戻ります。切り捨てされた文字は次の入力に行きますので意図した動きにはなりませんよ。
こちらで実験してみるとUSERで256文字以上入力すると、256文字からの入力はPASSに行ってしまいます。
②えーとかずまさんの指摘みてますかね? (^^;) あとはかずまさんにお任せします。
Re: 課題です
Posted: 2013年6月02日(日) 18:27
by softya(ソフト屋)
セキュリティ・キャンプ2013のソフトウェアセキュリティクラスの課題と判明しましたので、一時的に明確になるまで回答を停止してもらってよいでしょうか。
「課題( ̄◇ ̄;) • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=13168#p105360
とりあえず、課題締め切りの2013年6月10日(月)17:00(必着)まで保留とさせて頂きます。
Re: 課題です
Posted: 2013年6月02日(日) 19:09
by 勉強なう
ありがとうございました
Re: 課題です
Posted: 2013年6月02日(日) 19:09
by 勉強なう
ありがとうございました