All Articles

HackTheBox 「Blue」で学ぶ EternalBlue 脆弱性

「Hack The Box」という、ペネトレーションテストの学習プラットフォームを利用してセキュリティについて学んでいます。 「Hack The Box」のランクは、本記事執筆時点でProHackerです。

Hack The Box

この記事では、HackTheBoxのマシン攻略を通して「EternalBlue」に関連した攻撃方法について勉強したことをまとめていきます。

社会的に大きな被害を与えた「EternalBlue」に関連した攻撃について理解すべく、勉強したことをまとめていきます。

「EternalBlue」は、世界中で猛威を奮ったランサムウェア「WannaCry」の拡散の要因となったことでも知られています。

本記事について

本記事の内容は社会秩序に反する行為を推奨することを目的としたものではございません。

自身の所有する環境、もしくは許可された環境以外への攻撃の試行は、「不正アクセス行為の禁止等に関する法律(不正アクセス禁止法)」に違反する可能性があること、予めご留意ください。

またすべての発言は所属団体ではなく個人に帰属します。

もくじ

本記事のテーマ

今回のテーマは、「EternalBlue」の再現を通して、脆弱性の詳細と悪用方法について学び、セキュリティ対策に活用することです。

EternalBlueとは

EternalBlueは、Windows SMB1.0に存在したセキュリティ上の欠陥を利用した攻撃ツールを指します。

EternalBlueでは、「Windows SMB1.0(SMBv1)」の欠陥を悪用することで、攻撃者が任意のコードを実行できるようにします。

EternalBlueは、2017 年 3 月に公開された更新プログラム「MS17-010」によって解決されています。 参考:マイクロソフト セキュリティ情報 MS17-010 - 緊急 | Microsoft Docs

EternalBlueは、世界中で猛威を振るったランサムウェア「WannaCry」に利用され、世界中で約230,000台ものコンピューターに被害を及ぼし、世界中で猛威を振るった「WannaCry」による被害額は、合計で40億ドルに及んだと推計されているようです。

日本国内でも、日立製作所など、多くの企業が被害にあっています。

参考:ランサムウェア「WannaCry」 のすべて | カスペルスキー 参考:日立は「WannaCry」被害から何を学んだのか、IoTセキュリティサービスに昇華:IoTセキュリティ(1/2 ページ) - MONOist

EternalBlueは、「Shadow Brokers」と呼ばれるハッカー集団が流出された攻撃ツールに含まれていました。 これらの攻撃ツールは米国のNSAから流出したものと言われているようですが、真偽は不明です。

また、インターネットで検索すると、EternalBlueを脆弱性としているページとEternalBlueを脆弱性としているページが混在していますが、ESETやTrendmiroのレポートから、EternalBlueは「MS17-010」に関連した脆弱性を悪用するエクスプロイトという認識が正しそうです。

参考:One year later: EternalBlue exploit more popular now than during WannaCryptor outbreak | WeLiveSecurity 参考:トレンドマイクロ セキュリティブログ「WannaCry」を拡散させた脆弱性攻撃「EternalBlue」の仕組みを解説 | トレンドマイクロ セキュリティブログ

興味深い点としては、EternalBlueが公に流出した時点ではすでに「MS17-010」のパッチが提供されていたことです。

参考:Protecting customers and evaluating risk – Microsoft Security Response Center

脆弱性の修正パッチが提供されていたにも関わらず、EternalBlueは世界中で悪用されてしまいました。 また、Avastの調査によると、「WannaCry」の流行後一年が経過しても、全世界のWindowsPCの29%にパッチが適用されておらず、脆弱性が残存していたようです。

Criticalな脆弱性に対するパッチを適用さえしていれば、自端末の感染、もしくは少なくとも感染拡大については抑制が可能であったことを考えると、教訓とすべき事例なのかもしれません。

EternalBlueのメカニズム

さて、ではEternalBlueの攻撃メカニズムについて詳細を見ていきたいと思います。

