2024/09/24-26開催予定 @ 静岡大学情報学部
まず最初に十分理解していいただきたいのは,以下の実験内容は教育目的であって絶対に悪用しないでください.
インターネット上には,ポートスキャン方法やクラッキング方法など様々な情報が氾濫していますが,本実験環境のローカルネットワーク内における実験用サーバに対してのみ試してみて構いませんが,そのからくりを理解できていない人は周囲に迷惑をかける可能性もありますので十分注意して実施してください.外部サーバや他人のPCに対して試してみるということは絶対にしないでください.
学内のトラフィックは,情報基盤センターのツールで監視されています.皆さんはコンピュータネットワークの授業で,通信の仕組み(接続元IPアドレス・ポート番号,プロトコル種別,接続先IPアドレス・ポート番号の5つの情報で通信フローは識別可能)を学んでいるわけですので,どのような仕組みで監視できるのか認識しているものと思いますが,意図せぬウィルス感染や不正アクセスでも情報基盤センターから連絡は来ますので,十分注意して以下の課題に取り組んでください.皆さんのノートPCのMACアドレスは入学時に学内DBへ登録されているはずです.実験機材のMACアドレスもこちらで把握しています.また,学内DHCP(無線であろうが有線であろうが)でIPアドレスをもらっている場合,どのMACアドレスへいつからいつまでどのIPアドレスを割り振ったかログに記録されてます.学内にはネットワーク機器の運用規則がありますので,遵守するとともに敢えて抜け道を探すようなことは絶対にしないでください.もし抜け道に気づいてしまった場合は,真摯に教えてください.将来のネットワークエンジニアの卵として良い方向での成長を楽しみにしたいと思います.
また,もし何か意図せぬことが発生しているような気がする場合は,「学内ネットへ接続しているルータWAN側のLANケーブルを抜く」ということでお願いします.
よく,「ホームページが改竄(かいざん)された」というニュースや「セキュリティホールが見つかったのでソフトウェアアップデートしましょう」というような周知があるかと思いますが,これまでに実装したSimple HTTPサーバにもセキュリティホールがあります(というかあまり深く考えずにネットワークプログラムを開発すると,セキュリティホールだらけになりますので注意してください).
ここでは,セキュリティホールの基本であるバッファオーバフローを利用した攻撃方法について理解し,実際に以下のステップを実験用端末で試してみてセキュリティホールを実感してください.
上から順番に少しずつ攻撃を高度化したものになります.つまり,一番下に示すリモートサーバのシェルに接続できれば,ホームページの改竄もできてしまいます.
なお,この実験は静岡大学情報学部情報科学科カリキュラム,情報科学実験Aの内容をベースにしています.以下のURLを参考に予習を進めてください.
本実験ではRaspberry Piを利用します.必要なソフトウェアはインストール済ですが,演習開始までに以下の事前準備を終わらせておいてください.(静岡大学生かつ情報科学実験Aを履修済みの方はセットアップ済Raspiをお持ちかと思います.その場合以下は読み飛ばしてもらっても構いません)
接続用の無線ネットワーク情報は当日お伝えします.情報に従って無線ネットワークに接続してください
情報科学実験AでSimpleHttpサーバーをすでに作成してありプログラムをお持ちの方はこの準備をする必要がありませんので,読み飛ばしていただいて構いません.
以上が終わったら事前準備は完了です.では演習を始めていきましょう!
以下を参考としてください
プログラムが管理しているメモリ上に確保するバッファ領域に対して,脆弱性のある実装をしているとバッファ領域の上限を超えた部分に情報を格納(バッファオーバーフロー)してしまうことがあります.これによりプログラムが意図した通りに動作しなくなってしまう場合があります.詳細は「バッファオーバーフロー」で検索して調べてみてください.
まずは以下の簡単なプログラムについて考えてみましょう.以下のプログラムは任意の文字列1つを引数として取ることができます.試しに色々な引数を入れて実行してみてください.引数を長くしていくとある長さから先で実行結果がSegmentation Faultとなることがわかったはずです.この時,プログラムの中では何が起こっているのでしょうか?
gdb(GNUデバッガ,後述)を使いながら実行時のメモリの内容を確認してみましょう.たとえば以下のような情報を確認するとよいでしょう.
gdbはGNUデバッガの略称で,GNUソフトウェア・システムで動く標準のデバッガです.利用方法については,たとえば,下記のサイト等を参照しながら進めてみてください.
昨今のOSはデフォルトでは以下の対策が施されていますので,今回は敢えて体験できるよう以下の設定を解除してから実施してください.その他にも最新のセキュリティ対策が施されている場合がありますので,状況に応じて解除して実施してください.
% sudo sysctl –w kernel.randomize_va_space=0
% gcc –z execstack –fno-stack-protector xxxx.c
また,本演習で利用するRaspberry PiはARMアーキテクチャを使用しています.このため,「バッファオーバーフロー」等で検索して出てくるページに記載の内容とはレジスタ名等が異なることがあります.各自,ARMとx86/x64アーキテクチャの違いを意識して演習に取り組んでください.たとえば,違いをまとめたページとして以下のようなものがありますので参考にしてください.
上記のプログラムは任意の長さの文字列を入力可能です.適当に長い文字を入力すればバッファオーバーフローが起きるのが確認できたと思います.では,バッファオーバーフローによりリターンアドレスを上書きするには最低何文字の文字列を入力すればよいでしょうか?
バッファオーバーフローを利用して,リターンアドレスを上書きし,任意の関数を呼び出すことができます.まずは以下のようなサイトを参考にしながら,バッファオーバーランの仕組みを理解しましょう.
たとえば,以下のようなプログラムにおいて,パスワード(shizuokaやenpit)以外の文字列を入力してgrantedの文字を出力するにはどうしたらよいでしょうか?
gdb(GNUデバッガ,後述)を使いながら実行時のメモリの内容を確認してみましょう.
% ./auth_overflow $(python -c 'print("A" * 10 + "\x16\x85\x04..")')
※Aの数やアドレスは適当です
% ./auth_overflow $(python3 -c 'import sys; sys.stdout.buffer.write(b"A"*24 + b"\x16\x85\x04..")')
Python3な人はこっち
リターン先のアドレスを上書きするイメージがわかったでしょうか?このリターン先のアドレスに,サーバ側のシェル(/bin/sh等)を起動するコードを配置しておけば,任意のコマンドを実行させることができるようになります.まずは以下のような簡単なプログラムにおけるバッファオーバーフロー脆弱性を利用して,シェルを起動するエクスプロイトを書いてみましょう.
例えば以下のようなサイトもありますので,参考にして実現してみてください.
要約すると,次のようなデータを送り込めばよいことになります.gdbを使用してメモリ上の値を分析しながら実施すると具体的なイメージがわくと思います(ちなみにSSP (Stack-Smashing Protection)も無効にしておきましょう).
・・・とはいえ,最初はシェルコードの作成を自分で行うことは難しいかもしれません.現時点でハードルが高いと感じられた方については以下にサンプルのシェルコードを掲載しておきますので,まずはこちらを参考にしてどのようにしてシェルコードを実行するか?考えてみてください.プログラム中に変数の値として組み込む,引数として与える等色々やり方はあると思います.それぞれ実行の困難性や現実性に違いはありますが,今回は特に気にせず進めてよいとします.
シェルコードのサンプル(改行が入っているので注意)
\x01\x70\x8f\xe2\x17\xff\x2f\xe1
\x04\xa7\x03\xcf\x52\x40\x07\xb4
\x68\x46\x05\xb4\x69\x46\x0b\x27
\x01\xdf\x01\x01\x2f\x62\x69\x6e
\x2f\x2f\x73\x68
本演習の最終目標は,クライアント側で入力したコマンドをサーバへ送信&実行させ,そのサーバ側での実行結果の出力をクライアント側へ送信&表示させるように実装し,リモートからサーバ上の任意のコマンドを実行することです(もちろん通常は実行したコマンドがログとして残りますので,世の中のよくできたクラックツールは様々な工夫が施されておりますし,いたちごっこですのでサイバー攻防の発展は凄まじいですが).
今回対象とするコードは最も単純な機能のみを実装したSimpleHTTPサーバとします.静岡大学の学生さんで情報科学実験Aを受講された皆さんは実験で作成したSimple HTTP Serverを利用してくれて構いません. それ以外の方は以下にソースコードが用意されていますのでそちらを使ってください.ネットワークプログラミングについて忘れてしまった方も以下のURLなどを参考に復習しておきましょう.
例えば,サーバ側で実行させるシェルコードで,ディスクリプタを複製できるdup2()システムコールを実行させてaccept()で受け付けたソケットのディスクリプタを標準入出力へ複製してからexecve()するようにしておくといった方法があります.このような手法はTCP Bind Shellとも呼ばれます.具体的なシェルコードの作成方法等についてはたとえば以下のサイト等が参考になるでしょう.
SimpleHttpサーバーはexp1_http_session関数でクライアントからデータを受け取り,そのデータをexp1_parse_header関数に渡してHTTPヘッダの解析を行う,という流れで処理を行います.この間のバッファ受け渡しにおいていくつか注意しておくべき点があります.
バッファ先頭アドレスの推定がうまくいかない場合は,gdbを実行する際に起動済みプロセスにattachする形で調べてみてください(なぜこんなことをするのか?にも理由があります.時間に余裕がある人は調べてみましょう).どうしても難しい場合はソースコード中で printf("%p", ...); するように書き換えてもよいとします.どの変数のアドレスを調べるかは自分で考えてみましょう.
% gdb
(gdb) attach <pid>
(gdb) b 9 <-- 任意
(gdb) c
pidはpsコマンド等で確認できます.
以下にエクスプロイトコードの雛形を示しておきます.参考にしながら進めてみてください.
リモートからのシェル接続に成功した方,おめでとうございます!時間が残っている人は引き続いて理解度を深めるために以下の課題に取り組んでみてください.
上で作成したTCP Bind Shellのプログラムを元に以下のような課題に取り組んでみてください
最初に述べたように昨今のOSはASLR,SSP,DEPといったように今回のような攻撃を困難とするような対策が多く施されています.では,これらの対策を1つないし複数有効とした場合について,以下を検討してみてください.
最後にいくつか参考になるURLを記載してありますので,そちらなどを参考にしながら可能な限り進めてください
今回の課題と関連した内容について,自由に調査や実装を行ってみてください.たとえば,以下のような内容について調べたり,実装してみたりして報告してみるなどがあります.もちろんこれ以外でも大丈夫ですのでみなさんの自由な発想による取り組みを期待しています!
多くの場合Raspberry Piでは対策済みのバージョンがインストールされていると思いますが,古いバージョンにダウングレードして検証用コードを作成し,実行してみる等を行ってみるとよいでしょう.
最終発表では,皆さんが本演習で学んだことを発表してもらいます.以下の表を参考に,それぞれのグループがどこまで,どのようなことを達成できたかをまとめ,発表してください.本演習では発表内容をもとに,グループごとの進行度に応じて以下のように評価を行います.時間の目安を参考に,進行が遅れているなと思ったグループはTAにアドバイスを求める等積極的に行なってみるように心がけてください.また,各課題の達成点は達成度に応じて評価します.たとえ,明確なゴールに辿り着かなかったとしても,その過程での試行錯誤について発表して頂ければそれ自体を評価しますので,ぜひ高い目標にチャレンジしてみてください.
時間の目安 | 進行度 | 達成点 |
---|---|---|
9/24 11:00 | (必須)バッファオーバーフローの実行 | +30点 |
9/24 14:00 | (必須)バッファオーバーランを使ったコマンド実行に成功 | +15点 |
9/24 17:30 | (必須)リモートシェルの起動に成功(とりあえず動かす) | +15点 |
9/25 発表終了まで | (選択)発展課題1の実施 | +15点 |
(選択)発展課題2の実施 | +15点 | |
(選択)自由課題の実施 | +15点 | |
(必須)最終発表の実施(わかりやすさ等で評価) | +15点 |
選択式の発展課題や自由課題は複数取り組んでも構いません.教員の評価による加点も含めた合計点を最終得点とします.