PS3をポートスキャンしてみました。

知人がPS3を持っていたので、Jamesさんの ポートスキャンでWiiを調べてみた - Eiji James Yoshidaの記録 を真似てPS3をポートスキャンしてみました。
私、NWのことはとんと分からないので、結果で出た開いてる(そうな)ポートがどうセキュリティリスクになるのかは分からないですが、Wiiより開いてる(そうな)なポートが多いですね。25番がとても気になる。
間違ってると先輩からご指摘。

結果はこちら。

nmap -n -sSU ***.***.***.*** -p 0-

Starting Nmap 4.20 ( http://insecure.org ) at 2007-03-17 12:17 東京 (標準時)
Interesting ports on ***.***.***.***:
Not shown: 131067 closed ports
PORT     STATE         SERVICE
25/tcp   filtered      smtp
135/tcp  filtered      msrpc
1720/tcp filtered      H.323/Q.931
0/udp    open|filtered unknown
135/udp  open|filtered msrpc

Nmap finished: 1 IP address (1 host up) scanned in 543.782 seconds

PS3 20GにWindows版のnmapで試しました。

次回予告:今度はDSをやってみる。

・2007/03/22追記
ネサス流してみたけど、当たり前ですが何も出ず。

・2007/03/29追記
PS3はPPPOEでルータ等なしで直で外に出てます。

証明書エラーが出るサイトはIE7では見れない?

IE7を入れて遊んでいると、https のサイトで見れないサイトが出てきた。どうやら、証明書に問題があるサイトは表示されないようだ。IE6だと警告のポップアップが表示されるのだが、IE7だと画面に下の様なエラー画面が表示される。



 この Web サイトで提示されたセキュリティ証明書は、別の Web サイトのアドレス用に発行されたものです。
セキュリティ証明書の問題によって、詐欺や、お使いのコンピュータからサーバーに送信される情報を盗み取る意図が示唆されている場合があります。  
  このページを閉じて、この Web サイトの閲覧を続行しないことを推奨します。 
  ここをクリックしてこの Web ページを閉じる。  
  このサイトの閲覧を続行する (推奨されません)。  


画面は、高木浩光@自宅の日記で指摘されている証明書エラーが出る某サイトをIE7で表示させたもの。
http://takagi-hiromitsu.jp/diary/20050115.html

もちろん「このサイトの閲覧を続行する」をクリックすると表示はされるのだが、下の様にアドレスバーが赤くなり、証明書エラーと表示される。

IE7の普及でオレオレ証明書は減る?

証明書のエラーが出るのは、期限切れやオレオレ証明書や他ドメインの使い回しであったりするのだが、こういったサイトがIE7の普及により少なくなると良いなと思う。

セキュリティエンジニアの困った

しかし、困った事が出てきました。私はセキュリティ関係の仕事をしていて主にWebアプリの脆弱性をチェックする仕事をしているのですが、仕事でよくBurpProxyというツールを使っています。こいつは、Proxyサーバの役割をして、リクエストを書き換えてWebアプリの挙動を調べるのに使います。
イメージとしてはこんな感じ。サイト⇔BurpProxy⇔ブラウザ
正常な証明書エラーの出ないサイトを閲覧する時も、BurpProxyを経由するのでSSL使用時にはBurpProxyの証明書を受け入れなくてはならない。当たり前だけど、証明書エラーが出るので画面キャプチャを取る時に証明書エラーの画面はお客さんに出せないよなーっと思う。
BurpProxyではてなのログインページを表示。アドレスバーが赤くなっているのが分かる。

IE7のクロスドメインバリアって?


MSのサイトによると

Web ページのスクリプトと他のドメインやウィンドウのコンテンツとの連携を制限します。 この保護機能の強化により、悪意のある Web サイトが他の Web サイトの欠陥を利用したり、ユーザーに不要なコンテンツやソフトウェアをダウンロードさせる可能性を抑えることができ、マルウェアに対する防護が向上します。
http://www.microsoft.com/japan/windows/ie/ie7/about/features/default.mspx

とのこと。

悪意のある Web サイトが他の Web サイトの欠陥を利用したり、
これってXSSのことかなぁ?
さいばーとの検証では
XSS脆弱性があるAサイトに、
Bサイトからスクリプトを投げて、
Aサイトで発行するCookieをBサイトで表示するってのは出来たんですが。。。
きっと違う箇所を直したんですねMSさん!?

当分色々試す事がものがあって楽しめるので良いのですが。。

にしてもクロスドメインバリアってネーミングかっこ悪い。バリアって単語聞くの小学生以来だなぁ

ハックミー

ハックしちゃってください。→ http://tepppei.com/hackme/

お仲間に、この間作ったPHP_WAF(PHPスクリプト内でセキュリティ対策を行うもの)をどっかに挙げてハックさせろ。と言われ、結構面白そうなので、やってみることにしました。どうせなので、脆弱なコードと脆弱なコードにPHP_WAFの対策を行った場合の二つのアプリを公開したいと思います。
脆弱なコードでは

  • Cross site scripting
  • NULL Byte Attac
  • HTTP Response Splitting
  • Directory traversal

脆弱性を試すことが出来ます。

PHP_WAFについてはこちら。http://d.hatena.ne.jp/cybert/20060831/1157031516 簡単に説明すると、パラメータ毎に対策を行うのではなく、全部のパラメータに良く知られたWebアプリの攻撃を防御することによって、開発の負担を減らそうと言う趣旨のスクリプトです。

一応ログは取っています、ログ取得の目的は勉強になりそうな攻撃手法があれば学ぼうという考えからです。脆弱性の勉強とかにもなるかもしれません、しかしハックOKなのはWebアプリのみです、ネットワークやネットワーク機器、Webサーバやその他のソフトにハッキング行為は行わないで下さい。

ハックはこちらから http://tepppei.com/hackme/
 
 
 
 
 

PHPアプリケーションWAFα版(仮称)

特徴
PHPで作ったWAFのような動作をするスクリプトです。
ユーザから送られてくる次のパラメータに対して、浄化処理を行い下記の攻撃や問題を防ぎます。

  • Cross site scripting
  • NULL Byte Attack
  • CRLF Injection もしくは(HTTP Response Splitting)
  • Buffer over flow
  • マルチバイト問題
  • Directory traversal
  • PHPの設定ミス(この機能は作り途中でごく一部のみ)

機能
PHPでWebアプリ作るときに、セキュリティ対策を行うのは面倒です。そんな訳で、ユーザから送られてくる殆ど全てのパラメータに対して、勝手に且つ強引に浄化処理を行い攻撃や問題を防ぎます。基本的には、脆弱に成り得る文字を取り除いたり、無害化したりといった処理を行います。対象となるのは、GETパラメータ($_GET)、POSTパラメータ($_POST)、Cookieパラメータ($_COOKIE)、ヘッダパラメータ?($_SERVER['HTTP_からはじまるもの'])に対して、パラメータの浄化処理を行って、それぞれのパラメータを上書きします。上書きを行うので、既存のアプリケーションにも利用できるかと思います。

脆弱なコードと最も簡単な使い方
会員登録のアプリケーションを例にしたCross site scriptingとNULL Byte Attackに対して脆弱なコードの典型的な例。

<html>
<form method="GET" action="hoge.php">
<input type="text" name="name">
<input type="text" name="tel">
<input type=submit>
</form>
<?
print $_GET['name'] . "さん。";
//数字のみのデータなら
if(ereg("^\d+$",$_GET['tel'])){
       //登録処理
       print "あなたの電話番号" . $_GET['tel'] . "の登録が完了しました!";
}else{print "エラー数字以外が入力されてます。";}
?>

このようなコード場合、

htt://XXXX/hoge.php?name=<script>alert('XSS');</script>&tel=090000%00<script>alert('XSS');</script>

とアクセスすることで、Cross site scripting攻撃が成功し、実際にはアラートが表示され、電話番号のチェック=数字のみかをチェックしている箇所も、NULL Byte Attack攻撃が成功し意味をなさなくなります。

<?
require_once("PHP_WAF.php");
$obj = new PHP_WAF("SJIS");//オブジェクト作る、引数に文字コード
$obj->filterAll();//サニタイズを行う
?>
<html>
<form method="GET" action="hoge.php">
<input type="text" name="name">
<input type="text" name="tel">
<input type=submit>
</form>
<?
print $_GET['name'] . "さん。";
//数字のみのデータなら
if(ereg("^\d+$",$_GET['tel'])){
       //登録処理
       print "あなたの電話番号" . $_GET['tel'] . "の登録が完了しました!";
}else{print "エラー数字以外が入力されてます。";}
?>

この様に頭に3行足すことで、アプリはPHP_WAFによってパラメータがHTMLエンコードされ、NULLバイトを取り除かれる事によって脆弱性の対策がなされます。

お願い
バグ、機能に関しての連絡。ここのコードおかしくない? ハックできたよheheheって連絡ぜひください。連絡先は下にあります。

注意
上記挙げた脆弱性も含めて万能ではありません。このプログラムはまだアルファバージョンです。

使い方

//ここからのコードは必ずスクリプトの一番最初に書いてください。
//ファイルを読み込みますコードはブログの下の方にあります。
require_once("PHP_WAF.php");

//オブジェクト生成、ユーザの入力値の文字コードをセットしてください。
$obj = new PHP_WAF("SJIS");

//サニタイズ処理を全く行いたくない、又は一部の対策のみ行いたいパラメータを指定します。
//例はGETパラメータの hoge は改行文字を入れたいから除外する。
$obj->exceptParam("GET","hoge");

//パラメータにサニタイズ処理を行う(exceptParamで除外したものを除く)
//1-5番目の引数で指定した対策を行う項目名(BOF,XSS,CRLF,NULLBYTE)のいずれか。
//ENCODEはマルチバイト問題、CRLFはCRLF Injection、NULLBYTEは、NULL Byte Attack
//BOFはBuffer over flow、XSSはCross site scriptingの対策を行います。
//例では全部やる
$obj->sanitizeAllPalam();

//パラメータと対策方法を指定してサニタイズを行う、
//1番目の引数:パラメータの種類(GET,POST,COOKIE,HEAD)
//2番目の引数:パラメータの名前
//3-7番目の引数:対策を行う項目を指定(ENCODE,CRLF,NULLBYTE,BOF,XSS)
//ここで上で除外したhogeパラメータにBuffer over flowとCross site scriptingの対策を行う。
$obj->sanitizeEachPalam("GET","hoge","BOF","XSS");

//ここまでのコードは必ずスクリプトの一番最初に書いてください。

コードPHP_WAF.php と名前をつけてあげて下さい。)

