実戦形式で学ぶホワイトハッカーの技術

初心者向けのEthical Hacking講座です。

ディレクトリトラバーサル

次はディレクトリトラバーサルについて学びましょう。

ディレクトリトラバーサル(「パストラバーサル」とも呼ばれる)は、アプリケーション上で発生する脆弱性の1つで、攻撃者が制限されているはずのディレクトリ外のファイルやディレクトリにアクセスする能力を持つことを指します。この脆弱性は主にWebアプリに見られることが多く、適切な入力検証やサニタイジングが行われていない場合に発生します。

まずディレクトリトラバーサルを理解するうえで、ファイルパスについて理解する必要があります。
ファイルパスとは例えば下記の様なものです。

┌──(kali㉿kali)-[~]
└─$ pwd
/home/kali

pwd」コマンドを実行してみると、「/home/kali」という結果が得られました。
これはルートディレクトリ(/)の中のhomeディレクトリの中のkaliディレクトリに現在いるということです。

では今のディレクトリから1つ上のディレクトリ(上位ディレクトリ)に行くにはどうすればいいでしょうか?
コマンドライン操作に慣れている方にとっては簡単すぎる質問だと思いますが、1つ上のディレクトリに行くには下記の様に「cd」コマンドを実行します。

┌──(kali㉿kali)-[~]
└─$ cd ..

上記の様に「..」にて、1つ上のディレクトリに移動することが可能です。
これは下記のファイルパスがすべて同じディレクトリであることを意味します。

/home/
/home/kali/../
/home/kali/Downloads/../../

上記は全てhomeディレクトリを表します。
つまり「..」の回数分だけ1つ上のディレクトリに戻っているようなイメージです。

では実際にディレクトリトラバーサルを攻撃してみて理解を深めましょう。

ディレクトリトラバーサル(Level1)

まずは「ことわざ選択プログラム」の挙動を見てみましょう。
どうやら3つのことわざから1つ選択し、送信ボタンを押すとそのことわざの中身が返ってくるプログラムのようです。

ことわざ

実際にどのようなデータを送っているかBurp Suiteで見てみましょう。

ことわざ - Burp Suite

すると「filename」パラメータとしてファイル名を送信しているようです。
このようにファイル名を送信しているときは特に、ディレクトリトラバーサルを疑うべきです。
今回は一部サーバーサイドのソースコードを見てみましょう。

  var userInput = req.body.filename;
  var rootdir = "./kotowaza/";
  var filename = path.join(rootdir, userInput);

どうやら、送信されたファイル名と「kotowaza」ディレクトリを結合しているようです。
ではこの記事でお伝えしたファイルパスの知識を応用してみましょう。

filename=../../../../../../etc/passwd

これがユーザーのインプットであると、実は最終的なファイルは「/etc/passwd」になります。

というのは、まず上記のプログラムではカレントディレクトリにある「kotowaza」とユーザーからのファイル名を結合しています。
そして上記の例では、ファイル名が「../../../../../../etc/passwd」となっており、この2つが結合されるとカレントディレクトリ内の「kotowaza」ディレクトリから6つ上位のディレクトリに移動した先の「/etc/passwd」が最終的に表示するファイルになります。
カレントディレクトリがどこかは分かりませんが、6つ上位のディレクトリに移動することで大抵はルートディレクトリにたどり着けます。もちろんルートディレクトリに確実に到達するために、下記の様なペイロードで安全を期すこともできます。

filename=../../../../../../../../../../../etc/passwd

そして、「etc」はルートディレクトリ内にあるディレクトリです。
ですので、先ほどのペイロードディレクトリトラバーサルを発生させることで、本来ことわざしか見られないはずが、サーバーのあらゆるファイルを閲覧することが可能になります。(厳密にはWebアプリを実行しているユーザーの権限で閲覧できるファイルです。)
実際に先ほどのペイロードを送信してみると以下のようになります。

/etc/passwd

