バッファオーバーフロー攻撃、クロスサイト・スクリプィング攻撃

情報学類 分散システム					2008年02月19日

                                       筑波大学システム情報工学研究科
                                       コンピュータサイエンス専攻, 電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2007/2008-02-19
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/

■連絡事項

■セキュリティ

セキュリティとは、安全や機密を保持すること。

◆分散システムでのセキュリティの難しさ

集中システムで使える、次のような技術が使えない 分散システムの弱点 分散システムでは、集中システムよりも高いセキュリティを提供できる可能性がある

◆対策

動くプログラム(2年生レベル)と安全なプログラム(3年生レベル)

■cookie

協調して動作しているプログラムの間で、ある一連の作業を識別するための数 を意味する。

RPCでは、途中経過を表すのに利用する。 NFS では、readdir() で用いられている。

◆WWW cookieの利用

WWW(World Wide Web)では、1回のデータ転送ごとに通信路が切断される ので、通常はWWWのブラウザ(クライアント)とWWWサーバの間では、途 中経過を保持することができない。

途中経過を保存したい時:

WWWで途中経過を保存するためには、cookie が使われる。

サーバは、その情報を利用して、適切なページ(たとえば前回最後に訪れたペー ジ)を表示させるようにすることができる。

◆WWW cookieのプロトコル

RFC2965より。 以下の User Agent は、WWW ブラウザと思ってよい。
4.  EXAMPLES

4.1  Example 1

   Most detail of request and response headers has been omitted.  Assume
   the user agent has no stored cookies.

      1. User Agent -> Server

        POST /acme/login HTTP/1.1
        [form data]

        User identifies self via a form.

      2. Server -> User Agent

        HTTP/1.1 200 OK
        Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

        Cookie reflects user's identity.

      3. User Agent -> Server

        POST /acme/pickitem HTTP/1.1
        Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
        [form data]

        User selects an item for "shopping basket".

      4. Server -> User Agent

        HTTP/1.1 200 OK
        Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
                Path="/acme"

        Shopping basket contains an item.

      5. User Agent -> Server

        POST /acme/shipping HTTP/1.1
        Cookie: $Version="1";
                Customer="WILE_E_COYOTE"; $Path="/acme";
                Part_Number="Rocket_Launcher_0001"; $Path="/acme"
        [form data]

        User selects shipping method from form.

      6. Server -> User Agent

        HTTP/1.1 200 OK
        Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"

        New cookie reflects shipping method.

      7. User Agent -> Server

        POST /acme/process HTTP/1.1
        Cookie: $Version="1";
                Customer="WILE_E_COYOTE"; $Path="/acme";
                Part_Number="Rocket_Launcher_0001"; $Path="/acme";
                Shipping="FedEx"; $Path="/acme"
        [form data]

        User chooses to process order.

      8. Server -> User Agent

        HTTP/1.1 200 OK

        Transaction is complete.

   The user agent makes a series of requests on the origin server, after
   each of which it receives a new cookie.  All the cookies have the
   same Path attribute and (default) domain.  Because the request-URIs
   all path-match /acme, the Path attribute of each cookie, each request
   contains all the cookies received so far.

◆cookieとプライバシ

◆JavaScriptによるクッキーのアクセス

クッキーは、JavaScript のプログラムからアクセスできる。 悪意のある JavaScript を実行してしまうと、クッキーが盗まれる。

■バッファ・オーバーフロー

1学期開講の「システムプログラム」でも説明。 http://www.coins.tsukuba.ac.jp/~syspro/2007/shui/1stHalf.html#sec:buffer-overflow

スタック領域、引数、リターンアドレス、ローカル変数、buf[0]、buf[99]

図? バッファ・オーバーフロー

snprintf を使った文字列のコピーと結合

   1:	/*
   2:	        strcat-snprintf.c -- snprintf を使った文字列のコピーと結合
   3:	        ~yas/syspro/string/strcat-snprintf.c
   4:	        Created on: 2006/01/17 03:17:24
   5:	*/
   6:	
   7:	#include <stdio.h> /* stderr, snprintf() */
   8:	#include <stdlib.h> /* malloc() */
   9:	#include <string.h> /* strcat() */
  10:	
  11:	
  12:	main( int argc, char *argv[], char *envp[] )
  13:	{
  14:	        if( argc != 2 )
  15:	        {
  16:	            fprintf(stderr,"Usage:%% %s string\n",argv[0] );
  17:	            exit( 1 );
  18:	        }
  19:	        good( argv[1] );
  20:	        bad( argv[1] );
  21:	}
  22:	
  23:	#define DOCUMENT_ROOT "/usr/local/httpd/htdocs/"
  24:	#define BUFFSIZE 100
  25:	
  26:	bad( char *s )
  27:	{
  28:	    char buf[BUFFSIZE];
  29:	    int fd ;
  30:	        strcpy( buf,DOCUMENT_ROOT );
  31:	        strcat( buf,s );
  32:	        printf(" bad: open(\"%s\", O_RDONLY )\n",buf );
  33:	}
  34:	
  35:	good( char *s )
  36:	{
  37:	    char buf[BUFFSIZE];
  38:	    int req ;
  39:	        req = snprintf( buf,sizeof(buf),"%s%s",DOCUMENT_ROOT,s );
  40:	        if( req >= sizeof(buf) )
  41:	        {
  42:	            fprintf(stderr,"good: buffer overflow attack detected.\n");
  43:	            fprintf(stderr,"required: %d, actual: %d, strlen: %d, [%s]\n",
  44:	                    req, sizeof(buf), strlen(buf), buf );
  45:	            return( 0 );
  46:	        }
  47:	        printf("good: open(\"%s\", O_RDONLY )\n",buf );
  48:	        return( 1 );
  49:	}