<?
class PHP_WAF{
	/**
    * 入力文字コード
    * @var string
    */
	var $_encode;
	
	/**
    * 除外するGETパラメータ
    * @var array
    */
	var $_exParamGet = array();
	
	/**
    * 除外するPOSTパラメータ
    * @var array
    */
	var $_exParamPost = array();
	
	/**
    * 除外するCookieパラメータ
    * @var array
    */
	var $_exParamCookie = array();
	
	/**
    * 除外するHeadパラメータ
    * @var array
    */
	var $_exParamHead = array();
	
	/**
    * パラメータの最大入力文字数。マルチバイトも1文字として数えます。
    * @var Int
    */
	var $_maxParamLen;
	
	
   /**
	* コンストラクタ
	* @param1  string パラメータの文字コード
    * @param2  Int    パラメータの最大文字数(マルチバイトも1文字として数える)
    */
	function PHP_WAF($encode = "",$maxParamLen = 500){
		//指定エンコードがサポートされているか
		if(array_search($encode,mb_list_encodings()) !== FALSE){
			$this->_encode = $encode;
		}else{
			die("ERROR");
		}
		
		//パラメータの最大入力文字数をセット(マルチバイトも1文字として数える)
		$this->_maxParamLen = $maxParamLen;
	}



/**************************************************************************************
メインの処理を行うメソッド4つです。
PHP_WAF::exceptParam	対策を行わないパラメータを指定する。
PHP_WAF::sanitizeAllPalam		GET,POST,COOKIE,HEAD全てに指定したサニタイジングを行う。
PHP_WAF::sanitizeEachPalam	指定したパラメータのみ指定したサニタイジングを行う。
PHP_WAF::_sanitize		対策を行うメソッドをコールして
/**************************************************************************************

   /**
    * sanitizeAll を行った際に除外するパラメータ
    * notice:sanitizeAll より前にコールされなければなりません。
    *           指定されたパラメータは何も対策されません。
    *           除外したパラメータは sanitizeEachPalam で
    *           個別に対策してあげてください。
    * @access public
    * @param1  string パラメータのタイプ(GET,HEAD,POST,COOKIE)のいずれか
    * @param2  string パラメータ名
    * @return  Boolean
    */
	function exceptParam($type="",$name=""){
		switch($type){
			case 'HEAD':
				$name = "HTTP_" . strtoupper(str_replace("-","_",$name));
				$this->_exParamHead[] = $name;
				break;
			case 'GET':
				$this->_exParamGet[] = $name;
				break;
			case 'POST':
				$this->_exParamPost[] = $name;
				break;
			case 'COOKIE':
				$this->_exParamCookie[] = $name;
		}
	}
	
