.NETセキュリティ

.NET Frameworkに潜む脆弱性「SMTPコマンド・インジェクション」とその対処法

NTTコミュニケーションズ、セキュリティ・オペレーション・センター(SOC)
佐名木 智貴
2011/01/21


.NET TIPS:JISコード(JIS-2022-JP)でメールを送信するには?[2.0のみ、C#、VB]

 JISコードでエンコードされたメールを.NET Frameworkを用いて送信する際には、メール本文の作成にAlternateViewクラス(System.Net.Mail名前空間)を使う(.NET Framework 2.0以降で利用可能)。しかし、このAlternateViewクラスを使ったメール送信機能には、「SMTPコマンド・インジェクション(SMTP Command Injection)」の脆弱(ぜいじゃく)性が潜んでいることが判明したので、その内容と対策を解説する。

 なお、本稿の内容は、2011年1月11日にNTTコミュニケーションズが公表した「.NET Framework 上の SMTP Command Injection」に基づいている。

 この脆弱性を理解するためには、SMTPでのメール送信の仕組みを理解しておく必要がある。

 そこでまずは、SMTP自体についておさらいしてみよう。

SMTPは、改行をコマンドのデリミタとしたテキスト・ベースのプロトコル

コマンドライン・ツールによるSMTPコマンドの指定

 まずは、下の画面を見てほしい。これは「netcat」というUNIX系OS標準のコマンドライン・ツール(=メール送信などのネットワーク処理を扱える。サードパーティによってWindows版も提供されている)を使って、SMTPサーバ(=CentOS 5.1に付属するsendmail 8.13.8)にアクセスしている例である。

コマンドライン・ツール「netcat」によるメール送信例
SMTPでは、このようにテキストを交換しながらメールを送受信している。コマンドラインで呼び出している「nc」は、コマンドライン・ツール「netcat」の.EXEファイルである。
  送信元メール・アドレス指定。メール本文中のFromと区別して、「エンベロープFrom」と呼ばれることもある。
  あて先メール・アドレス指定。メール本文中のToと区別して、「エンベロープTo」と呼ばれることもある。
  DATAコマンドによって、メール・コンテンツを入力開始。
  メール・コンテンツ。この部分だけがあて先に送信される。エンベロープFromやエンベロープToはSMTPサーバには渡されるが、メールのあて先には送信されない。
  「.」(=ドット)だけの行が、メール・コンテンツの入力終了を表す。これを受け取るとメール・サーバは実際にメールを送信する。

 「MAIL FROM」(=送信元)や「RCPT TO」(=あて先)などのコマンドで指定しているテキストが、メール・クライアント(この画面では「netcat」)からSMTPサーバへ送り出しているデータで、送信元やあて先をSMTPサーバへ知らせている(これらはエンベロープFromやエンベロープToと呼ばれる)。

 さらに「DATA」コマンドによって、メール・コンテンツの入力を開始する。次の行の「end with "." on a line by itself」というSMTPサーバからの応答の後に、「From」や「To」などのメール・コンテンツのヘッダ(いわゆるメーラで見ることができる「ヘッダ情報」)やメール本文を入力している。最後に「.」(=ドット)だけの行を入力して「DATA」コマンドによるメール・コンテンツ入力を終了させる。これを受け取ると、SMTPサーバは受信したメールの配送を開始する。

 SMTPクライアントとSMTPサーバは、このようなテキスト情報のやり取りによってメールの送受信を行っている。

 これらのやり取りをアプリケーション・プログラマーに隠ぺいしているのが、メール送受信を扱う各種のライブラリである。

テキスト・ファイルによる一連のSMTPコマンドの一括指定

 また、一般的なメール・サーバであれば、事前に一連のSMTPコマンドをテキスト・ファイルに用意しておき、それをSMTPサーバに与えることでも、メールの送信は可能である。このような機能は、バッチ処理などに活用できるだろう。次の画面はその例である。

テキスト・ファイルによるメール送信例
一連のSMTPコマンドを記載したテキスト・ファイル(この例では「a.txt」)を用意し、それをSMTPサーバに与えてもメールの送信は可能である。コマンドラインで呼び出している「nc」は、コマンドライン・ツール「netcat」の.EXEファイルである。またSMTPサーバは前述のCentOS上のsendmailを用いている。

 しかし、Windows Server 2003 R2 SP2上のSMTPサービス(=IIS 6.0に付属している)でテキスト・ファイルによるメール送信を行った場合、下の画面のように、「DATA」コマンド以降は読み込み待機となるようで処理が停止してしまう。結果としてメールが送信できない。

Windows Server 2003 R2 SP2上のSMTPサービスでのテキスト・ファイルによるメール送信例(=送信失敗)
IISのSMTPの場合、「DATA」コマンドの後で処理が停止してしまった。このように、SMTPコマンドの入力と応答の交換状態を管理しているようなSMTPサーバ(IISなど)の場合は、SMTPコマンド・インジェクションの危険性は比較的低い。

 このような(テキスト・ファイルによるメール送信に対応していない)タイプのSMTPサーバが使用されている場合、本稿で説明するSMTPコマンド・インジェクションの影響はない(ただし、「.」だけの行によって、それ以降のメール本文をメールから切り捨てさせるなどの行為は可能*1)。

*1 メールのフッタには問い合わせ先などが書かれている場合が多いので、肝心な部分が切られてしまう可能性がある。

隠しドット・アルゴリズム(hidden dot algorithm)

 さて、(前述のとおり)「DATA」コマンドは「.」だけの行が与えられると終了する。となると、「.」だけの行を含んだメール本文を送信したい場合は、どうすればいいのだろうか。答えは「.」を「..」=(ドット2個)に置換する、である。ただしこれでは「..」という行を送りたいときに区別が付かなくなってしまう。そこでDATAコマンドを使う場合は、行の長さに関係なく、行頭に「.」があれば常に「..」に変換してから送ると決められている。そしてメールを受信した側では、行頭の「..」を「.」に戻すことにしている(正確には、「.」で始まり、任意の文字が続く行は、先頭の「.」を除去する。例えば「.NET」は「NET」になる)。こうすれば「.」ならDATAコマンドの終了、「..〜」ならメール本文の一部というふうに区別できる。

 このエスケープ処理(=送信時には行頭の「.」を「..」に置換して、受信時には行頭の「.」を除去する処理)を「hidden dot algorithm」(以下、隠しドット・アルゴリズム)と呼ぶ(RFC821のセクション「4.5.2. 透過」参照)。次の画面は、隠しドット・アルゴリズムによるエスケープ処理の例である。

隠しドット・アルゴリズムによるエスケープ処理の例
例えば「.NET Framework」など行頭が「.」で始まる1文をメールで送信したい場合は、それを「..NET Framework」と入力すればよい。
  行頭が「.」の場合は、「..」とドットを重ねる必要がある。
  「.」だけの行は、DATAコマンドの終了を表す。

 次の画面は、「.NET Framework」という1文を「..NET Framework」にエスケープ処理したメールを送信し、それをメール・クライアントにより受信して、そのメール内容を表示した例だ。

隠しドット・アルゴリズムに対してのエスケープ処理が施されたメールの受信結果

 このように、「DATA」コマンドに「..NET Framework」と入力されたメール(=エスケープ処理されたメール)は、受信時に行頭の「.」が1つ消えて(=隠しドット・アルゴリズム)、「.NET Framework」というメール本文となる。

SMTPコマンド・インジェクションと対策方法

メール送信でのSMTPコマンド・インジェクションとは?

 実は、.NET FrameworkのAlternateViewクラスのCreateAlternateViewFromStringメソッドには、このエスケープ処理が実装されていない。よって、「このメソッドを使っている.NET Framework上のアプリケーションに対して、細工したメール本文を与えれば、任意のSMTPコマンド(具体的にはスパム・メールをばらまくこと)が実行できる」(=SMTPコマンド・インジェクション)という脆弱性が存在するのである。

 「.NET Framework 上の SMTP Command Injection」にあるエクスプロイト・コード(Exploit Code)(=セキュリティ・ホールを攻撃するプログラム)を実行した結果が、下の画面になる。

SMTPコマンド・インジェクションによる別メールの送信
エクスプロイト・コードを実行した例。本来のメールに加え、別のメール(計2通)が送信される。
  ここが「DATA」コマンドに与えられるメール・コンテンツ部分。「.」のエスケープ処理が行われないので、この表示内容のままDATAコマンドに与えられる。

 このようなメール・コンテンツを送信すると、メール本文中の「.」だけの行によって「DATA」コマンドは終了し、それ以降がSMTPのコマンドとして解釈されてしまう。正しくは、1通のメールとして送られなければならないのに、この例ではSMTPコマンド・インジェクションにより、もう1通、別のメールを送るSMTPコマンドが実行されている。

SMTPコマンド・インジェクションにより送信されたメールの受信

 上のSMTPコマンド・インジェクションによって送信されたメールをメール・クライアントで受信した結果が、次の画面である。

SMTPコマンド・インジェクションにより送信された別メールの受信
上記のエクスプロイト・コードの実行結果。題名が「TESTPart1」である本来のメールとは別に、「NewMailInFile」という題名のメールも受信したことが分かる。

 このように2通のメールを受信していることから、SMTPコマンド・インジェクションが成功していることが分かる。メール本文(の一部)をユーザーが入力できるようなシステムがあったとすると、この脆弱性を使って(テキストの途中に「.」だけの行と、新しいSMTPコマンドなどを仕組んでおくと)、任意のあて先にスパム・メールを送ることが可能となってしまう。

SMTPコマンド・インジェクションの対策方法

 ちなみに、今回の例で実装したエクスプロイト・コードはコンソール・プログラムであるが、AlternateViewクラスを用いるASP.NETなどでも再現可能であるため、注意が必要だ(実際、筆者が最初に確認したのは、ASP.NETで構築されたWebアプリケーションのセキュリティ診断中であった*2)。

*2 その顧客はすでにエスケープ処理を実施対処済みである。

 マイクロソフト社に問い合わせたところ、.NET Frameworkの次期バージョン(4.5?)では対応するが、既存の.NET Framework(2.0/3.0/3.5/4.0)に対して修正プログラムを配布する予定はないとのことである。

 つまり、.NET FrameworkのAlternateViewクラスを使ってメール送信処理を開発しているアプリケーション・プログラマーは、CreateAlternateViewFromStringメソッドにメール本文を渡す前に自分自身でエスケープ処理、つまり行頭の「.」を「..」に置換する処理を、各自で実装する必要があるということだ。また、この対策を行わないと、SMTPコマンド・インジェクションの脆弱性が生じるだけでなく、メール本文中に「.」から始まる行を含むメールは正しく送信できない。このため、この問題は機能上の不具合にもなってしまうのである。

 実際にC#/Visual Basicでその処理コードを記述すると、次のようになる。

String body = ".NET Frameworkなどのメール本文";
body = "\n" + body;                  // 1行目の先頭に改行を入れる
body = body.Replace("\n.","\n..");   // エスケープ処理
body = body.Substring("\n".Length);  // 1行目の先頭の改行を削除
Dim body As String = ".NET Frameworkなどのメール本文"
body = vbLf & body                   ' 1行目の先頭に改行を入れる
body = body.Replace(vbLf & ".", vbLf & "..")  ' エスケープ処理
body = body.Substring(vbLf.Length)   ' 1行目の先頭の改行を削除
CreateAlternateViewFromStringメソッドにメール本文を与える前にエスケープ処理を行うサンプル・コード(上:C#、下:VB)

 エスケープ処理の適用を「行頭」に制限するために、「\n.」(=改行とドットの組み合わせ)を置換するようにしている。

 この例では、1行目の先頭に「\n」を付与して置換処理を行い、最終的に先頭行に付与したその「\n」を取り除く、という処理を実装している。このようにしているのは、1行目の先頭の「.」もエスケープ処理するためである。

 なお、このような処理コードを既存の.NET Framework 2.0/3.0/3.5/4.0向けに追加した場合、これが次期.NET Framework(4.5?以降)で実行されたときには動作しないようにする条件分岐が必要になる(参考:「.NET TIPS:ビルド時および実行時のCLRバージョンを取得するには?」)。次期.NET FrameworkでCreateAlternateViewFromStringメソッドがこの問題に対応した場合、上記のエスケープ処理により、先頭に余計な「.」が増えてしまう結果となることに留意してほしい(つまり、この処理が将来的にバグになってしまう可能性がある)。

まとめ

 個人的には、既存バージョンの.NET Frameworkにも修正プログラムを提供すべきではないかと思う。しかし、マイクロソフト社が「提供しない」と決断した以上、.NET Framework上でアプリケーションを開発しているプログラマーは、自分自身で対処しなければならない。

 また、AlternateViewクラスだけではなく、Attachmentクラス(System.Net.Mail名前空間)のCreateAttachmentFromStringメソッドにも同様の脆弱性がある。

 さらに、まれな状況とは思うが、添付ファイルをBase64などでエンコード処理を行わない場合、つまりAttachmentクラスを使ってファイルを添付する際にも、ファイル内容にSMTPコマンドを仕込むことで、同様の脆弱性が発現してしまう。ファイルを添付する際には、素直にBase64などでエンコードすることを筆者は推奨する。end of article

インデックス・ページヘ  「.NETセキュリティ」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間