レスポンスとして「/etc/passwd」が返ってきました。
ディレクトリトラバーサルでは、「/etc/passwd」だけでなく様々なファイルへのアクセスが可能です。攻撃者がどのようなファイルを閲覧するのか気になる方は、下記リンクに飛んでみてください。
sushant747.gitbooks.io

ディレクトリトラバーサルは、機密情報の漏えいにつながることはもちろんのこと、例えばSSHのプライベートキーを漏えいしてしまうと、サーバーへの侵入が成立するおそれもあります。
SSHのプライベートキーは通常、「/home/username/.ssh/id_rsa」です。仮にディレクトリトラバーサルによってid_rsaが読み取れた場合、ターゲットのサーバーへ下記コマンドでログイン(侵入)することができます。

ssh -i id_rsa <username>@<ip address>

SSH秘密鍵にはパスフレーズを設定することも可能なため、id_rsaを入手しただけではログインできないこともありますが、パスフレーズの強度が弱いとクラックすることができます。

ディレクトリトラバーサル(Level2)

では続いてLevel2に突入しましょう。
Level2でも先ほどと同じペイロードを送信してみましょう。
すると、「Can't read this file.」というエラーが発生します。

Can't read this file

このエラーが発生する原因は不明ですが、何かしらの対策が講じられている可能性を考えましょう。
今回はソースコードをお見せするので、どのように回避できるのか考えましょう。

  var userInput = req.body.filename;
  userInput = userInput.replace(/\.\.\//g, "");
  var rootdir = "./kotowaza/";
  var filename = path.join(rootdir, userInput);

Level1の時との違いは、2行目です。
エスケープ処理が施されているため少しわかりにくいですが、「../」を「」に置換するという意味になります。(実質消すということです。)
さらに今回はXSSの時と違って、「../」がユーザーのインプットに存在すれば何度でも置換を行います。つまり一度だけ置換を行っているわけではないということです。
XSSの時とは別の回避方法を考えましょう。

では正解発表です。

filename=....//....//....//....//....//....//etc/passwd

上記のペイロードを考えてみましょう。
先ほどお伝えしたように、Level2では「../」を「」へと置換します。実際に上記のペイロードから「../」を削除してみてください。
するとLevel1の時と同じペイロードになります。

filename=../../../../../../etc/passwd

実際に送信してみると、「/etc/passwd」がLevel1の時と同じように返ってきます。

/etc/passwd

一見すると「../」を封じられるとディレクトリトラバーサルは成立しないように思えますが、攻撃者は容易に回避することが可能です。
今回は「/etc/passwd」を閲覧するところで止めましたが、ディレクトリトラバーサルソースコード秘密鍵の漏えいに繋がる重大な脆弱性です。しっかりとした対策を講じる必要があります。

対策

対策方法は大きく分けて2つです。
1つはホワイトリストです。今回であればユーザーのインプットは3種類のファイル名のみのはずです。
ですので「kotowaza1.txt」「kotowaza2.txt」「kotowaza3.txt」のみを許可すればよいわけです。
しかし実際のプログラムではそのようなホワイトリストを使えない場面も多いでしょう。

そこで2つ目の対策方法はパスのノーマライズです。
簡単に言うと、「.」や「..」が含まれていた場合に、含まれない形のパスに変換することです。
例えば下記の様になります

ノーマライズする前
data/doc/../pdf/report.pdf

ノーマライズした後
data/pdf/report.pdf

「data/doc/../pdf/report.pdf」がユーザーのインプットであった場合、「data/pdf/report.pdf」へとパスをノーマライズすればよいわけです。

 var userInput = req.body.filename;
 var normalizedPath = path.normalize(userInput);

上記の様にユーザーのインプットを先にノーマライズしておくことで、後ほどディレクトリと結合する際にディレクトリトラバーサルが発生することがなくなります。

お疲れ様でした。
次はブルートフォース攻撃です。

learn-ethicalhacking.hatenablog.com