More Related Content Similar to 著名PHPアプリの脆弱性に学ぶセキュアコーディングの原則 (20) More from Hiroshi Tokumaru (19) 著名PHPアプリの脆弱性に学ぶセキュアコーディングの原則2. 徳丸浩の自己紹介
• 経歴
– 1985年 京セラ株式会社入社
– 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍
– 2008年 KCCS退職、HASHコンサルティング株式会社(現社名:EGセキュアソリューショ
ンズ株式会社)設立
• 経験したこと
– 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当
– その後、企業向けパッケージソフトの企画・開発・事業化を担当
– 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当
Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始
– 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立上げ
• 現在
– EGセキュアソリューションズ株式会社 代表 https://www.eg-secure.co.jp/
– 独立行政法人情報処理推進機構 非常勤研究員 https://www.ipa.go.jp/security/
– 著書「体系的に学ぶ 安全なWebアプリケーションの作り方」(2011年3月)
「徳丸浩のWebセキュリティ教室 」(2015年10月)
– 技術士(情報工学部門)
2
4. 【参考】CVEとCWE
• 脆弱性の国際的な分類として CVE と CWE がある
• CVE(Common Vulnerabilities and Exposures)
– 個別ソフトウェアの具体的な脆弱性を識別する番号
– 米国政府の支援を受けた非営利団体のMITRE社他のCNAが採番
– CVEの例
• CVE-2017-1001000 WordPress Rest APIの脆弱性
• CVE-2017-5638 Apache Struts2の脆弱性S2-045
• CWE(Common Weakness Enumeration)
– 脆弱性の種類を識別する番号
– MITRE社が中心となって策定
– CWEの例
• CWE-89 SQLインジェクション
• CWE-22 ディレクトリトラバーサル
4
参考: https://www.ipa.go.jp/security/vuln/CVE.html
https://www.ipa.go.jp/security/vuln/CWE.html
※ CAN: CVE Numbering Authority, CVE 採番機関
7. Java セキュアコーディングスタンダード CERT/Oracle 版
• はじめに
• 00. 入力値検査とデータの
無害化 (IDS)
• 01. 宣言と初期化 (DCL)
• 02. 式 (EXP)
• 03. 数値型とその操作
(NUM)
• 04. オブジェクト指向 (OBJ)
• 05. メソッド (MET)
• 06. 例外時の動作 (ERR)
• 07. 可視性とアトミック性
(VNA)
• 08. ロック (LCK)
• 09. スレッド API (THI)
• 10. スレッドプール (TPS)
• 11. スレッドの安全性に関
する雑則 (TSM)
• 12. 入出力 (FIO)
• 13. シリアライズ (SER)
• 14. プラットフォームのセ
キュリティ (SEC)
• 15. 実行環境 (ENV)
• 49. 雑則 (MSC)
• AA. 参考情報
• BB. Glossary
7https://www.jpcert.or.jp/java-rules/
49. Welcart 1.9.4 をリリースしました【脆弱性の修正】
Welcart 1.9.4 をリリースしました。オブジェクトインジェクション
脆弱性の修正などを行いました。詳細は以下の通りです。
アップグレードを行う場合は、Welcartを停止してからアップグレー
ドを行ってください。
【変更点】
• オブジェクトインジェクション脆弱性の修正
フロントにて、オブジェクトインジェクションと思われる脆弱性
が認められました。
過去のすべてのバージョンが対象となります。1.9.4にアップグ
レードしてください。
放置しますと、サイトに任意のファイルの埋め込まれる可能性が
あります。
脆弱性に関する修正の差分はこちら
49https://www.welcart.com/community/archives/83947より引用
51. Welcart 1.9.3 と 1.9.4の差分
51
https://plugins.trac.wordpress.org/changeset?sfp_email=&sfph_mail=&reponame=&new=1728429
40usc-e-shop&old=1728428%40usc-e-shop&sfp_email=&sfph_mail= より引用
典型的な
オブジェクトインジェクション脆弱性
56. 権限チェックのupdate_item_permissions_checkメソッド
497: public function update_item_permissions_check( $request ) {
498: $post = get_post( $request['id'] );
499: $post_type = get_post_type_object( $this->post_type );
500: if ( $post && ! $this->check_update_permission( $post ) ) {
501: return new WP_Error( ‘rest_cannot_edit’, __(Sorry, you are not allowed ...
502: }
503: if ( ! empty( $request[‘author’] ) && get_current_user_id() !==
$request['author'] &&
! current_user_can( $post_type->cap->edit_others_posts ) ) {
504: return new WP_Error( 'rest_cannot_edit_others', __( 'Sorry, you are not ...
505: }
506: if ( ! empty( $request['sticky'] ) &&
! current_user_can( $post_type->cap->edit_others_posts ) ) {
507: return new WP_Error( 'rest_cannot_assign_sticky', __( 'Sorry, you are not ...
508: }
509: if ( ! $this->check_assign_terms_permission( $request ) ) {
510: return new WP_Error( 'rest_cannot_assign_term', __( 'Sorry, you are not ...
511: }
512: return true;
513: }
56
wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php (Ver 4.7.1)
58. update_item()メソッド
523: public function update_item( $request ) {
524: $id = (int) $request['id'];
525: $post = get_post( $id );
526: if ( empty( $id ) || empty( $post->ID )
|| $this->post_type !== $post->post_type ) {
527: return new WP_Error( ‘rest_post_invalid_id’,
__( 'Invalid post ID.' ), array( 'status' => 404 ) );
528: }
529: $post = $this->prepare_item_for_database( $request );
530: if ( is_wp_error( $post ) ) {
531: return $post;
532: }
58
59. WordPress 4.7.1は何がいけなかったか?
• 原因:
– 権限チェックの際に、存在しない id に対して、権限あり
を返していた
– 権限チェックの際は id キャストなし、データ更新の際は
id を整数にキャストしていた
• 直接の対策
– 存在しない id に対しては「権限なし」を返す
– 権限チェックと更新の際には同じ id を用いる
• 原則論として
– 正規化(この場合は整数へのキャスト)は早期に実施す
る
– バリデーションしていれば防げましたね
59
62. Joomla2.5.2の権限昇格脆弱性
components/com_users/controllers/registration.php register()関数
$data = $model->validate($form, $requestData);
// Check for validation errors.
if ($data === false) {
// Save the data in the session.
$app->setUserState('com_users.registration.data', $requestData);
// Redirect back to the registration screen.
$this->setRedirect(JRoute::_('index.php?option=com_users&view=registrat
ion', false));
return false;
// 中略
// バリデーションが正常の場合
// Flush the data from the session.
$app->setUserState('com_users.registration.data', null);
62
バリデーションエラーの場合、リクエストデータを
まるごとセッション変数に放り込んでいる
権限の情報も含まれている
63. components/com_users/models/registration.php getData() 関数内
$temp = (array)$app->getUserState('com_users.registration.data', array());
foreach ($temp as $k => $v) {
$this->data->$k = $v; // セッションのデータをモデルに放り込んでいる
}
【中略】
$this->data->groups = isset($this->data->groups) ? array_unique($this->da
ta->groups) : array();
// $this->data->groups = array(); 2.5.3でこのように修正
63
セッション汚染、Trust Boundary Violation
と呼ばれる問題
66. phpMyAdmin: CVE-2013-3238
66
case 'replace_prefix_tbl':
$current = $selected[$i];
$newtablename = preg_replace("/^" . $from_prefix . "/",
$to_prefix, $current);
preg_replace("/^/e¥0/", "phpinfo();", "test");
preg_replace("/^/e", "phpinfo();", "test");
$from_pref = "/e¥0“;
$to_prefix = "phpinfo();”;
PHP5.4.3以前では、¥0以降は無視される
67. 脆弱性が混入した要因
• preg_replaceに渡す正規表現をエスケープしていな
かった
– 最低限、/ をエスケープする必要がある
• えーっと、preg_quoteってマルチバイト対応?
– Shift_JIS以外では問題ない?
• そもそも、正規表現を外部から(信頼境界を超え
て)渡す実装は避けるべき(実際にもその方向で改
修された)
67
preg_replace(“/^” . $from_prefix . “/”, …
↓
reg_replace("/^" . preg_quote($from_prefix, '/') . "/", …
71. IN句生成の便利な呼び出し方だが…
71
<?php
db_query("SELECT * FROM {users} where name IN (:name)",
array(':name'=>array('user1','user2')));
?>
SELECT * from users where name IN (:name_0, :name_1)
array(':name_0'=>'user1', ':name_1'=>'user2'))
db_queryにてIN句のバインド値を配列にすると…
IN句の値がプレースホルダのリストに展開される
バインド値の配列は以下の様に変形される
73. 空白付きのキー
73
array(2) {
[":name_1 xxxxx"] => "user1" ← :name_1 ではない
[":name_2"] => "user2"
}
SELECT * FROM {users} WHERE name = :name_1 xxxxx, :name_2 AND sta
tus = 1
キー名に空白をつけてみる
プレースホルダに空白が含まれる
ちぎれたプレースホルダはSQL文
の一部として認識される
プレースホルダには、キー :name_1がないので上記のSQL文呼び出しはエラーになる
name[1 xxxxx]=user1&name[2]=user2
74. バインド値のつじつまを合わせる
74
array(2) {
[":name_2 xxxxx"] => ""
[":name_2"] => "user2"
}
SELECT * FROM {users} WHERE name = :name_2 xxxxx, :name_2 AND sta
tus = 1
キー名に空白をつけてみる
プレースホルダに空白が含まれる
プレースホルダ :name_2 が
2箇所現れる
プレースホルダ配列は上記SQL文の要求を満たすのでSQL文は呼び出される…
が、xxxxxの箇所でSQLの文法違反となる
name[2 xxxxx]=&name[2]=user2
75. SQLインジェクションを試す
75
SELECT * FROM users WHERE name = 'user2' ;SELECT sleep(10) -- , '
user2' AND status = 1
キー名に追加のSQL文を書く
実際に呼び出されるSQL文
name[2 ;SELECT sleep(10) -- ]=&name[2]=user2
SELECT * FROM {users} WHERE name = :name_2 ;SELECT sleep(10) -- ,
:name_2 AND status = 1
プレースホルダの後ろに追加のSQL文が現れる
76. 脆弱なソース
// includes/database/database.inc
protected function expandArguments(&$query, &$args) {
$modified = FALSE;
// $argsの要素から配列のみ処理対象として foreach
foreach (array_filter($args, 'is_array') as $key => $data) {
$new_keys = array();
// $dataは配列であるはずなので、foreach 可能。 $i(キー)に注目
foreach ($data as $i => $value) {
$new_keys[$key . '_' . $i] = $value;
}
// $queryを改変 $new_keysのキーをarray_keysでSQL文に混ぜている
$query = preg_replace('#' . $key . '¥b#',
implode(', ', array_keys($new_keys)), $query);
unset($args[$key]);
$args += $new_keys;
$modified = TRUE;
}
return $modified;
}
76
77. 対策版(7.32)
// includes/database/database.inc
protected function expandArguments(&$query, &$args) {
$modified = FALSE;
// $argsの要素から配列のみ処理対象として foreach
foreach (array_filter($args, 'is_array') as $key => $data) {
$new_keys = array();
// $dataは配列であるはずなので、foreach 可能。 $i(キー)に注目
//foreach ($data as $i => $value) {
foreach (array_values($data) as $i => $value) { // キーを削除
$new_keys[$key . '_' . $i] = $value;
}
// $queryを改変 $new_keysのキーをarray_keysでSQL文に混ぜている
$query = preg_replace('#' . $key . '¥b#',
implode(', ', array_keys($new_keys)), $query);
unset($args[$key]);
$args += $new_keys;
$modified = TRUE;
}
return $modified;
}
77
81. 81
PHP7 で堅牢なコードを書く - 例外処理、表明プログラミング、契約による設計
https://speakerdeck.com/twada/php-conference-2016 より引用
PHPカンファレンス2016
和田卓人さんの講演から
82. 82
PHP7 で堅牢なコードを書く - 例外処理、表明プログラミング、契約による設計
https://speakerdeck.com/twada/php-conference-2016 より引用
PHP7 で堅牢なコードを書く - 例外処理、表明プログラミング、契約による設計
https://speakerdeck.com/twada/php-conference-2016 より引用
PHPカンファレンス2016
和田卓人さんの講演から
83. Drupageddonを例外処理と表明で対処しようとする
foreach ($data as $i => $value) {
if (! is_int($i)) {
throw new Exception('添字は整数である必要があります');
}
$new_keys[$key . '_' . $i] = $value;
}
83
foreach ($data as $i => $value) {
assert(is_int($i));
$new_keys[$key . '_' . $i] = $value;
}
foreach (array_values($data) as $i => $value) { // キーを削除
$new_keys[$key . '_' . $i] = $value;
}
Drupal 7.32
例外処理
表明