情報処理技術者試験で学ぶ SAML
勉強会用に、急いで作りました。土日しんだ。
とりあえず、見切り発車(0.9.1版)で公開します。これで乗り切るしかない。
よかったら、SlideShare のページから、ダウンロードしてください。
間違いがあったら、指摘いただけるとうれしいです。
新人教育 ~ 言葉を選び、よく対話すれば、学びは深くなる
あしです。
今日、「ゼロから教えて 新人教育」という書籍を読んだので、学んだことをシェア(ウソ、メモ)しておきます。
絵や図が多いので、さらっと頭に入れるには、とてもよい書籍だと思います*1。
まず、なぜこの本を読んだのか、その背景と目的について書きます。
次に、この本から、何を学んだかについて書きます。
最後に、明日からのアクションプランを書いて、終わりにしようと思います。
| | なぜ読んだのか? |
- 背景
どうやら、今年度の春に入社してくる社員さん(以下、新人さんと呼びます)たちと、少しの間、同じ時間を過ごすことになりそうです。
これまで、テクニカルな研修(ネットワーク、Java、Web アプリケーションセキュリティ)なんかで、新人さんとご一緒させていただいたことは何度もありました。逆に、それ以外で、新人さんを育成したことはほとんどなく(多少あります。失敗したと思っています)、どうしようかと。
そんなとき、この本が今年度の「課題図書(?)」的に挙がっていたので、「これは、一石二鳥」と、読んでみました。
- 目的
ゴールというか、自分の願い(?)望み(?)は、新人さんたちに「ビジネスを行う上での基本動作を身につけてもらいたい」ということです。自分がイメージしている「基本動作*2」とは、計画、段取り、ライティング、ホウレンソウ、振り返りです。
これらは、仕事をする上で、めちゃめちゃ大切です。しかし残念ながら、自分では、到底「教える」には至りません。
そんな「未熟な自分が、どうすれば "ビジネスを行う上での基本動作" をうまく伝えられるか」、そのヒントを得るために読みました。
| | 何を学んだか? |
この本を読んだことにより、目的が十分達成できたとは思いませんが、もちろん学んだことはあります。
学んだことをヒトコトで言うと、
「言葉を選び、よく対話すれば、学びは深くなる」
ということです。
なお、書籍では、教える立場の人を「リーダー」と呼んでいます。このエントリも、それにならいます。
- 心がまえ
「完璧であろうとすると、逆効果。自分もつぶれる」ということを学びました。
リーダーの心がまえの 1 つとして、『自分が先生であろうとしない』と紹介されていました。そうですよね。頭ではわかっていたものの、少し「ほっと」しました。
- 準備
教える前にしておきたいこととして、『指導プラン』をつくるよう書かれています。その際、5 W 2 H(1R)*3を意識するよう書かれています。
また、信頼関係を構築する一環として、相手のこと(e.g. 出身地, 趣味, 特技)を調べておくよう書かれています。
はい。しっかりやっておきます。
- 実践
書籍の 47 ページから最後のページ(185 ページ)までを使って、新人さんに「教える内容(e.g. PDCA, 各種マナー)」と、リーダーが実践する「教え方(e.g. コーチング, 傾聴)」が書かれています。
この 139 ページ分が、ノウハウの塊です。ほぼほぼ、見開き完結で、ポイントが解説されています。
その中でも、特に共有したい箇所、ためになった箇所を列挙します。
|
分類 |
内容 |
|---|---|
|
話し方 |
新人さんには、「まずは、テンプレートを使って話させてみる」ことを学びました。 書籍では、PREP 法と呼ばれるテンプレートが紹介されています。 PREP とは、結論(Point)、理由(Reason)、具体例(Example)、結論(Point)という話し方のテンプレートです。
これは、ライティングにも、そのまま活かせるテンプレートですね。 次の書籍にも、類似のテンプレートがあります。
ライティングに関しては、マナブさんのブログ manablog のエントリでも、類似のテンプレートが、紹介されています。 有料級の情報です。まぢに、読んでおくとよいです。
【完全に解決】文章が書けない原因は「型」にあります【必読ですよ】 |
|
聴き方 |
リーダーは、「意見を聴くときは、安易に話を切るべきではない」ことを学びました。具体的には、こんな感じだと NG です。
このあたり、マコなり社長の発信が、感動レベルなので、紹介しておきます。
【厳禁】実は気づいていないパワハラ発言 TOP5 |
|
叱り方 |
「叱るときは、事前に内容をよく吟味すべき」ことを、学びました。具体的には、次のように叱ればよいとなりました。
このあたりについても、マコなり社長の発信が、感動レベルなので、紹介しておきます。
絶対にやってはいけない「人の叱り方」トップ 5 |
| | アクションプラン |
スタートまでの時間が短いので、もうやるしかないです。
◆『指導プラン』は、他の部隊が作成済み。明日と明後日で、しっかり理解する
◆ 明日と明後日で、新人さんの情報をインプットする
◆ 次のような箇所をピックアップする。今すぐ、それらを暗記する
- 意識しなければ、やることを忘れてしまいそうな箇所
- ダメだとはわかっていても、やってしまいそうな箇所
- おまけ 1
|
部下の育成については、やはり マコなり社長 の動画が感動レベルなので、紹介しておきます。 部下の育成に関するエッセンスが、さらに圧縮されて 15 分程度にまとめられているため、ものすごく濃い内容となっています。おススメです。
上司の 9 割は「育て方」を知らない https://www.youtube.com/watch?v=0NHkILdM-bk
ちなみに私は、この動画を繰り返し繰り返し見ています。控え目に言って、20 回くらいは見たかな。メモも、完璧にとっています。 |
- おまけ 2
最近は、↓ この書籍の影響を受けています。
本エントリでも、自分が学んだ内容をヒトコトで言うときは、だいたい 20 字くらいにしています。
応用情報・午後・セキュリティを解く(R01春)その 1
あしです。こんにちは。
今回は、応用情報処理技術者試験、2019 年度(令和元年度)、午後 問 1 を解いていこうと思います。「早速、設問 1 から」といきたいところですが、先に、電子メールに関する知識が問われている、空欄 b と c を片づけておこうと思います。
| 今回は、「送信ドメイン認証」、「S/MIME、PGP」、「OP25B」 について解説します。これらのタームについて、「知らんぞ」という方は、ハイライトの箇所だけでも、眺めていただけると、勉強になると思います。 |
電子メールに関するセキュリティについては、午前問題はもちろんのこと、「平成 27 年度 春期 午後」にも、がっつり出題されています。過去問をしっかりつぶしていた人は、ごっそり得点できたはずです。
| |【おさらい】SMTP |
まずは、メールに関するプロトコルのおさらいから。この絵は、左の人から、右の人までメールが届くまでのイメージを表したものです。

まず、クライアントからメールサーバに SMTP で送信、次に、メールサーバから次のメールサーバまで SMTP で転送、最後に、メールを見るために、IMAP4 や POP3 を使いました。
さらに、SMTP がどんなプロトコルだったか、確認させてください。例えば、クライアントからメールサーバに、メールを送信するときの通信を見てみましょう。こんな感じになります。