snprintf() の引数

snprintf() は、決してバッファ・オーバーフローを起こさない。 結果として、必要なバイト数(最後の0は含まない、strlen()と同じ)を返す。 これが、バッファよりも少なければ成功である。 等しいか大きい時には、後ろが切られる。

snprintf() は、%s 以外に %d や %c も使える。

snprintf() は、決してバッファ・オーバーフローを起こすことはないが、バッ ファが足りない時には意図していない結果が保存されていることになる。後ろ が切れてもよい場合には、リターンされた結果を比較しない方法がある。 (void とも書かなくてもよい。)

	(void)snprintf( buf,sizeof(buf),"%s%s",DOCUMENT_ROOT,s );

実行例:

% cp ~yas/syspro/string/strcat-snprintf.c . [←]
% make strcat-snprintf [←]
cc     strcat-snprintf.c   -o strcat-snprintf
% ./strcat-snprintf index.html [←]
good: open("/usr/local/httpd/htdocs/index.html", O_RDONLY )
 bad: open("/usr/local/httpd/htdocs/index.html", O_RDONLY )
% ./strcat-snprintf 01234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567890123456789[←]
good: buffer overflow attack detected.
required: 134, actual: 100, strlen: 99, [/usr/local/httpd/htdocs/0123456
78901234567890123456789012345678901234567890123456789012345678901234]
 bad: open("/usr/local/httpd/htdocs/012345678901234567890123456789012345
678901234567890123456789012345678901234567890123456789012345678901234567
89", O_RDONLY )
Segmentation fault
% []

■CGIの考え方

WWW サーバは、普通は、ファイルに保存された HTML データやイメージ・データを 読み込み、WWWブラウザに返する。 CGI (Common Gateway Interface) では、ファイルが読み込まれる代わりにプログラムが実行され、その実行結果 がブラウザに返される。

Gateway とは、WWW で使われている HTTP というプロトコルへの入り口という 意味である。 プログラムの実行結果は、普通は、HTML にすることが多いが、普通のテキス トであることもイメージであることもある。

クライアント、WWWサーバ、CGIによるプロセス、ファイル

図? CGIの仕組み

CGI の利用例

◆JavaScript

JavaScript は、WWW ブラウザ上で動作するスクリプト言語である。

JavaScript は、文法が少し Java 言語に似ているが、Java とはまったく別の 言語である。WWW ページの中の Javaアプレットは、 「実行可能なインライン・イメージ」に似ている。これに対して JavaScript の記述は、「実行可能なインライン・テキスト」 に似ている。

JavaScrip のプログラムの例:

<SCRIPT LANGUAGE="JavaScript">
<!--
for( i=0 ; i<10; i++ )
  document.writeln("<P>hello,world</P>");
//-->
</SCRIPT>

これは、<P>hello,world</P> を 10 回書いた のと同じ効果がある。<!--//->は、JavaScriptを知らないブラウザにはコメント として扱われる。関数定義などは、ヘッダ部分 <HEAD></HEAD>に書くという方法もよく使われる。

◆JavaScript の言語としての特徴

◆JavaScript によるブラウザの制御

JavaScript の記述は、CGI と似ているところもあるが、JavaScript でないと できないものに、ブラウザの制御がある。たとえば、次の例では、ブラウザの (戻る)ボタンと同じ動きをさせることができる。

<A HREF="javascript:history.back();">戻る</A>

次の例は、<FORM></FORM>からパラメタを受け取るも のである。

<SCRIPT LANGUAGE="JavaScript">
function go(s,h,p)
{
	location.href = s.value + "://" + h.value + p.value ;
}
</SCRIPT>

<FORM NAME="form1">
<INPUT NAME="scheme" TYPE="text" VALUE="http"><BR>
<INPUT NAME="host"   TYPE="text"><BR>
<INPUT NAME="path"   TYPE="text" VALUE="/"><BR>
<INPUT TYPE="button" VALUE="go" onClick="go(form1.scheme,form1.host,form1.path)">
</FORM>

onClick 属性の値は、クリックした時に評 価される式であり、関数 go() が呼び出されている。引 数は、<FORM> の値である。関数 go() の中では、 .value フィールドから値が読み出されている。 location.href に代入することで そのページを表示させることができる。

この例では、<INPUT type="text"><INPUT type="button">が使われている。その他に、 <FORM>では、<INPUT TYPE="radio"><INPUT TYPE="checkbox"><SELECT>が使える。イベントとしては、 onClick が主に使われる。その他に、 onFocus が使われることもある。

JavaScript では、document.open() で新しく HTML の ドキュメントを生成して、それをブラウザに表示させることもできる。

■クロスサイトスクリプティング攻撃

WWWブラウザでは、信頼しているサイトから送られてくるJavaScriptのプログ ラムだけを実行するようにし、攻撃サイトから送られてくるJavaScriptのプロ グラムを実行しないようにしたい。

WWW ブラウザ、攻撃サイト、信頼しているサイト、JavaScriptのプログラム

図? JavaScripの送信元サイトの区別

脆弱性があるサイトでは、攻撃サイトから送られてきた JavaScript のプログ ラムを中継してしまう。

WWW ブラウザ、攻撃サイト、脆弱性のあるサイト、JavaScriptのプログラム

図? JavaScripの送信元サイトの区別

これがクロスサイトスクリプティング攻撃(cross-site scripting atack, XSS atack)である。

CGI のプログラムをつくる時には、クロスサイトスクリプティング攻撃に気を つける。これは、クライアントから送られてる文字列の中に <SCRIPT>のようなタグが含まれていた場合、それをそのままクラ イアントに送り返すと問題がある。

クライアントから送られてきた文字列は、必ず検査し、安全な状態にして (sanitize)から使う。「<>&"」のようなタグが含まれている場合 には注意する。このような文字列を受け取った場合、不用意に送り返してはい けない。送り返す時には、必ず次のように変換する。
画面表示 代りに送りだす文字列
& &amp;
< &lt;
> &gt;
" &quot;

■その他の脆弱性と攻撃

◆format string bug

[format.c]
   1: 
   2: /*
   3:         f o r m a t .c -- printf() 系の危険な利用方法
   4:  */
   5: main(int argc, char *argv[])
   6: {
   7:         printf(argv[1]);
   8: }

% wget http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2007/2008-02-19
/format.c [←]
% make format [←]
cc     format.c   -o format
% ./format aaa [←]
aaa% [←]
% ./format "%s%s%s%s"  [←]
Bus error
% []
printf() の には、外から来た文字列を与えてはならない。 syslog(3) も同様。

◆シンボリックリンク攻撃

/tmp や /var/tmp には、誰でも書き込める。テンポラリ・ファイルが作られ る。

そのような誰でも書き込める場所に不用意にのファイルを作るプログラムはシ ンボリックリンク攻撃に対して脆弱性を持つ。

特に危険なものは、root の権限で動作させるプログラム。set-uid だけでな く、root の作業でよく利用するプログラムにも注意する必要がある。

しかし、lstat() で調べるだけでは不十分。

◆TOCTOU (Time to check to time to use)

チェックした後、書き換えられる可能性がある。
if( check(filename) )
	    fd = open(filename,O_RDONLY)
check() と open() の間に、check() の状態が変化してしまうことがある。

◆他のプログラムの実行

CGI では、意図していないプログラムを実行しないようにする。

◆他のプログラムの実行(C言語)

他のプログラムを実行する時には、execve() のようなシステムコールを使い、 かつ、限られたプログラムしか実行しないようにすると安全性が高くなる。ク ライアントから送られてきた文字列をsystem() や popen() に渡してプログラ ムを実行する時には、必ず検査する。特にシェルが解釈する特殊な文字 「| & ; && || `」などが含 まれていた場合、意図しないプログラムが実行されることがある。

char *user ;
...
snprintf(cmd,BUFSIZE,"finger %s",user );
f = poepn(cmd,"r");
もし、user に ";""|" が含まれていたら、、、 
f = poepn("finger yas; /bin/sh","r");

◆他のプログラムの実行(Perl言語)

Perl には、バッファ・オーバーフローの問題はない。

perl の open() には、危険性がある。 C 言語のライブラリ関数 popen() と同じ動きをすることがある。

open(FILE, "|cmd")
Perl の危険な関数、式、

参考

産業技術総合研究所 グリッド研究センター セキュアプログラミングチーム
http://securit.gtrc.aist.go.jp/
)

IPA セキュア・プログラミング講座
http://www.ipa.go.jp/security/awareness/vendor/programming/
)


Last updated: 2008/02/18 22:16:05
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>