   /**
    * 機能:GET,POST,HEAD,COOKIE にサニタイジングを行う
    * notice: exceptParam より後にコールされるべきです。
    *         _exParamGet _exParamPost _exParamCookie 
    *         _exParamHeadの値のパラメータはスキップされる。
    * @param string  対策を行う項目名、のいずれか。
    * @access public
    * @return nothing
    */
	function sanitizeAllPalam($pattern="NULLBYTE,CRLF,ENCODE,BOF,XSS,DIRT"){
		
		//GETパラメータ全てに対策
		foreach($_GET as $key => $value){
			//除外パラメータでは無いかチェック
			if($value != "" AND array_search($key, $this->_exParamGet) === FALSE){
				//$patternの対策を全て行い上書きする。
				$_GET[$key] = $this->_sanitize($value,$pattern);
			}
		}
		
		foreach($_POST as $key => $value){
			if($value != "" AND array_search($key, $this->_exParamPost) === FALSE){
				$_POST[$key] = $this->_sanitize($value,$pattern);
			}
		}
		
		foreach($_COOKIE as $key => $value){
			if($value != "" AND array_search($key, $this->_exParamCookie) === FALSE){
				$_COOKIE[$key] = $this->_sanitize($value,$pattern);
			}
		}
		
		foreach($_SERVER as $key => $value){
			if($value != "" AND array_search($key, $this->_exParamHead) === FALSE AND preg_match("/^HTTP_/",$key)){
				$_SERVER[$key] = $this->_sanitize($value,$pattern);
			}
		}
	}
	