まずは、ポート番号 25 番に対して、TCP のコネクションを張ります(3 ウェイハンドシェイクと呼ばれる通信によって、コネクションを確立します)。
そのコネクションを用いて、メールサーバに対し、HELO、MAIL FROM、RCPT TO などのテキスト(SMTP のコマンド)を送信します。
DATA コマンドの後に、メールの From、To、タイトル、本文などを送信します。
QUIT コマンドを送信し、TCP のコネクションを切断します。
これを見ると、メール中の「送信元アドレス」は、簡単に書き換えられることがわかると思います。だから、送信ドメイン認証が必要になるんです。
| | 送信ドメイン認証 |
空欄 b、c で問われているのは、送信ドメイン認証についてです。有名な方式に、SPF と DKIM(ディーキム)があります。
1. ポイント
もぅ細かいことはよいので、コレをおさえます。
|
2. 過去問知識
送信ドメイン認証についての、過去問を見ていきます。
「平成 27 年度 春期 午後」の問 1 には、次のような記述がありました(ハイライト等は筆者にて加工)。
メールサーバでのメール受信時の送信元メールアドレスが偽証されていないかのチェックは [ a ] と呼ばれ、送信元 IP アドレスを基にチェックする技術(SPF)、又は受信メールの中の電子署名を基にチェックする技術(DKIM)を導入します。
《平成 27 年度 春期 午後 p.6 》
上記の空欄 a の解答が、まさに「送信ドメイン認証」でした。
SPF については、平成 28 年度 秋期の午前問題でも出題されています(ハイライト等は筆者にて加工)。
(問 43)
受信した電子メールの、送信元ドメインが詐称されていないことを検証する仕組みである SPF(Sender Policy Framework)の特徴はどれか。
(正 解)
受信側のメールサーバが、受信メールの送信元 IP アドレスと、送信元ドメインの DNS に登録されているメールサーバの IP アドレスとを照合する 。
この 問 43 にある通り、SPF の動作は、こんな雰囲気になります。だいたいのイメージがあれば十分です。

DKIM では、デジタル署名により偽証を検知します。(1) DNS サーバに公開鍵を登録しておく、(2) メールを送信する側が、メールにデジタル署名を付与する、(3) 受信側は、DNS サーバに問い合わせ、デジタル署名を検証する、という流れになります。
3. 解答
ということで、空欄 b には、SPF が入ります。
さらに、上記には、送信ドメイン認証は、『メール受信時の送信元メールアドレスが偽証されていないかのチェック』をしてくれるとあります。
ということで、空欄 c には、「送信元メールアドレスの偽証」が入ります。
この問題は、以上です。一応、他の肢も見ておきましょう。
| | S/MIME, PGP |
選択肢 ウ の S/MIME と、選択肢 イの PGP は、ペアで出題されることが多いので、この機におさえておきましょう。
1. ポイント
まずは、S/MIME から。
S/MIME(Secure/MIME)は、証明書を利用して電子メールに暗号化とデジタル署名のセキュリティを提供します。
《 IPA PKI 関連技術情報「7.2 S/MIME」》
MIME とは、メールにて、画像などのバイナリを送信する規格のことです。S/MIME は、MIME の拡張です。
S/MIME では、信頼性の高い通信を提供するため、公開鍵の交換には、証明書を利用します。
次に、PGP です(もともとは、メールの暗号化ツールの名称です)。
PGP(Pretty Good Privacy)は公開鍵の交換を事前に当事者間で行ない、その間で電子署名や暗号化されたメールのやり取りを可能にする仕組みである。
公開鍵の交換は、手渡しや Web of Trust(信頼の輪)に基づいて行われます。Web of Trust とは、「友達の友達は、そこそこ信頼できる」という考え方です。
2. 過去問知識
S/MIME も PGP も、既出です。
S/MIME については、まず、平成 26 年度 秋期 の午前に出題されています。
平成 27 年度 春期 午後 問 1 には、次のような記述があります。
現在のメールシステムでは、営業部でのメールの暗号化には、S/MIME を利用することになっています。メール宛先の [ b ] を利用して暗号化する方式で、安全性は高いのですが、先方が [ b ] をもっていなければ使えない方法なので、利用している顧客はごく一部です。
《平成 27 年度 春期 午後 p.6 》
上記の空欄 b の解答は、「公開鍵」でした(ちなみに、公開鍵で暗号化するのは、メール本文ではなく、メール本文を暗号化・復号するための共通鍵です)。
さらには、同年度、秋期の午前問題にも出題されています。てか、基本情報技術者試験でも、出題されています。
| | OP25B |
最後に、肢 ア についてです。OP25B(Outbound Port 25 Blocking)は、午前問題でも、やや突っ込んできかれているので、ここでしっかりおさえます。
OP25B とは、ISP(インターネット・サービス・プロバイダ)のメールサーバを経由しないで外へ向かう SMTP の通信を、ブロックする仕組みです。
下の絵のように、2 つの ISP、ISP-A と ISP-B があるとします。

攻撃者は、右の人(青)に、スパムメールなどを送ろうとします。
しかし、OP25B により、ISP-A から外へ出ていく SMTP の通信がブロックされます。つまり、この経路では、ISP-A のメールサーバを通らずに、ISP-B のメールサーバに直接アクセスすることができません。
例えば、ISP-A のメールサーバに、送信元 IP アドレスによる制限がかかっていたりすると、レンジ外の攻撃者は、右の人に、標的型攻撃のメール、スパムメールなどを送ることができなくなります。
あ。仮に、攻撃者や攻撃者のボットが、 ISP-A と契約しているのであれば、普通にメールサーバ経由で、メールを送信することができますよ。当たり前ですが。
では、「ISP-A の管理下にいない人には、ISP-B のメールサーバへアクセスする方法はないのか」というと、あります。

それは、ISP-B のメールサーバで認証をかける方法です。
「きちんと認証された人なら、メール送信してもいいよ」ということです。
認証をかけるには、SMTP-AUTH などの認証機能のついたプロトコルを用います。このとき使うポートを、「サブミッションポート」と呼びます。
今回は、いったんこれで、終わりにします。次回は、残りの問題の解説をします。
最後まで読んでいただき、ありがとうございました。
(次回へ続く)
安全確保支援士対策 BOF 編 [3]
こんにちは、あし です。
このエントリでは、安全確保支援士試験の対策として、情報処理技術者試験の過去問を解説します。
過去問を解きながら、知識のインプットができるようにしたつもりです。問題に取り組んでいただき、その後、本エントリを見ていただければと思います。
時間がなければ、問題を見ながら、さらっと読んでいただければよいと思います。さらに時間がなければ、絵だけ見ながら、流せばよいと思います。
さて、今回は、BOF(バッファオーバフロー)編 第三弾。「2016 年度(平成 28 年度)秋期 情報セキュリティスペシャリスト 午後 1 問 2」を解いていきます。
《問題》
情報処理技術者試験のページからダウンロードしておいてください
《凡例》
|
それでは、午後 1 の 問 2 を、解き進めましょう。
前回同様、まずは、設問をながめます。

ざっと、こんなことがつかめれば、十分だと思います。
- 選択式の穴埋め a ~ d → 選択肢が 4 つしかない → サービス問題?
- 設問 2 とは、ガチで BOF っぽい
- 設問 3 は、変な文字列選択するようになっているし、修正用のコードもある、もっとガチかも
- 設問 4 は、BOF の対策っぽい
頭から、設問 1 a からいきましょう。6 ページの真ん中らへんです。

速攻で、CVE-ID → CVE 識別子です。出血、大サービス問題です
↓ このあたりをおさえている人が多いと思います
- 脆弱性情報のデータベースの 1 つ
- 各ベンダーが公表する脆弱性情報がバラバラだったので、それらをまとめて、共通したユニークな識別番号をつけた
- アメリカの MITRE(マイター)社が運営している
設問 1 b と c です。

これらは、もしや 「マグネット売場」 なのでは?
もとい。
ここに挙げられた、「ゼロデイ攻撃 + 標的型攻撃」 には、高い確率でヤラレると思います。出題の裏には、相当な危機感があると思われます。
本問を選択したほぼ全ての受験生が正解したでしょうね。
設問 1 d です。