EternalBlueは、「Windows SMB1.0(SMBv1)」のカーネル関数「srv!SrvOs2FeaListToNt」による「File ExtendedAttribute(拡張ファイル属性、FEA)」処理時に「Large Non-PagedPool(ラージ非ページプール)領域」のバッファオーバーフローを発生させる脆弱性です。

具体的には、カーネル関数「srv!SrvOs2FeaListToNt」にて、FEA(拡張ファイル属性) を「NTFEA(Windows NT FEA)」に変換する際、関数「srv!SrvOs2FeaListSizeToNt」を呼び出して FEA(拡張ファイル属性)リストのサイズを計算する際の不具合に起因したオーバーフローが発生します。

Trendmiroの調査によると、以下のフローでオーバーフローが発生するようです。

  1. 関数「srv!SrvOs2FeaListSizeToNt」がFEA リストのサイズを計算し、受け取った FEA リストのサイズを更新する。
  2. この時、間違ったデータ型(WORD型、2 バイトの符号なし整数を扱う C 言語のデータ型)への型変換により、FEA のサイズが元の値より大きくなる。
  3. 不正確なリストサイズにより、FEA リストを NTFEA リストに変換する繰り返し処理時、非ページプール上でオーバーフローが発生する。

引用:トレンドマイクロ セキュリティブログ「WannaCry」を拡散させた脆弱性攻撃「EternalBlue」の仕組みを解説 | トレンドマイクロ セキュリティブログ

File ExtendedAttribute(拡張ファイル属性、FEA)とは

さて、EternalBuleで悪用される脆弱性を持つFEA(拡張ファイル属性)とはそもそも何でしょうか。

RFC8276によると、この拡張ファイル属性は、ファイルシステムによって解釈されない不透明なメタデータをファイルおよびディレクトリに関連付けるために提供されるもののようです。

つまり、ファイルシステムが解釈しないメタデータをユーザ側がファイルと紐づけることができる仕組みというイメージでしょうか。

一方で、ファイルの権限やatime、ctimeなどの属性は、通常の属性としてファイルシステムにより厳密に定義されているものとしてFEAとは区別されているようです。

参考:

srv!SrvOs2FeaListSizeToNt 関数

EternalBuleでは、srv!SrvOs2FeaListSizeToNt関数が計算したFEAリストのサイズを処理した際に生じるバッファオーバーフローの脆弱性を悪用します。

srv!SrvOs2FeaListSizeToNt関数は、SMBプロトコルのためのカーネルドライバであるSRV.sysに含まれる関数で、OS/2 FEAリストをNT FEAリスト変換するための機能を持っています。

参考:

SMBプロトコルについて

EternalBuleで悪用される、srv!SrvOs2FeaListSizeToNt関数は、SMBプロトコルが利用するSRV.sysというカーネルドライバに存在することがわかりました。

しかし、そもそもSMBプロトコルとはなんでしょうか(知らない)。 よく名前は聞きますが、いまいち実態がつかめないプロトコルです。

SMBプロトコルは、Windowsを中心とした環境において、ファイル共有やプリンタ共有などに使用される通信プロトコルの総称、だそうです。

SMBプロトコルは、複数のプロトコル上で動作することが可能で、SMBv1はダイレクトホスティングSMBという機能により、ポート445を利用してTCP上で直接動作することも可能になりました。

SMBプロトコルはもともと、OS/2ベースのファイルサーバーOSで動作していたファイルサーバのファイル共有用プロトコルでしたが、Windows 3.xや9xからファイルサーバー機能が搭載されるようになったことで、一般的に利用されるようになりました。

srv!SrvOs2FeaListSizeToNtがOS/2 FEAリストをNT FEAリスト変換する処理を行っているのは、こういう歴史的な背景もありそうです。

参考:

EternalBlueの検証環境

さて、EternalBuleの悪用方法や環境についてのリサーチが大体できたところで、実際に攻撃手法を検証していきたいと思います。

今回はEternalBuleの検証のため、次の環境を準備しました。

