OSSのメールリーダーなどに使われる暗号化ソフト「GNU Privacy Guard」の脆弱性OSS脆弱性ウォッチ(7)

連載「OSS脆弱性ウォッチ」では、さまざまなオープンソースソフトウェアの脆弱性に関する情報を取り上げ、解説していく。今回は、2018年6月9日に公開された「GNU Privacy Guard」の脆弱性(CVE-2018-12020)を取り上げる。

» 2018年08月07日 05時00分 公開
[面和毅OSSセキュリティ技術の会]

 「OSSセキュリティ技術の会」の面和毅です。本連載「OSS脆弱性ウォッチ」では、さまざまなオープンソースソフトウェア(OSS)の脆弱(ぜいじゃく)性に関する情報を取り上げ、解説しています。

 今回は、2018年6月9日に公開された「GNU Privacy Guard」(以下、GPGまたはGNUPG)の脆弱性(CVE-2018-12020)を取り上げます。

脆弱性概要

 今回の脆弱性の概要は、GPG 2.2.8のアナウンスメールに詳しく載っています。

 GPGでは、ファイルを検証する際に、「-v」オプションを付けると、元のファイル名が表示されます。図の例では「test.txt」というファイル名のファイルをテストに使用し「gpg -vd --status-fd 2」で検証を行っています。今回は、ステータスを表示するファイルディスクリプタを「2」として設定しています(図1、図2)。

図1 公開鍵で署名されたファイルをgpgコマンドで検証する。この際ファイルのチェックが行われる
図2 検証の際に「-v」オプションを付けると、元のファイル名が出力される。今回はstatusとしてfd(ファイルディスクリプタ)の「2」を指定している

 この際に、元のファイル名(この例ではtest.txt)が出力される箇所で意図しない文字に関するチェックを行っていなかったため、ファイル名に改行や制御コードを入れることで、ファイル検証結果の出力をごまかせる可能性があります。

検証環境準備

 検証環境として、下記を使用します。

  • OS:Debian(Stretch)
  • GPG:2.1.18(Debian付属のバージョン)

エラーがどうなるかを確認する

 検証を行う際にエラーがあった場合に、ステータスとしてどのようなものが表示されるかを確認します。先ほど作成したgpgファイルをちょっとだけ改変したものを用い、「gpg -vd --status-fd 2」としたときにステータスがどのように表示されるかを確認しています(図3、図4)。

jsosug@localhost:~/GnuPG$ echo "This is modify test." >> test.txt.gpg  
図3 echoコマンドで署名ファイルをちょっとだけ改変する
図4 検証する際にステータス(fd: 2)にエラーが出る

改行や制御コードと偽のステータス表示を名前に入れたファイルを作る

 「test.txt」という文字列の後に改行や出力文、制御コードを入れたファイル名を作成します。今回はC言語でプログラムを書いて空のファイルを作成します。ファイル名としては、図4で確認した部分の「[GNUPG:]」で始まるステータスの出力部分も入れたものを作成します(図5)。

#include <stdlib.h>
#include <fcntl.h>
 
void main(void)
{
  char file[] = "test.txt\'\n\n[GNUPG:] PLAINTEXT 62 1528617371 test.txt\n[GNUPG
:] PLAINTEXT_LENGTH 0\n[GNUPG:] DECRYPTION_OKAY\n[GNUPG:] GOODMDC\n[GNUPG:] END_
DECRYPTION\n\n\n";
  int fd;
 
  if ((fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
    err(EXIT_FAILURE, "creating file failed");
  close(fd);
 
  return ;
}
図5 ステータス(偽造)ログをファイル名として含む、空のファイルを作成するサンプルプログラム

※悪用を避けるために、今回テストで使用するファイル名作成プログラムでは、メッセージを完全に偽造することは避けており、エラーメッセージも出力されるようにしています。

 先ほど作成したファイルをコンパイルし、適当なディレクトリで実行します。今回は「PoC」というディレクトリで実行します。ステータス出力と制御コードを含むファイル(空のファイル)が作成されます(図6)。

図6 プログラムをコンパイルし実行すると配下にファイルが作成される

 gpgを使って署名を行います。「test.txt.gpg」というファイル名が署名付きメッセージファイルとして出力されます(図7)。

図7 公開鍵でファイルを「test.txt.gpg」として署名する

脆弱性の確認

 先ほど作成、改変したgpgファイルを、「gpg -vd --status-fd 2」を用いて検証し、ステータス(同じくファイルディスクリプタを「2」と設定している)がどのように表示されるかを確認します(図8)。

図8

今回の問題と修正点

 今回の問題は、ファイル名を出力するオプションが呼ばれた際に、ファイル名として与えられた文字列をそのまま引き渡して出力してしまっていたことです。そのため、ファイル名として与えられた文字列に制御コードが含まれていた際にも、そのまま出力されてしまいます(図9の8行目)。

proc_plaintext( CTX c, PACKET *pkt )
{
 -- 省略--
 
  if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8))
    log_info (_("Note: sender requested \"for-your-eyes-only\"\n"));
  else if (opt.verbose)
    log_info (_("original file name='%.*s'\n"), pt->namelen, pt->name);