ファジング(Fuzzing)とは、ファズ(fuzz)と呼ばれる、問題を引き起こしそうなデータを大量に送り込み、その応答や挙動を監視することで、脆弱性を検出する検査手法になります。
ちょっと脱線しますが、ここに出てくる 「静的解析ツール」 とは、ソースコードの段階で、脆弱性を含む不具合を検知してくれるツールです。
特に、セキュリティ面を重視した静的解析を、SAST(Static Application Security Testing)と呼んだりします。これは、DevSecOps(セキュリティを維持したまま、リリースの頻度を高めること)を実現するための、重要な要素となってきています。このあたり、SE っぽいでしょ?
戻ります。
設問 2 に入ります。

また、この問題ですか。何度でも、きいてきますね。
『関数呼び出し時にスタックに必ず積まれる』 は、スタックフレームです。
『何の値を書き換える』 は、スタックフレームに入っている値のいずれかです。
別に、怒っていませんよ。
# インプット ここから ---
念のため、スタックフレームのレイアウトを確認させてください。
またこの絵です。

- 左の絵は、メモリ空間の全体
上のアドレスが 「低」 く、下のアドレスが 「高」 いことに注意してください(スタック領域は低い方に、ヒープ領域は高い方に成長します) - 真ん中は、スタック領域(スタックが積み重なっている)
- 右の絵は、スタックフレームのレイアウト(ローカル変数、スタックフレームポインタ、リターンアドレス、引数)
ここで、スタックフレームポインタ(SFP)と、リターンアドレス(RET)が何だったかというと、
- スタックフレームポインタ →(呼び出し元関数の)スタックフレームの基準となるアドレス。1 つ下のスタックフレームがどこにあるのか
- リターンアドレス → (呼び出し元関数の)命令があるアドレス。この関数が終わったとき、どこに戻ればよいのか
です。
# インプット ここまで ---
これを踏まえて、設問に戻ります。

「リターンアドレス」 には、今の関数の処理が終わったとき、どこに戻ればよいのか、そのアドレスが格納されています。
リターンアドレスの領域が書き換えられるということは、次に実行する命令を、好きな場所に指定できるということです。
スタックベースの BOF 脆弱性がある場合には、ローカル変数に確保した領域より大きなデータが投入されると、データがリターンアドレスの領域にあふれます。
リターンアドレスを都合のよい値に書き換えれば、プログラムの制御を奪える = 好きなコードを実行できるのです。
過去には、① shell コードの実行、② 共有ライブラリ内の関数であって、かつ、任意のプログラムを実行できる関数(e.g. libc 共有ライブラリ)の実行なんかが、出題されました。
次に移ります。

いわゆる、setuid や SUID(Set User ID)と呼ばれるものです。問題文中に、丁寧な説明がありますので、知らなくても解けます。
ただ、setuid、setgid を悪用し、権限昇格を図る手法は、とても有名なので、ここで覚えてしまいましょう。再び問われる可能性があります。
ls コマンドの結果です。

上の 2 行は、ディレクトリなのでムシしましょう。「.」 が、現在のディレクトリを表し、「..」 が、一つ上のディレクトリを表します。
本問では、所有ユーザに注目します。
まず、4 つのファイルとも、ユーザ suzuki に、読み取り権限、実行権限があります(書き込み権限はありません)。
パーミッションが、「rwx(リード / ライト / 実行)」 や 「r-x(リード / 実行)」 であれば、すべて、suzuki 権限で動作します。
さて、『実行権限の属性に "s" が表示されているファイルは、ファイルの所有権限で実行される』 とあるので、suzuki で起動しても、root 権限で実行されるケースは
- 所有ユーザの実行権限 s になっている
- 所有ユーザが root である
場合になります。それって、sample2 ファイルのみですね。
まとめます。

この 3 つの条件を満たすファイルを選べばよいです。
- 実行権限の属性が "s" である
- 一般利用者 suzuki によって起動できる
- ファイルの所有者が root である
ア の、sample2 ですね。
設問 3 です。まいります。

まずは、プログラムを見ましょう。スライドには、「図2 ヒープベース BOF の脆弱性のあるプログラム Y」 の、main 関数の中身だけ抜き出しました。
その中で、さらに骨格だけ残してみました。行番号を入れていないところが、思い切って省略した箇所です。
| このプログラムは、C++ で書かれていますが、C++ をよく知らない人でも、① 単純な ID パスワード認証の処理であること、② コメントが充実していることから、各行がどのような処理をしているのかについては、比較的容易に把握できる、はず。です (少なくとも、私は Java の人で、C++ は、3 ヵ月程度さわったに過ぎません) |
一応、プログラムの内容を言葉にしておきます(コードの方が、簡潔でわかりやすいですが)。
- 20 行目、21 行目(青い吹き出しです) → プログラムの中で、領域を確保しています。"new" とあるので、察しはつくと思います。9 バイトずつの領域が、「ヒープ領域に」 確保されます
- 22 行目 → 第 1 引数(ユーザ ID)から、パスワードを取得し、pass 領域に格納しています
- 23 行目(赤い吹き出しです)→ また strcpy です。まぁ、こうなりますよね。第 1 引数(ユーザ ID)を、uid 領域にコピーします
- 25 行目(灰色の吹き出しです)→ pass 領域に文字列があり、この値が、第 2 引数で指定した文字列と一致したときに、認証が成功します
プログラムがやっていること(左)と、メモリのレイアウト(右)をまとめてみました。↓ ココまで整理できていれば、正解は、すぐそこです。

なお、右のメモリのレイアウトは、一例です。ヒープ BOF の脆弱性があるということは、uid の領域があふれ、pass の領域を侵食するだろうことだけ意識して書けばよいと思います。
この問題は、けっこう悩みました。正解以外の選択肢が、あまりにも意味不明だったからです。
整理できたら、あとは具体的に値を入れてみればよいです。

第 1 引数をメモリ領域にコピー(strcpy)し、パスワードの領域まで侵食します。
その後、パスワードの領域にある値と、第 2 引数とを比較します。
つまり、第 1 引数の下 8 桁が、第 2 引数の 8 桁と同じになる場合には、認証が成功します。
ふぅ。
設問 3 の (2) は、もうよいでしょう。

次いきます。
ぱっと見、「ムリ」 と思ったかもしれませんが、ご安心あれ。難易度は、かなり低いです。

C++ をよく知らなくても、正解にたどり着けます。C や C++ の関数名そのものを問いたいわけでは、なさそうです。
まず、『ウ』 です。
これまでより少し多く(PASS_SIZE+8)、パスワード用のバッファを確保しているだけです。PASS_SIZE+8 より大きなパスワードが指定されると、当然、想定していたパスワード用の領域からあふれます。
速攻きります。
次に、『ア』 と 『エ』 についです。どちらも、コピー cpy 関数なので、第 1 引数と第 2 引数が、コピー元、コピー先と考えるのが普通です。第 3 引数は何だったかと言うと、確保するバッファの大きさ(バッファの上限)でした。過去問で、何度も strcpy が出てきたので、知っていた受験生が多かったと思います。これについては、次のスライドで簡単に触れます。
これを踏まえると、『ア』 と 『エ』 では、バッファの上限として strlen(argv[1])+1 が指定されています。ということは、argv[1] の値が大きくなれば、バッファの上限も大きくなります。ユーザ ID として、256 バイトを指定すると、257 バイトまでコピーできるので、当然、ユーザ ID 用の領域からあふれます。
最後に、『イ』 と 『オ』 です。これらは、バッファの上限として、固定値 "9" を指定しています。9 バイト以上の値はコピーできません。これらが正解となります。
ここでまた、少しだけ、知識の確認をさせてください。