ターゲットマシン(仮想マシン)

  • Windows7 64bit (IP:169.254.100.60)

    kd> vertarget
    
    Windows 7 Kernel Version 7601 (Service Pack 1) MP (1 procs) Free x64
    Built by: 7601.17514.amd64fre.win7sp1_rtm.101119-1850
    Machine Name:
    Kernel base = 0xfffff800`02e1f000 PsLoadedModuleList = 0xfffff800`03064e90
    Debug session time: Mon Apr 26 01:19:52.742 2021 (UTC + 9:00)
    System Uptime: 0 days 0:08:03.468

攻撃マシン(仮想マシン)

  • Parrot OS(IP:169.254.100.10)
  • WireShark

デバッグマシン(ホスト)

  • Windows 10 Pro 20H2
  • Hyper-V
  • WinDbg 10.0.19041.685 X86

ターゲットマシンの準備

カーネルモードデバッグの有効化

まずはターゲットマシンのWindows7にて、カーネルデバッグを有効にします。

今回のターゲットマシンはHyper-Vで構築した仮想マシンなので、デバッグのためのシリアルポートを名前付きパイプとして設定します。

image-20210425142147502

次に、ターゲットマシンにログインして、カーネルモードのデバッグを有効にします。

管理者権限で起動したコマンドプロンプトで以下のコマンドを実行することで有効化できます。

bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
shutdown /r /t 0

Msconfig.exeを起動して、詳細オプションからCOM1ポートを指定してデバッグを有効した後に再起動してもOKです。

SMVv1の稼働確認

次に、ターゲットホストのWindows7にて、SMVv1が有効になっていることを確認します。

以下のコマンドの出力結果に、DEPENDENCIES: MRxSmb10存在するとSMB1.0が有効になっていると判断できます。

sc.exe qc lanmanworkstation

image-20210425111203549

これでターゲットマシン側の準備は完了しました。

WinDbgを利用したカーネルデバッグ

インストール

ホスト側のWindows10にWinDbgをセットアップして、ターゲットマシンのカーネルデバッグを行います。

WinDbgは、Debugging Tools for Windowsに含まれるカーネルモードおよびユーザーモードのデバッガです。 WinDbgを利用することで、Windowsシステムドライバのデバッグも可能になります。

本記事執筆時点でWinDbgをセットアップする方法は、大きく以下の2通りあります。

  1. Microsoft Storeから、Download WinDbg(Preview)のUWPアプリを入手する
  2. Windows 10 SDKから、Debugging Tools for Windowsが含まれるWindows SDKを入手する

参考:Download Debugging Tools for Windows - WinDbg - Windows drivers | Microsoft Docs

簡単なのはMicrosoft Storeから、プレビュービルドのWinDbgを入手する方法ですが、まだ正式リリース前ということもあり、不具合が多いためWindows SDKをインストールする方が無難に使用可能です。

Debugging Tools for Windowsのチェックボックスを有効化した状態でWindows SDKのインストールが完了すると、C:\Program Files (x86)\Windows Kits\というフォルダが作成されます。

WinDbgは、この中に含まれます。

今回のターゲットマシンは64bit版のWindow7なので、C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\内にあるWinDbgを使用します。

WinDbgによるターゲットマシンへの接続

ダウンロードしたC:\Program Files (x86)\Windows Kits\10\Debuggers\x64\内のWinDbgを、管理者権限で起動します。

この際、一般ユーザ権限で起動すると、ターゲットマシンのカーネルデバッグ接続時にKernel debugger failed initialization, Win32 error 5 アクセス拒否されましたというエラーが発生して、カーネルデバッグに失敗するので注意してください。

WinDbgを管理者権限で起動したら、[File]>[Kernel Debug]を選択し、以下の画像のように名前付きパイプを利用してターゲットマシンに接続させます。

image-20210425143834960

プロンプトが起動し、dt nt!_*を実行したときに以下のようにシンボルリストが出力されれば接続は成功です。

image-20210425144046592

初回接続時にはまだターゲットマシンのカーネルが稼働しているため、Busy状態と表示され、コマンドが入力できない状態になっているかと思います。