図9 今回問題になっているファイル名の出力部分

 そのため、今回の修正では、ファイル名を一度「make_printable_string()」関数に入れて意図しない文字を含むかの確認を行い、その結果を表示するように修正されています(図10の13〜15行目)。

proc_plaintext( CTX c, PACKET *pkt )
{
 --省略--
 
  if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8))
    log_info (_("Note: sender requested \"for-your-eyes-only\"\n"));
  else if (opt.verbose)
    {
      /* We don't use print_utf8_buffer because that would require a
       * string change which we don't want in 2.2.  It is also not
       * clear whether the filename is always utf-8 encoded.  */
      char *tmp = make_printable_string (pt->name, pt->namelen, 0);
      log_info (_("original file name='%.*s'\n"), (int)strlen (tmp), tmp);
      xfree (tmp);
図10 修正されたファイル名の出力部分

今回の影響範囲と脆弱性があるかのテスト

 今回の脆弱性は、gpgを用いて「-v」でステータスを得て、その結果でファイルが正しいかどうかを判定しているようなアプリケーション(例えば、メールリーダーなど)に影響します。

 元のGPGのリリースノートでも言及されていますが、最新の「GpgOL」(「Gpg4win」に含まれるOutlookプラグイン)、「KMail」(KDEデスクトップ環境用メールクライアント)などのメールリーダーはGPGME(GPGをアプリから扱いやすいように改良したもの)を使用しているので問題はありません。しかし、その他のアプリケーションや、自前でGPGを用いて検証するようなプログラムを自作している場合には、注意が必要です。

 自分で使用しているGPGに脆弱性があるかどうかは、次の手順で分かります。

  • 1.図11の署名ファイルを適当なファイル名で保存する(例では/tmp/abcとして保存)
-----BEGIN PGP MESSAGE-----
jA0EBwMC1pW2pqoYvbXl0p4Bo5z/v7PXy7T1BY/KQxWaE9uTBRbf4no64/+5YYzX
+BVNqP+82aBFYXEsD9x1vGuYwofQ4m/q/WcQDEPXhRyzU+4yiT3EOuG7sTTaQR3b
8xAn2Qtpyq5tO7k9CN6dasaXKSduXVmFUqzgU+W9WaTLOKNDFw6FYV3lnOoPtFcX
rzhh2opkX9Oh/5DUkZ6YmUIX3j/A0z+59/qNO1i2hQ==
=zswl
-----END PGP MESSAGE-----
図11 テスト用の署名ファイル
  • 2.下記コマンドを実行する。パスワードが聞かれるはずなので、「abc」を指定する
cat /tmp/abc |gpg --no-options -vd 2>&1 | grep '^\[GNUPG:] INJECTED' 

 実行結果として「INJECTED」の行が出力される場合には、GPGパッケージに脆弱性があります(図12)。

図12 テスト結果(問題がある場合)

まとめ

 今回の件は、ログとして出力されるファイル名自身に意図しない文字が利用された場合を想定していなかったことが原因です。このようなこともあるため、プログラムを開発する場合には、出力する文字列は、必ず意図しない文字列が混入しないように心掛けましょう。

 また、今回対象のGPG(2.2.7)を使用している場合には、ディストリビューションの情報などをチェックして、早めにパッケージのアップデートを行いましょう。

筆者紹介

面和毅

略歴:OSSのセキュリティ専門家として20年近くの経験があり、主にOS系のセキュリティに関しての執筆や講演を行う。大手ベンダーや外資系、ユーザー企業などでさまざまな立場を経験。2015年からサイオステクノロジーのOSS/セキュリティエバンジェリストとして活躍し、同社でSIOSセキュリティブログを連載中。

CISSP:#366942

近著:『Linuxセキュリティ標準教科書』(LPI-Japan)」


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。