- strcpy は、文字列 str をコピー cpy する関数として、これまで何度も問われてきました。対策として、str"n"cpy を使って、バッファの上限を指定することを、知っていなければなりません。
ちなみに、"n" なしの、単なる strcpy は、バッファの上限を指定できませんでした。
- memcpy も、有名な関数です。メモリ mem の内容を、コピー cpy します。見聞きしたことがあるのではないでしょうか。なければ、ココで覚えておきましょう
今回のケースでは、argv[1] の指す領域を、UID_SIZE+1 バイト分、uid が指す領域へ、コピーします。
memcpy、strncpy、どちらも、BOF に脆弱となりうる 「ど典型」 の関数なので、覚えておきたいです。
以上です。
設問 4 に突入です。

設問で、『引数が同でも』 とあります。当然、プログラム Y の書き換えはないため、実行する 「処理も同じ」 となります。
となると、「メモリの配置が異なる」 しかありません。
「その実行環境」 では、メモリの配置が異なるということです。
とはいえ、新たなメモリの配置が固定であれば、その配置が悪用される可能性があります。なので、「メモリ配置が毎回異なる」 となればよいです。
全くわからなくても、ココまでは、書きたいです。
あとは知識があるかどうかです。基礎知識である 「ASLR」 を知っているかどうかです。

ASLR は、2014 年度(平成 26 年度)秋 の試験で、出題されました。
なので...
あら?
IPA の解答が、ASLR に限定していない。なんで、この解答になるのか、わかりません。ごめんなさい。
後ろ髪を引かれつつも、スルーして、(2) に移ります。

これも、知識問題と言わざるをえないです。DEP のざっくりとした仕組みがわかっていれば十分ですが(過去問をやれば、どの程度の深さで技術をおさえればよいか、わかります)。
スライドには、DEP を全く知らない場合の思考を書いてみました。いけなくはないですが、、かなり厳しいです
ただ、何か書かなければならない場合には、こんな感じで推測するしかありません

DEP とは、テキスト領域以外、つまり、ヒープ領域やスタック領域にあるコードに印をつけ、そこからコードが実行されると、プログラムを異常終了させる仕組みです。
私は、「ヒープ領域にあるコードが実行されるわけではないから」 とか、
「ヒープ領域の操作が問題で、テキスト領域のコードを実行するから」 と解答を作成しました。
30 字でまとめるのは、まぢで厳しいです。
それでは、これまで見てきたこと、本問で得た知識を、簡単に復習しましょう。


な感じですかね。
総括です。

総括です
よく出題される、重要な技術、受験生の正解しやすさなどを鑑み、独断と偏見で、問題ごとに、ランクをつけてみました("A" ~ "C")。
- "A" は、絶対にとりたいです。これだけでも、合格ラインを超えるかもしれません
- "B" が、いずれか取れていれば、十分合格ラインを超えると思います
- "C" は、時間かけてもできませんでした。この道の専門の人ならできるのでしょうが
今回も、長文になってしまいました。だらだら書きすぎですね。慣れてきたら、だんだん「コンパクトに」まとめていこうと思います。
最後まて見ていただき、ありがとうございました。
安全確保支援士対策 BOF 編 [2]
このエントリでは、安全確保支援士試験の対策として、情報処理技術者試験の過去問を解説します。
過去問を解きながら、知識のインプットができるようにしたつもりです。問題に取り組んでいただき、その後、本エントリを見ていただければと思います。
時間がなければ、問題を見ながら、さらっと読んでいただければよいと思います。さらに時間がなければ、絵だけ見ながら、流せばよいと思います。
さて、今回は、BOF(バッファオーバフロー)編 第二弾。「2014 年度(平成 26 年度)秋期 情報セキュリティスペシャリスト 午後 1 問 1」を解いていきます。2007 年度に比べると、難易度が上がっているように感じました。
難易度が上がれば、他の受験生の出来も悪くなるので、過度に心配する必要はないです。
《問題》
情報処理技術者試験のページからダウンロードしておいてください
《凡例》
|
それでは、午後 1 の 問 1 を、解き進めましょう。
前回同様、まずは、設問をながめます。

選択式の穴埋め、フリーの穴埋め。
記述問題 20 字 ~ 40 字(これだと、1 ~ 2 トピックしか入りません。フリーの穴埋めプラスアルファくらいのイメージです)。
問題も眺めます。四角 a ~ d の前後、下線部 ① ~ ⑤ を確認します。
テーマは BOF で、設問 2 はガチ。設問 3 には、IPS と WAF が登場 → なので、純粋な BOF の話ではなさそう。設問 4 は、BOF ではなさそうです。
頭から、設問 1 a からいきましょう。3 ページの上の方です。

すぐに、「パッチ」 とか 「修正プログラム」 などが思いつかないと、ヤバいです。ほぼすべての受験生がとってきます。
「[ a ] の適用」 が、「ソフトウェアの更新」 と並列になっているので、解答に 「セキュリティ」 という文言は入れたいです。
なので、答えは 「セキュリティパッチ」。これしかないんじゃないかなと思います。
設問 1 の b です。3 ページ真ん中らへんです。

スタックバッファオーバフロー攻撃ときたら、だいたい、「ヒープ」 バッファオーバフロー攻撃ですw
これも、他の受験生は、間違いなくとってきます。
設問 1 の d です。5 ページの真ん中よりやや上です。

で、私は、知らんかったです(チーン)。
ちょいと調べたところ、かなり有名な攻撃名であるため、名前、覚えておきます。
どのような攻撃なのかわからない、という方は、設問 2 の解説を見た後に、戻ってくるとよいです。
図1 のコードは、問題を解く際には、あまり関係ないのですが、一応、触れておきます。

|
この Vuln は、スタック BOF に脆弱な、ド典型のコードです。 後で見ますが、スタック領域には、関数の引数とローカル変数が格納されています。もちろん b も c も、スタック領域上にあります。 そして b は、巡り巡って、プログラム Vuln の第一引数の値を指し示します(オレンジ色の箇所です)。 しかし、この 11 行目、strcpy 関数は、バッファの上限のバイト数を指定できません。さらに、Vuln では、コピー元のデータが、確保したバッファ char c[24]; 内におさまるかどうかのチェックもしていません。 まとめますと、このスタック領域上の b に、巡り巡ってやってきたプログラムの引数 b に、スタック領域に確保した char c[24]; より長いデータを与えると、char c[24]; がオーバフローします。 ちなみに、strcpy 関数以外にも、strcat、sprint などの関数があります。表に示した関数くらいは、把握しておきたいです。 |
設問 2 の (1) です。図 2 を見ると、実質 5 択であることがわかります。

スタック BOF では、攻撃者がスタック領域に 「注入した」 shell コードが実行されます。この後、説明します。
通常のコードでは、事前に、テキスト領域に展開された命令が実行されます。ですので、この場合は、「スタック領域にあるコードは実行しない」とすればよいです。
解答は、そのまま、「スタック領域に適用すればよい」 となります。まんまなので、少し勇気いります?
いよいよ(?)、設問 2 (2) です。

