LoginSignup
9
3

More than 5 years have passed since last update.

PostgreSQL の仕様の穴 (CVE-2018-1058) で遊んでみた

Last updated at Posted at 2018-03-10

CVE-2018-1058 は PostgreSQL 10.3 等で文書化された脆弱性で、マニュアルの 5.8.6. Usage Patterns などに対策のための記述が追加されました。

詳しい内容は Wiki の A Guide to CVE-2018-1058: Protect Your Search Path に記述されており (日本語だとOSSデータベース取り取り時報 第32回が良いです)、面白い挙動だと思ったので実際の動きを確認してみました。

再現手順

1. Windows 10 に PostgreSQL 10.3 をインストール

ロケールを C にして適当にインストールしました。

2. C:\Program Files\PostgreSQL\10\bin を PATH に追加

3. postgres さんでログイン

PS> psql -Upostgres

4. alice ちゃんのアカウントをつくる

postgres=# CREATE USER alice WITH PASSWORD 'Shino'; -- シノ大好き!

インストーラーが作るデータベース・クラスタは initdb -A md5 となっているため、パスワード認証必須みたいです。

5. テーブル a をつくる

postgres=# CREATE TABLE a (full_name varchar(255));

6. 適当に insert する

postgres=# INSERT INTO a VALUES ('humpty dumpty');

7. upper 関数を使って確認

postgres=# SELECT upper(full_name) FROM a;
     upper
---------------
 HUMPTY DUMPTY
(1 )

これがあるべき結果!

8. alice ちゃんでログイン

PS> psql -Ualice postgres

9. いたずらで罠関数版の upper を作る

postgres=> CREATE FUNCTION upper(varchar) RETURNS text AS $$
postgres$>     -- 日本の文字大好き! 全角にしよう!
postgres$>     SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
postgres$> $$ LANGUAGE SQL IMMUTABLE;

10. postgres さんでさっきと同じクエリを実行

postgres=# SELECT upper(full_name) FROM a;
           upper
---------------------------
 HUMPTY DUMPTY
(1 )

さっきと違って全角になってる!! 罠関数を踏んでしまった!

普通の upper は引数が text 型なので varchar 型とは暗黙の型変換が行われますが、alice ちゃんの upper は引数が元から varchar 型なので、より良く一致するのですね。

11. postgres さんで問題を解決

postgres=# -- 容疑者探し
postgres=# \df+ public.*
                                                                                                                                関数一覧
 スキーマ | 名前  | 結果のデータ型 |  引数のデータ型   |    | 関数の変動性分類 | 並列実行 | 所有者 | セキュリティ | アクセス権限 | 手続き言語 |                                                  ソースコード                                                   | 説明
----------+-------+----------------+-------------------+------+------------------+----------+--------+--------------+--------------+------------+-----------------------------------------------------------------------------------------------------------------+------
 public   | upper | text           | character varying | 通常 | IMMUTABLE        | 危険     | alice  | 起動ロール   |              | sql        |                                                                                                                +|
          |       |                |                   |      |                  |          |        |              |              |            |     -- 日本の文字大好き! 全角にしよう!                                                                       +|
          |       |                |                   |      |                  |          |        |              |              |            |     SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');+|
          |       |                |                   |      |                  |          |        |              |              |            |                                                                                                                 |
(1 )

postgres=# DROP FUNCTION public.upper; -- アリスちゃんのいたずらの後始末
DROP FUNCTION

postgres=# REVOKE CREATE ON SCHEMA public FROM PUBLIC; -- 明示的に許可していないユーザーは public に CREATE できなくしよう
REVOKE

この対策が取れない場合、search_path を '"$user", public' ではなく "$user" とする方法があります。

12. alice ちゃんでいたずらできないのを確認

postgres=> CREATE FUNCTION upper(varchar) RETURNS text AS $$
postgres$>     SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
postgres$> $$ LANGUAGE SQL IMMUTABLE;
ERROR:  permission denied for schema public

13. alice ちゃん用の遊び場を作成

postgres=# CREATE SCHEMA AUTHORIZATION alice;

14. alice ちゃんが自室で遊べることを確認

postgres=> CREATE FUNCTION upper(varchar) RETURNS text AS $$
postgres$>     SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
postgres$> $$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION
postgres=> CREATE TABLE b (first varchar(256), last text);
CREATE TABLE
postgres=> INSERT INTO b VALUES ('humpty', 'dumpty');
INSERT 0 1
postgres=> SELECT upper(first), upper(last) FROM b;
    upper     | upper
--------------+--------
 HUMPTY | DUMPTY
(1 )

あとがき

デフォルトの権限を見直さず alice ちゃんに不要な権限を与えちゃったのがいけなかったですね。とはいえデフォルト値の initdb -A trust とか、public に一般ユーザが CREATE できるとかは好ましいとは思えず、最初から安全にしてくれても良いのに、と思いました。11 に期待できるでしょうか。

私は 10.3 の提供開始当初、アップデートしさえすれば安全になると思い込んでいました。Windows Server の Meltdown 脆弱性パッチでも同じ勘違いをしていました。リリースノート等はきちんと読むべきですね。

私に商用環境の構築経験はないため、もしかすると上記では不十分な点もあるかもしれません。業務でご参考になさる場合には、私と同じ轍を踏まないよう、公式文書も合わせてご確認ください。

ここまでご覧いただきありがとうございました。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3