   /*
    * @function GET,POST,HEAD,COOKIE にサニタイジングを行う
    * @notice sanitizeAllPalam より後にコールされるべきです。
    * @param1 string パラメータの種類(GET,POST,COOKIE,HEADのいずれか)
    * @param2 string パラメータの名前
    * @param3 string 対策を行う項目名(BOF,XSS,CRLF,NULLBYTE,ENCODE,DIRT)のいずれか。
    * @access public
    * @return Boolean
    */
    
	function sanitizeEachPalam($type="",$name="",$pattern=""){
		
		switch($type){
			case 'HEAD':
				$name = "HTTP_" . strtoupper(str_replace("-","_",$name));
				$_SERVER[$name] = $this->_sanitize($_SERVER[$name],$pattern);
				break;
			case 'GET':
				$_GET[$name] = $this->_sanitize($_GET[$name],$pattern);
				break;
			case 'POST':
				$_POST[$name] = $this->_sanitize($_POST[$name],$pattern);
				break;
			case 'COOKIE':
				$_COOKIE[$name] = $this->_sanitize($_COOKIE[$name],$pattern);
		}
	}

   /**
    * param1の値をparam2で指定したメソッドの引数に与える。
    * @param1 文字列
    * @param2 メソッド名(,で複数指定可能)
    * @access private
    * @return サニタイジングされた値
    */
	function _sanitize($str="",$pattern=""){
		
		$patternArry = preg_split("/,/",$pattern);
		
		foreach($patternArry as $key => $method){
			if(is_callable(array($this,$method))){
				$str = call_user_func(array($this,$method),$str);
			}
		}
		return $str;
	}
	