「リトルエンディアンってなんだっけ?」 という人は、すぐにとばしましょう。この 1 問で合否が決まるわけではありません。
「リトルエンディアン」 の説明の前に、まずは、「レジスタ」 について復習します。
レジスタとは、CPU の記憶回路のことです。CPU 内にあるメモリのイメージです。
左側の表を見てください。これは、Intel が作った CPU である、x86(今や、32 bit アーキテクチャを指すことの方が多い?)から、ピックアップしてきたものです。レジスタは、色々な用途に使われています。ちなみに、x86 のレジスタは、全部で 16 あるそうです。
で、「リトルエンディアン」 ですが、これは、バイトの順序を表すタームです。
右の絵を見てください。今、レジスタ上に、C8, 04, 80, 26 というデータが格納されているとします。これを、メモリ上に持ってきたときにはどうなるかというと、逆さまに格納されます。つまり、26, 80, 04, C8 となります。
このように、バイトの順序が入れ替わる方式が、リトルエンディアンです。逆に、バイトの順序が入れ替わらない方式を、ビッグエンディアンと呼びます。
どちらがよいというわけではありません。ちなみに、x86 は、リトルエンディアン方式です。
ここから、しばらく、基本知識の整理をさせてください。関数を呼び出したときの、メモリ、レジスタの変化について、確認します。ガチで書いたので、結構、長いです。なんとなく知っている方は、「# インプット ここまで ---」まで、すっ飛ばしてください。
# インプット ここから ---
① 各種レジスタの名前、② リターンアドレス(ret)、③ ebp レジスタ保存値(sfp)などの用語になじみがないと、説明が難しく感じるかもしれません。が、気のせいです。単に慣れていないだけです。過去問を解く中で、慣れていってください。
こんな順で説明します。
- スタック領域 ~「スタック」のおさらい
- レジスタとメモリ ~ プログラム実行時のレジスタとメモリの様子
- スタックフレーム ~ スタックに PUSH / POP するデータのレイアウト
- 具体例 ~ プログラム実行時のレジスタとメモリの様子
main 関数実行時 --> foo 関数呼び出し時 --> foo 関数終了時
まずは、「スタック領域」から。

スタックというデータ構造は、みなさんご存じでしょう。「本」 が積まれているイメージです。新たに本を積むことを 「PUSH」 と呼び、本をとることを 「POP」 と呼びました。最初に積んだ本は、最後までとることができません(FILO)。最後に積んだ本が、最初にとれます(LIFO)。こんな特徴がありました。
「てか、このスタックの絵、逆さまぢゃね?」
はい。いつも見ているスタックのイメージと逆さまになっているので、少しわかりにくいです。問題中の、図 2 にあわせました。
続けます。「スタック領域」 は、「スタックフレーム」 という 「本」 を PUSH したり POP したりする領域になります。
ここで大事なことは、スタック領域は、高位のアドレスから、低位のアドレスに成長するということです。
逆さまになっていない図を使っている記事や書籍もあります(むしろ、そっちの方が多いと思います)。どうして逆さまになっていないかというと、低位のアドレスを上に、高位のアドレスを下に書いているからです。それだけです。
このスタック領域が、いつ使われるかというと、関数の呼び出し時です。関数を呼び出すときには、その関数が使う 「スタックフレーム」 なる 「本」 を作成し、スタックに PUSH します。関数を終えるとき、関数を呼び出した前の状態を復元して、「スタックフレーム」 なる 「本」 を、スタックから POP します。
次に、レジスタとメモリを使って、どのようにプログラムが実行されるのか、おさえましょう。

今回、用途をおさえておいてほしいレジスタは、「スタックポインタ(esp)」、「ベースポインタ(ebp)」、それから、「インストラクションポインタ(eip)」 の 3 つです。
左の絵を見てください。esp と ebp は、スタック領域を指し示します。
- esp には、スタックのトップのアドレスが格納されています。この値により、メモリを確保したり、開放したりしています
- ebp には、スタックフレームの 「ベース(基準)」 となる、アドレスが格納されています
右の絵を見てください。eip は、これらとは少し毛色が異なります。ここには、実行する命令のアドレスが格納されています。
eip が指す命令をとってきて(フェッチ)、解釈して(デコード)、実行する。すると、eip がカウントアップし、そこから、フェッチ、デコード、実行します。このようにして、プログラムが実行されていきます。
次に、スタック領域に積まれる 「本」 である 「スタックフレーム」 が、どのようなデータなのか、説明します。

スタックフレームのレイアウトは、問題文の図 2 に書いてあります。ちょっと見にくいので、簡潔に書きました。例えば、右側の絵のようなレイアウトになっています。
このスライドの、ちっちゃく描かれた 「スタック領域」 には、main 関数のスタックフレームがあり、その上に foo 関数のスタックフレームが積みあがっています。
スタックフレーム中の「リターンアドレス(ret)」と「ebp レジスタ保存値(sfp)」は、foo 関数が終了する際、foo 関数を 「呼び出す前の状態」 に復元するために使います。
それでは、関数が実行されるときのレジスタとメモリの様子を、具体的に見ていきましょう。丁寧に追っていきます。

この絵は、main 関数が実行されているときの、レジスタとメモリの様子です。
左側が、メモリのスタック領域、右側が、メモリのテキスト領域(プログラム Vuln の命令がある領域です)です。
まずは、簡単に、状況を把握しましょう。
- 左側にある、スタック領域を見てください。赤字の箇所がアドレスです。
main 関数のスタックフレームは、B 番地にあります。もちろん、ebp に格納されているアドレスは、B 番地です - 右側にある、テキスト領域を見てください。こちらも、赤字の箇所がアドレスです
eip は、X 番地を指しています。
この状態で、foo 関数が呼ばれると、どうなるかというと、 こうなります。

スタック領域に、foo 関数のスタックフレームが積まれました。つまり、esp が、新しいスタックの先頭を指しました。
ebp は、新しいスタックフレーム、C 番地を指し示しています。このとき、main 関数のスタックフレーム B 番地を見失わないように、sfp に退避しておきます。
eip は、カウントアップではなく、foo 関数の命令があるアドレスまでジャンプします。
このとき、呼び出し元である main 関数に戻ってこられないとまずいので、eip の値 X 番地(の次の番地)を、foo 関数のスタックフレームの ret に退避します。
そして、foo 関数の処理が終了しました。foo 関数のすべての命令が実行されました。

となると、foo 関数を呼び出す前に、戻らなければなりません。ebp が main 関数のスタックフレームを指すように、eip が main 関数の続きの命令を指すように、復元します。
これは、「foo 関数のスタックフレーム」に退避していましたよね。退避したリターンアドレス(X の次の番地)を eip に、sfp(B 番地)を ebp に戻します。
そして、foo 関数のスタックフレームを POP します。イコール、esp からスタックフレーム分のバイトを引いて、メモリ領域を開放します。
これで、foo 関数を呼び出す前の状態に戻り、X の次の番地から、フェッチ、デコード、実行です。
これで、インプットはお終いです。お疲れさまでした。
設問に戻りましょう。
# インプット ここまで ---
設問 2 の (2) です。

右の図は、図 2 を簡略化して書いたものです。図 2 って何だったかというと、関数 foo が呼び出された後のメモリ配置でした。
となると、このスタックフレームは、foo 関数のものです。では、foo 関数が終わったときに、どのような挙動になるかというと。
リターンアドレスを eip に入れます。そうすると、eip は、main 関数の続きの命令を指すようになります。そして、foo 関数のスタックフレームが POP されます。
ここで、eip が shell コードの先頭を指せば、shell コードの命令が、フェッチ、デコード、実行されてしまいます。
eip が shell コードの先頭を指すには、"リターンアドレスを" shell コードの先頭に指定すればよいでしょう。EIP の値が、C8 04 08 26 であればよいということです。
で、この CPU は、リトルエンディアン方式であるため、EIP の値を C8 04 08 26 にするには、メモリ上で、26 80 04 C8 とすればよいです。
ですので、答えは エ になります。
わかっている人は、「shell コードの先頭のアドレス C8 04 08 26 を EIP に入れるので、リターンアドレスが 26 80 04 C8 だったらいいよね。以上」 で、秒速で終了です。
次いきましょう。
設問 2、(3) です。5 ページの真ん中よりちょっと上、「アドレス空間配置ランダム化技術」 についてです。