WinDbgからコマンド操作ができるようにするためには、Ctrl+Break(Breakキーがない場合は、Ctrl+Fn+Bなど)か、Breakボタンをクリックします。

なお、カーネルデバッグ実行中は、ターゲットマシンの操作は不可能になるため、ターゲットマシンを再度操作する場合は、F5キーかGoボタンをクリックします。

image-20210425144334695

脆弱性を悪用してリバースシェルを取得

カーネルドライバの動きを確認する準備ができたところで、さっそくEternalBuleの攻撃を再現していきます。

攻撃には、Metasploitのwindows/smb/ms17_010_eternalblueを使用します。

攻撃サーバからエクスプロイトを実行すると、Root権限のシェルを取得することができました。

image-20210426105539203

これで、今回構築した環境でEternalBuleの攻撃が再現できることが確認できました。

WinDbgで、カーネルデバッグを実践

さて、それではいよいよエクスプロイト実行時のSRV.sysの動きをWinDbgで見てみます。

カーネルドライバのデバッグを行うので、Windows ドライバーのデバッグの手順を参考に進めました。

まずは、デバッガーマークアップ言語 (DML) を有効にした後に、コマンドリファレンスヘルプを表示します。

このヘルプが非常に役に立ちます。

kd> .prefer_dml 1
kd> .hh .prefer_dml

次に、読み込まれているカーネルモジュールの一覧をlmコマンドで表示します。

モジュールがいくつも表示されますが、この中から、今回のターゲットであるSRV.sysを特定します。 Ctrl+fで文字列検索ができます。

image-20210425201017305

SRV.sysらしきものが見つかったので、クリックしてみると次のような詳細が表示されました。

kd> lmDvmsrv
Browse full module list
start    end        module name
93269000 932ba000   srv        (deferred)             
    Image path: \SystemRoot\System32\DRIVERS\srv.sys
    Image name: srv.sys
    Browse all global symbols  functions  data
    Timestamp:        Sat Nov 20 17:45:29 2010 (4CE78AA9)
    CheckSum:         0005542B
    ImageSize:        00051000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
    Information from resource tables

どうやら93269000からのアドレスにSRV.sysが配置されているようです。

次に、SRV.sysの中から、問題のある関数のアドレスを特定していきます。 srv!a*コマンドを実行すると、SRV.sysの持つ関数がアルファベット別に表示されました。

脆弱性のある関数はSrvOs2FeaListSizeToNtですが、問題の関数はsrv!SrvSmbOpen2から呼び出されるため、まずはsrv!SrvSmbOpen2のアドレスを特定しました。

image-20210425201740669

932a156fsrv!SrvSmbOpen2が配置されていることがわかったので、以下のコマンドで関数にブレークポイントを仕掛けます。

bp srv!SrvSmbOpen2

ブレークポイントは、blコマンドか、Disassemblyウィンドウから確認可能です。

Alt+Shift+7キーでDisassemblyウィンドウを開くと、ブレークポイントが設定されたアドレスがハイライトされます。

image-20210426012153835

ここで、エクスプロイトを再実行すると、ブレークポイントに設定したカーネル関数が呼び出されたタイミングで、処理を停止し、デバッグモードに移行することが確認できました。

image-20210426012304866

これで、WinDbgによるカーネルデバッグの準備は完了です。

悪用時の通信を追う

EternalBule攻撃時のメモリの動きを追う前に、どのような攻撃パケットが送り込まれているのか、通信の中身をのぞいてみようと思います。

攻撃サーバからのSMB通信

意外なことに、攻撃サーバから送り込まれてきたSMBパケットは40件程度と少なかったので、まずはここから見ていきます。

image-20210426110622437

まず着目したのは、攻撃サーバからの不審なNT Trans Requestです。

パケット情報を見ると、Total Data Count66512に設定されています。 そして、SMBヘッダー直後のデータが0x00010000に設定され、それ以降大量のデータが連続して送信されています。

image-20210426132307955