	/**************************************************************************************
	ここからは、個別の対策を行うメソッドです。
	クラスを継承して、個別の対策を上書きOR追加することが簡単にできます。
	個別の対策を行うメソッド名はそのまま PHP_WAF::_sanitize が呼び出すのに使用します。
	よって、メソッド名HOGEを作った場合、PHP_WAF::sanitizeAll('HOGE') とすれば良いのです。
	文字列入力→サニタイズ→文字列出力の機能を守ってください。
	/**************************************************************************************

   /**
    * BOF対策を行う。_maxParamLen で指定した長さ(デフォルト500文字)以上は切り捨てる。
    * Notice 長さはマルチバイトも1として数えられます。
    * @access private
    * @param  string 
    * @return string
    */
	function BOF($str){
		return mb_substr($str,0,$this->_maxParamLen,$this->_encode);
	}
	
   /**
    * XSS対策を行う。
    * '"<>& の5つの文字をHTMLエンコードする
    * @access private
    * @param  string 
    * @return string
    */
	function XSS($str){
		return htmlspecialchars($str,ENT_QUOTES,$this->_encode);
	}
	
   /**
    * crlf対策を行う。
    * 改行文字を取り除く
    * @access private
    * @param  string 
    * @return string
    */
	function CRLF($str){
		$chrs = array("\r","\n");
		return str_replace($chrs,"",$str);
	}
	
   /**
    * ヌルバイトアタック対策を行う。NULL文字を取り除く
    * @access private
    * @param  string 
    * @return string
    */
	function NULLBYTE($str){
		return str_replace("\0","",$str);
	}
	
   /**
    * マルチバイト問題対策を行う。入力文字の再エンコードを行う。
    * @access private
    * @param  string 
    * @return string
    */
	function ENCODE($str){
		return mb_convert_encoding($str, $this->_encode, $this->_encode);
	}