いわゆる ASLR(アスラー)です。この名前は知っておきましょう。
設問 2 (2) がわかれば、セットでとれます。
この問題の事例では、攻撃者は、shell コードが、どのアドレスに展開されるかわかっていました。だからこそ、リターンアドレスを shell コードの先頭に指定できたのです。
『具体的に述べよ』 とあったので、私は、そのまま 「リターンアドレスを shell コードの先頭に指定する(行為をできないようにする)」 と解答しました。
これだと、「shell コードの先頭」 って何? となるかもしれません。正直、25 字でまとめるのは厳しかったです。
IPA の解答は、『攻撃を成功させるためのジャンプ先アドレスの特定』 です。特にコメントはありません。
設問 3 (1) です。3 ページの、下線部 ① です。

IPS とは、侵入防御システムのことです。4 層における不正なデータ(主に、OS への攻撃)を検知、破壊します。
WAF とは、Web アプリケーションファイアウォールの略です。7 層における不正なデータ(主に、アプリケーションへの攻撃)を検知、破壊します。
いずれも、あやしいと判断したデータについては、先に進めないようにします。
設問を見ると、また 『具体的に述べよ』 です。たった 25 字で、具体的に?
私は、「既知の攻撃を含むパケットを遮断する(処理)」 と解答しました。これは、ダメです。「アノマリ検知」 があることを忘れていました。あと、ぜんぜん具体的ではありません。
IPA の解答は、『インジェクションベクタを検知・破壊する』 となっています。
『インジェクションベクタ』、まんま使ってきました。本文中の言葉を使うと、2 つのメリットがあります。
- いちいち、その定義は何なのか、それが何を指すのか、説明しなくてよいため、コンパクトに収めることができる
- いっきに具体的になる
「そこまでわかっているなら、オマエ使えよ」、です。はい。ごめんなさい。
どんどんいきます。設問 3 (2) です。

私は、『あらゆる命令の実行が shell コードで可能となる』 = 「誰でも、どこからでも実行できる」 と、とらえました。
このうち、「どこからでも実行できる」 は、「shell コードの展開箇所によらない」 という意味です。これは、p.5 の冒頭にあります。なので、スルーしました。
というわけで、自分は、「権限によらず、あらゆる命令が実行できる(条件)」 としました。まずくはないと思います。
しかし、問題文中に、『ルート特権化』 という文言が、何度も繰り返し出てきています。そう、これを使えば、コンパクトにできるのです。そこででしょう。IPA の解答例は、『ルート特権があること』 となっています。
設問 4 の (1) です。

正直、何を答えてよいのか、わかりませんでした。仕方がないので、一般的なファイルシステムのアクセス制御について言及しました。こんな感じです。
「読出すファイルに、利用者やアプリからの参照権限がない場合、処理を中断する仕様」
めちゃめちゃ苦しいですね。でも、何も書かないと、100 %、0 点になりますから。。何か書きましょう。
スマホのアプリは、サンドボックス内で実行されています。サンドボックスとは、「砂場」 のことです。ある砂場から、他の砂場のリソースやデータには、アクセスできません。アクセスするには、明示的に許可が必要です。
これについて、答えてほしかったのでしょう。
設問 4 の (2) です。

この問題は、絵にある 2 箇所に着目できれば、それでおしまいです。多くの受験生がとってくると思います。
私は、本文中の言葉をできる限り使って、「データを盗み出すタイプのマルウェアに侵入された」(状況)としました。
ラスト、設問 4 の (3) です。

ポイントは、p.2 の最初の段落にあります。これは、少し見つけにくいです。国語力が試されます。
とはいえ、1 箇所見つければよいだけなので、多くの受験生がたどり着くと思います。書き負けないでください。
少なくとも、スマホの管理に M システムを使っていることは、たどり着いてください。
それでは、これまで見てきたこと、本問で得た知識を、簡単に復習しましょう。


な感じですかね。
総括です。

よく出題される、重要な技術、受験生の正解しやすさなどを鑑み、独断と偏見で、問題ごとに、ランクをつけてみました("A" ~ "C")
- "A" は、絶対にとりたいです
- "B" が半分くらい取れていれば、それで十分合格ラインを超えるという感覚です。全部とれれば、上位合格だと思います
- "C" は、時間かけてもできませんでした。設問 4 (1) なんて、ムリぢゃね?
めちゃめちゃ長文になってしまいました。最後まで読んでいただき、ありがとうございました。
安全確保支援士対策 BOF 編 [1]
このエントリでは、安全確保支援士試験の対策として、情報処理技術者試験の過去問を解説します。
過去問を解きながら、知識のインプットができるようにしたつもりです。ぜひ、問題に取り組んでいただき、その後、本エントリを見ていただければと思います。
さて、今回は、BOF(バッファオーバフロー)編 第一弾。おそらく、BOF の過去問の中では最も易しいであろう、「2007 年度(平成 19 年度)春期 テクニカルエンジニア 情報セキュリティ試験 午後 1 問 1」を解いていきます。
《問題》
情報処理技術者試験のページからダウンロードしておいてください
《凡例》
|
それでは、午後 1 の 問 1 を、解き進めましょう。
まずは、設問をながめます。

ぱっと見、ほぼほぼ BOF に関する技術的な内容です。

設問 1、まずは、a からいきます。3 ページの下、T 君のセリフの箇所です。
『バッファオーバフローの結果 [ a ] 領域に確保された変数の値が、意図に反して書き換えられる可能性』 とあります。
メモリには、いくつかの領域がありますが、バッファオーバフローの文脈では、まず、「スタック」 または 「ヒープ」 を思い浮かべてください。すぐあとに見ますが、ここは、「スタック」 が正解です。
ほぼ全ての受験生が正解したはずです。絶対に落とせません。

次に、b と c です。4 ページの一番上、T 君のセリフです。ここでは、どの変数がバッファオーバフローを起こして、どの値が書きかえられるかが問われています。
『図1 脆弱性のあるプログラム例』 を見てください。
プログラムが何をやっているのか、全行にコメントがあります。C/C++ 言語をあまり知らなくても、BOF の原理がわかっていれば解けます。
このプログラムは、13 行目で、「外部から指定された、第一引数 argv[1]」 を処理しています。strcpy 関数を見たら、ぴくっと反応しなければなりません。こいつは、バッファの上限が指定できない関数です。使うべきではありません。
この strcpy 関数を用いて、プログラム外部からの入力 argv[1] を、"ノーチェック" で、128 バイトの領域(val2)にコピーしています。入力が 128 バイトを超えると、バッファがあふれます。
c を解くには、少し前提知識が必要となります。簡単に、確認させてください。

ここでのゴールは、プログラムを実行した際の、メモリ空間がどのようになっているのか、把握することです。
この図の左の絵は、メモリ空間の全体像です。上のアドレスが 「低」 く、下のアドレスが 「高」 いことに注意してください。
その中に、「スタック領域」 と呼ばれる領域があります。
スタックというデータ構造は、ご存じだと思います。本を積み上げるイメージです。積み上がっている本の一番上に、本を置くことを、PUSH と呼び、一番上の本をとることを、POP と呼びました。このデータ構造の特徴は、「最初に積んだ本は、最後にならないととれません(FILO)」、同じことですが、「最後に積んだ本が、最初にとれます(LIFO)」 というものでした。
後でも説明しますが、関数が呼ばれるたびに、この 「本」 が積みあがっていきます。
大事なことは、スタック領域は、アドレスで言えば、高い方から低い方へと成長するということです。真ん中の絵は、上のアドレスを 「低」 く、下のアドレスを 「高」 く描いたので、イメージ通り、下から上に成長するようになっています。
逆に、「ヒープ領域」 は、上から下へ成長します。ヒープ領域とは、プログラムの実行中に、データを展開する領域です。
スタック領域に積みあがっている 1 冊 1 冊の 「本」 は、「スタックフレーム」 と呼ばれます。それが、真ん中の絵です。そのスタックフレーム(1 冊の本)のレイアウトが、右の絵になります。
「ローカル変数」 と 「引数」 は、ここに入ってきます。
このメモリのレイアウトが書けないと、本問を解くのは厳しいです。おそらく、この問題を選択した人の、大半が描けたと思います。