この値、0x00010000は、EternalBlueが悪用するバッファオーバーフロー脆弱性のポイントになるSizeOfListInBytesであり、それ以降の空のデータは加工されたFEAリストのようです。

このSizeOfListInBytesの情報から、SMB ドライバが FEA リストを NTFEA リストに変換する際に必要なメモリのバッファ領域を確保します。

このバッファ領域の確保のために、脆弱性を持つsrv!SrvOs2FeaListSizeToNtが呼び出されるようです。

参考:Virus Bulletin :: EternalBlue: a prominent threat actor of 2017–2018

次に、Total Data Count4096である Trans2 Secondary Requestが15回連続で送信されています。

これ、最初は何をしているのかさっぱりわからなかったのですが、どうやら脆弱性の悪用のために、先ほどの空のFEAレコードを605個送ったあと、加工された0xf383 + 5の大きさの606個目のFEAレコードと、0xa8 + 5の大きさの607個目のFEAレコードを送付する必要があるようです。

image-20210426133625120

606個目のFEAレコードと、607個目のFEAレコードのサイズを合計すると、10進数で62517となり、ちょうど4096バイトのパケット15個分になりました。

ここで、607個目のFEAレコードが送信された時点で、SizeOfListInBytesで指定した0x10000の領域を超えて、次のメモリ領域である「SRVNET.sys」のプールを上書きすることでバッファオーバーフローが成立する流れのようです。

バッファオーバーフロー時のカーネルデバッグ

では最後に、この607個目のレコードの送付によって、SRVNET バッファと SRVNET の一部が上書きされるところをカーネルデバッグで観察してみたいと思います。

ブレークポイントは、こんな感じで設定してみました。

bp srv!SrvOs2FeaToNt+04d “.printf \”MOV2: dst: %p src: %p size:%p\\n\”,ebx,eax,poi(esp+8);g;”

bp srv!SrvOs2FeaListToNt+0xd4

image-20210426140721254

ブレークポイントで止まるタイミングでddコマンドを使ってメモリの中身をのぞいてみると、0で埋まっています。

image-20210426143302073

アドレスの番地も+5ずつ増えていることから、これが空のFEAレコードで埋められている部分と考えてよさそうです(多分)

これが605回続くと結構大変なので、一旦srv!SrvOs2FeaListToNt+0xd4のブレークポイントを解除して、関数終了前のsrv!SrvOs2FeaListToNt+0x120に設定しなおしました。

そのまま最後までエクスプロイトを実行させたあと607回上記の処理が実行されたことを確認し、出力結果を取得しました。

最終的に607回目のレコードがfffffa8001c9b000という、ひとつ前のアドレスに0xf383 + 0x5 + 0x5した値からコピーされており、ここから607個目のFEAによるオーバーフローが実行されていそうです。

image-20210426175537572

最後にこのアドレスから+a8内のメモリ情報を出力することで、オーバーフローによるエクスプロイトが成功したことを確認したかったのですが、いかんせんバイナリ列を見ても上書きが成功しているかどうかの判断がつかず、断念しました。。。

そのうちカーネルデバッグの知識が身についてから再トライしようと思います。

まとめ

今回は、「EternalBlue」の再現を通して、脆弱性の詳細と悪用方法について学ぶことを目的に色々検証した結果についてまとめました。

Windowsのカーネルデバッグについては全くの初めてだったこともあり、手探りで進めたため結構時間がかかりました。

HackTheBoxのマシンを攻略するだけでなく、そこで利用した脆弱性について深堀りしてみることは非常に学びになるなと思います。

特に今回テーマにした「EternalBlue」は、MetasploitやExploitDBのコードを使うと簡単に再現できてしまうため、マシン攻略としての難易度は非常に低いのですが、脆弱性の詳細をちゃんと理解することは結構難しいと感じました。

脆弱性の深堀り記事は今後も書いていきたいと思います。 通信プロトコル系はまだちょっと難しいということを改めて実感したので、もっとライトに検証できるOSSなどから攻めてみようかと感じています。

参考

Book

Web