   /**
    * ディレクトリとらさば 対策を行う。../ ..\ の文字を全角にする。
    * @access private
    * @param  string 
    * @return string
    */
	function DIRT($str){
		if(preg_match("/\.+[\/\\\]+/",$str)){
			$str = str_replace("/","/",$str);
			$str = str_replace(".",".",$str);
			$str = str_replace("\\","¥",$str);
		}
		return $str;
	}
	

/**************************************************************************************
メインの処理を行うメソッド4つです。
PHP_WAF::exceptParam	対策を行わないパラメータを指定する。
PHP_WAF::sanitizeAll		GET,POST,COOKIE,HEAD全てに指定したサニタイジングを行う。
PHP_WAF::sanitizeEachPalam	指定したパラメータのみ指定したサニタイジングを行う。
PHP_WAF::_sanitize		対策を行うメソッドをコールする
/**************************************************************************************
   /**
    * PHP の設定をセキュアに変更
    * notice:ポリシーは著者の独断と偏見です。ここで設定できるのはアクセスレベルがPHP_INI_ALL(7)のものだけです。
    * @access public
    * @param  3 もしくは safe              ポリシー:不要と思われるもの全てをOFFに変更 + レベル2,1の項目
    *         2 もしくは normal            ポリシー:最低限不要と思われるものをOFFに変更 + レベル1の項目
    *         1 もしくは min (デフォルト)  ポリシー:セキュリティ上脅威とり得るものを設定変更
    * @return boolean TRUE もしくは STRING(最後に失敗した項目名)
    */
	function setiniLevel($level = 1){
		$failed = array();
		if($level == 3 OR $level == "safe"){
			//session.auto_start
			//expose_php=off
			//file_uploads=off 
			//session.use_strict_mode=1
		}
		if($level >= 2 OR $level == "safe"
		               OR $level == "normal"){

			//session.use_trans_sid
			//if(!ini_set("session.use_trans_sid",0)){$failed[] = "session.use_trans_sid";}
			//session.use_only_cookies
			//if(!ini_set("session.use_only_cookie",1)){$failed[] = "session.use_only_cookie";}
			//session.gc_maxlifetime 
			//memory_limit
			//safemode
			//variables_order="GPCS"
			//register_long_arrays=off
			//register_argc_argv=off 
			//magic_quotes_gpc=off 
			//allow_url_include=off
			//if(!ini_set("allow_url_include",0)){$failed[] = "allow_url_include";}
		}
		if($level >= 1 OR $level == "safe"
		               OR $level == "normal"
		               OR $level == "min"){
		     //SQL特殊文字のエスケープを自動で行わない(magic_quotes_gpcは問題がある)
			//if(!ini_set("magic_quotes_gpc",0)){$failed[] = "magic_quotes_gpc";}
		    //allow_url_fopen
			//エラーをLogに取るか
			//if(!ini_set("log_errors",1)){$failed[] = "log_errors";}
			//取得するエラーのタイプ
			if(!ini_set("error_reporting",2047)){$failed[] = "error_reporting";}
			//エラー出力をしない
			if(!ini_set("display_errors",0)){$failed[] = "display_errors";}
			//起動時のエラー出力をしない
			//if(!ini_set("display_startup_errors",0)){$failed[] = "display_startup_errors";}
			//Content-type:ヘッダの文字コード
			//if(!ini_set("default_charset",$this->_encode)){$failed[] = "default_charset";}
			//register_globals
			//if(!ini_set("register_globals",0)){$failed[] = "register_globals";}
		}
		
		//ini_set に失敗すれば最後に失敗した項目名を返します。
		//全て成功時にTRUEを返す。通常のIFの使い方ではなく === TRUE という使い方をして下さい。
		//アクセスレベルはバージョンに依存するので結構失敗します。
		if(!isset($failed[0])){
			return TRUE;
		}else{
			return $failed;
		}
	}
   /**
    * PHP の設定をユーザにより変更、setiniLevel より後にコールすればsetiniLevelの設定の上書きが可能
    * notice:setiniLevel をコールする場合、setiniLevelより後にコールされるべきです。
    * ここで設定できるのはアクセスレベルがPHP_INI_ALL(7)のものだけです。
    * @access public
    * @param  string 設定項目名
    * @param  string 設定項目値
    * @return boolean (成功時にTRUE 失敗時にFalse)
    */
	function setEachini($name="",$value=""){
			return ini_set ($name,$value);
	}
}
?>

連絡先 sekine_works@yahoo.co.jp

注意事項
このソフトウェアを頒布または転載するときは以下の点を遵守してください。オリジナルのまま、頒布または転載してください。頒布または転載の際に、メディア代、通信代等の実費を除いて、金銭の授受があってはなりません。商業的目的で頒布する際には、事前に著作者の許可を取る必要があります。なお、雑誌への掲載収録に限り、許可が不要となります。アルファ版やベータ版など、このソフトウェアがテスト公開バージョンの場合は、再配布できません。このソフトウェアは雑誌へ掲載、収録を歓迎しております。なお、雑誌ではなく書籍形態のものについては、事前に著作者の許可を取る必要があります。著作権は さいばーと が所有しています。このソフトウェアに含まれる著作権情報を書き換えてはなりません。このソフトウェアの使用または使用不可によって、いかなる問題が生じた場合も、著作者はその責任を負いません。バージョンアップや不具合に対する対応の責任も負わないものとします。この文書の内容およびソフトウェアの意匠、仕様は、予告なしに変更されることがあります。