設問 1 の c に戻ります。
今回のスタックフレームが、どのようなレイアウトになっているかわからないと、val2 がどの領域にあふれていくか、わかりません。本問では、3 ページの最後から、4 ページの最初にかけて、val1, val2, val3 それぞれの領域の先頭アドレスが与えられています。これに従うと、右の絵のようなレイアウトになるはずです。
データは、低いアドレスから高いアドレスに格納されていきます。ですので、val2 に 128 バイトより大きなデータがやってくると、val1 の領域にあふれます。

図 1 のプログラム、13 行目にある strcpy 関数について補足します。繰り返しになりますが、こいつは、書き込みバイト数の上限を指定できない関数です。
strcpy 関数のように、文字列を扱う関数には、書き込みバイト数の上限を指定できる、代替関数があります。概ね、関数名の中に n がついた名称となっています。
この表の 3 つの関数、strcpy、strcat、sprintf 関数は、特に有名です。頭にいれておいて、損はありません。

d いきます。4 ページ、図 2 のすぐ下、S 主任の発言です。
抽象度が高い設問なので、素直に 「権限昇格」 と答えましょう。おそらく、大半の人が正解してきます。とりこぼしは厳しいです。
e と f は、いったん、とばします。先に、下線部 ① があるので、そっちをやります。

4 ページの真ん中、下線部 ① です。ふたたび、図 1 のプログラムを見てください。
19 行目のコメントに、『名前が val1 のファイルを入力ファイルとして開く』 とあります。そこで、val1 の値が 'afile' になるようにデータをいじればよいとわかります。
この絵の、ローカル変数の部分を拡大してみます。

ローカル変数 val1, val2, val3 の箇所を拡大すると、これらは、メモリ内では、左の絵のように展開されています。上から val3, val2, val1 となっています。val1 には、'somefile' と格納されています。
最後の \n は、文字列の終端を表す値です(メモリ上には 0x00 と展開されます)。「文字列はココまでですよ」 と教えてくれる値です。NULL(ヌル, ナル)文字や、EOS(End of String)などと呼ばれています。
ですので、コマンドラインに、128 byte 分データのあとに、'afile' という文字列を入れてあげると、val2 がオーバフローし、右の絵のような状態になります。
val2 を 「c」 で埋めましたが、何でもよいです。
なお、コマンドラインの引数(文字列)は、メモリ内に展開した際に、自動的に NULL 文字が追加されます(でないと、どこまでが引数で指定した文字列なのか、わかりませんから)。

ということで、[ ア ] は、128 byte でした。面倒なバイト計算は、一切ありません。わかる人は、瞬殺です。
できれば正解したいところです。とれなくても、これが致命傷にはならないと思います。

さて、設問 1 の [ e ] に戻ります。
ここも、少しだけ、前提知識が必要なので、確認させてください。

ここからのインプットのゴールは、関数呼び出し時のスタックの様子についてイメージをわかせることです。
右にある、main 関数から next 関数を呼び出すプログラムについて、検討していきます
(next 関数の処理は、何でもよいのですが、ここでは、引数に 1 を足して返します)。
大きな流れは、こんな感じです。
- next 関数を呼び出す
→ スタックフレームを生成し、スタック領域へ PUSH します。後で戻ってこられるように、今、自分がいる位置を、スタックフレームに入れておきます - next 関数を終了する
→ next 関数が呼び出される前の状態に戻して、スタックフレームを POP します
なんとなくつかめたら、細部を見ていきましょう。

左の絵も、右の絵も、メモリ空間の一部を表しています。左は、「命令コード領域」 で、まさに、ソースコードに書いた処理を実現するための命令が入っています。CPU は、ここから命令をとってきて、解釈して、実行します。とってくることを 「フェッチ」、解釈することを 「デコード」 と呼んだことを思い出してください。
まず、左の絵 「命令コード領域」 を見てください。
CPU がどの命令をとってきて実行するかというと、「EIP レジスタ」 に格納されているアドレスからです。
レジスタとは、CPU の記憶回路(CPU 内で、データを保持するところ)です。例えば、Intel の x86 という CPU には、16 個のレジスタがあります。その中に、EIP(インストラクションポインタ)と呼ばれるレジスタがあります。ここに、実行する命令を指し示すアドレスが入っています。
ごちゃごちゃ言いましたが、つまりは、「EIP が指すところから命令をフェッチ、デコード、実行する」 というわけです。
右の絵は、おなじみ、スタックフレームです。今は、main 関数のフレームがスタックされています。
左の絵では、EIP は main 関数の命令の先頭を指しています。ここから、順に命令を実行していきます。

main 関数の、最初の命令を実行すると、EIP の値がカウントアップされ、次の命令を指します。そこから、フェッチ、デコード、実行です。

main の命令を、次々に実行していきます。
状況が大きく変わるのは、main 関数が、next 関数を呼び出したときです。next 関数の命令は、main 関数とは別のところにあります。next 関数が、複数の関数から呼び出されることを考えると、合理的ですよね。このため、EIP の値は、大きく変わり、next 関数の先頭を指します。next 関数の最初の命令まで 「ジャンプ」 するわけです。

このとき、next 関数のスタックフレームをつくり、スタック領域に PUSH します。スタックフレームに、引数やローカル変数の情報が入るのは、これまで見てきた通りです。
ここでもう一つ、スタックフレームに、戻りアドレス(リターンアドレスとも呼びます)RET を入れています。
これは、next 関数の処理が終了した際に、元の処理、つまり、呼び出し元である main 関数の続きの処理ができるようにするためです。
そして、EIP の値に、next 関数の命令があるアドレスを格納し、ジャンプします。

next 関数の命令を実行しています。

さて、next 関数の処理が終了しますよ。

きました。緑の矢印です。EIP に、戻りアドレス(RET)の値を入れて、ジャンプです。呼び出し前の位置まで戻ってきました。

next 関数のスタックフレームを POP します。これによって、きれいに、main 関数の続きが実行されていくのです。
この挙動を、おさえておきましょう。

まとめます。もう一度、冒頭で説明したことを繰り返します。この ① ~ ④ の動きがわかっていれば、目標達成です。
● next 関数を呼び出す
① スタックフレームを生成し、スタック領域へ PUSH します。
その際、後で戻ってこられるように、① 今自分がいる位置を、
スタックフレームに入れておきます。
② next 関数の命令にジャンプします。
● next 関数を終了する
③ next 関数が呼び出される前の状態に戻して、
④ スタックフレームを POP します。

ようやく [ e ] です。解答の骨格は、「関数」 となります。
しかし、他の選択肢と異なり、これだけ 「6 字以内」 と、字数が少しだけ多くなっています。単に 「関数」 という答えでは、満点はもらえないと思います。
この問題文中に、こんなセリフがあります。『戻りアドレスが書き換えられてしまう』 と。この、最も典型的な例に、触れておきます。
攻撃者は、「偽の戻りアドレス」 と 「悪意のコード」 の両方が含まれるデータを使って、バッファをあふれさせます。もちろん、戻りアドレスの領域も、攻撃者の用意したデータで上書きされます。そのとき、戻りアドレスの領域を悪意のコードの先頭になるように調整します。そうすると、スタックフレームが POP したときに、自分の用意したコードを実行することができるのです(このようなコードを、「shell コード」 と呼びます)。
となると、BOF の脆弱性を悪用されると、任意のコードが実行される可能性があります。

続いて、5 ページの上、[ f ] です。
『malloc 関数などによって、[ f ] 領域に確保された変数』 とあります。そのすぐ下には、『[ a ] 領域と [ f ] 領域に確保された変数については』 ともあります。
malloc 関数は、指定されたバイト分、「ヒープ領域」 のメモリを確保する関数です。使用後には、free 関数を呼び出して、確保していたメモリを開放する必要があります
答えは、「ヒープ」 です。絶対におとせません。

設問 2 の (2) です。'afile' の内容が表示されてしまうことによる、セキュリティ上の問題が問われています。
管理者のみが read/write できるところ、一般利用者でも read/write できるということは、すぐにわかります。
私は、それ以上は書けませんでした。。
採点講評には、次のようにあります。
『・・・ afile の内容の表示についてだけ記述した解答が多かった。・・・ 任意のファイルの内容を表示できることに気づいてほしかった』
これ、大部分の人は、わかってたと思いますけど、、まぁよいです。
『afile の内容の表示についてだけ記述した解答が多かった』 とあるので、合否に影響する問題ではないと、信じたいです。

問題文中に、BOF の対策が書いてあるので、少しだけ補足します。
5 ページ [ f ] の近く T 君のせりふに、『どちらもプログラム作成上の対策は同じと考えてよい』 とあります。
これは、「スタックオーバフローも、ヒープオーバフローも、想定したメモリ領域があふれることに起因しているから、メモリ領域を超えないように、チェックすればよい」 と、考えたからでしょう。
その後の S 主任のせりふに、『バッファオーバフローを防ぐ根本的な対策は、ループ文の中で配列への書き込みを行う場合や、組み込み関数を使う場合などで、方法が異なる』 とあります。なので、コーディングルールとしては、状況に応じて、対策を示す必要があります。
例えば、バッファへの書き込みを、ループで処理するときには、バッファの境界チェックを、ループの終了条件に含めることが対策になります。一方、組み込み関数を使うときには、危険な関数を使わず、安全な関数を使うことが対策になります。何が危険で、どうすれば安全に実装できるのか、示す必要があります。

設問 2 の (3) です。
文章で解答する場合は、50 字以内です。かなり簡潔に書かなければなりません。
strcpy が、「無制限に」 文字列をメモリに書き込むからあふれます。なので、入力を、128 バイト未満に制限してあげないといけません。128 バイトぴったりだと、NULL 文字があふれてしまうので、「以下」 ではなく 「未満」 としなければなりません
解答には、「かつ」 と 「128 バイト未満」 が必須となるでしょう。
私は、次のようにしました。
「条件文を、コマンドライン引数が 1 より大きく、かつ、この引数の長さが 128 バイト未満であるとする」 です。
IPA の解答のように、『論理積として加える』 などという表現は、私には、なかなかでてきません。

コードで書くと、とてもシンプルになります。ただし、(1) 論理積が && になること、(2) 文字列の長さを取得するのに strlen 関数を使うこと、の 2 つがわからなければ、書けません。
私は、文章で書きました。strlen 関数に自信がなかったからです。

設問 3 です。下線部 ② にいきましょう。プログラミング以外で、BOF を緩和する方法についてです。
完全に知識問題です。もう、知らなかったら書けません。
結論、ローカル変数と SFP(スタックフレームポインタ)の間に、推測されない値(一定の桁数の疑似乱数)を挿入します。普通にプログラムを実行している場合には、この値は変わらないはずです。これが変わったことを検知し、プログラムを停止する仕組みがあります。
このような、推測されない値を、「カナリア」 や 「クッキー」 と呼びます。

この、IPA の解答例程度の内容を把握しておけば、十分だと思います。

コンパイラや実行環境で、BOF を緩和する方法については、5 ページ中央の T 君のセリフにあります。
・ DEP(Data Execution Prevention)
・ Libsafe など
もう 1 つ付け加えるのであれば、
・ ASLR(Address Space Layout Randomization)
です。ここに書いた程度のことを、おさえておきましょう。
それでは、これまでやってきたことを簡単に復習しましょう。

まず、メモリ空間です。
- メモリ空間には、「スタック領域」 と 「ヒープ領域」 がありました
- 「スタック領域」 は、我々のイメージとは逆に、高いアドレスから低いアドレスに向かって成長しました
次に、関数呼び出しです。
- スタック領域には、関数が呼び出されるたびに、スタックフレームが PUSH されました
- スタックフレームには、引数、ローカル変数、リターンアドレス、スタックフレームポインタがありました
- 関数が終了すると、リターンアドレスを使って、元のアドレスに戻り、スタックフレームは POP されました
最後に BOF です。
- 想定を超えるサイズのデータにより、メモリ上のバッファがあふれると、例えば本問であれば、任意のファイルが開かれる可能性がありました。RET を書き換えることで、任意のプログラムを実行される可能性もありました
- プログラミングでの対策は、プログラム外の値が、想定している領域からオーバフローしないように実装することでした。例えば、(1) サイズをチェックしてから、確保した領域にデータを格納する(2) strcpy 関数を strncpy 関数に変更し、サイズの上限を指定する
- コンパイラや実行環境により BOF を緩和させる技術として、カナリア値をはさむこと、DEP、Libsafe、ASLR を紹介しました

独断と偏見で、なんとなくランク付けしてみました。
- [A] は、必ずとりたい問題です
- [B] は、できればとりたい問題です
- [C] は、ぶっちゃけとれなくても、合否に影響がない(だろう)問題です
- [A] をとり、[B] を半分くらいとれば、十分合格ラインを超えると思います
最後まで読んでいただき、ありがとうございました。
速習・ペンテスト(Linux BOF)
前回の続き。「Windowsだけではなく、Linux でもやってみよう」 という問題。やり方は、おおむね前回と同様で、しかもうまくいったので、メモは少しだけにする。
使ったデバッガは、もちろん異なる。Kali Linux には、edb-debugger という GUI のデバッガが同梱されているので、これを使った。
まずは、文字 "A"(0x41)の数を、少しずつ増やして送り込み、サーバをクラッシュさせる。
次に、一定のパターンを持った文字列を生成して、そのデータを投入する。これにより、EIP に格納された値が、「生成したパターンの、どこに含まれているのか」 について調べることができる。
これで、下の図の 1 のデータを投入することで、EIP にピンポイントで "BBBB" を格納することに成功する。簡単ではあるが、EIP の制御は、攻略できた(さらに、EAX および ESP のアドレスに格納される値も、自由に変更できた)。
この問題で少し面倒だったのは 2 つ。(1) EAX が指すデータの先頭に、必ず 「XXXXXXXXXXX 」 がくっついてくること、(2) 文字列 「C」 が 7 文字しかなく、シェルコードが格納しにくいこと。
そこで、プログラムの実行の流れを強制的に変えて、「AAAA … 」 の箇所に、シェルコードを投入することを検討する。
まずは、プログラムの中から JMP ESP を探す。JMP ESP の実行が制御できると、自分の好きなタイミングで、ESP に格納されているアドレスに、ジャンプできるからだ。すでに、EIP は制御できる。なので、「BBBB」 の箇所(つまり EIP の値を上書きする箇所)を、JMP ESP があるアドレスに書き換えることで、プログラムの流れを変えることができる。プログラムの制御は、命令 JMP ESP の箇所にとばされて、この命令が実行されることで、すかさず ESP が指すアドレス(つまり 「CCCCCCC」 の箇所)にジャンプする。
ちょっとだけ工夫が必要なのは、その後、「AAAA … 」 の箇所に制御を移すところ。といっても、EAX から 「XXXXXXXXXXX [space](12 バイト)」 先へジャンプすればよいだけ。つまり、「CCCCCCC」 の箇所で、ADD EAX, 0Ch して、JMP EAX すればよい。
これらの命令のバイト列を 「CCCCCCC」 の箇所に書き込んでおくことで、目的地へのジャンプが実現できる(余ったところには、何もしない命令 NOP を入れて、つじつまを合わせておく)。
こんなもん。




