情報処理技術者試験で学ぶ SAML

勉強会用に、急いで作りました。土日しんだ。

とりあえず、見切り発車(0.9.1版)で公開します。これで乗り切るしかない。

 

よかったら、SlideShare のページから、ダウンロードしてください。

 

間違いがあったら、指摘いただけるとうれしいです。

新人教育 ~ 言葉を選び、よく対話すれば、学びは深くなる

あしです。

今日、「ゼロから教えて 新人教育」という書籍を読んだので、学んだことをシェア(ウソ、メモ)しておきます。

絵や図が多いので、さらっと頭に入れるには、とてもよい書籍だと思います*1

ゼロから教えて 新人教育

ゼロから教えて 新人教育

  • 作者:大部 美知子
  • 発売日: 2014/02/25
  • メディア: 単行本(ソフトカバー)
 

まず、なぜこの本を読んだのか、その背景と目的について書きます。

次に、この本から、何を学んだかについて書きます。

最後に、明日からのアクションプランを書いて、終わりにしようと思います。

 

| なぜ読んだのか?

- 背景

どうやら、今年度の春に入社してくる社員さん(以下、新人さんと呼びます)たちと、少しの間、同じ時間を過ごすことになりそうです。

 

これまで、テクニカルな研修(ネットワーク、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)という話し方のテンプレートです。

 

これは、ライティングにも、そのまま活かせるテンプレートですね。

 次の書籍にも、類似のテンプレートがあります。

世界一ラクにスラスラ書ける文章講座

世界一ラクにスラスラ書ける文章講座

  • 作者:山口 拓朗
  • 発売日: 2019/12/18
  • メディア: 単行本(ソフトカバー)
 

 

ライティングに関しては、マナブさんのブログ manablog のエントリでも、類似のテンプレートが、紹介されています。

有料級の情報です。まぢに、読んでおくとよいです。

 

【完全に解決】文章が書けない原因は「型」にあります【必読ですよ】 

   https://manablog.org/blog-writing-structure/

聴き方

リーダーは、「意見を聴くときは、安易に話を切るべきではない」ことを学びました。具体的には、こんな感じだと NG です。

  • それ、誰かに言われたの? プイっ
  • みんなそんなもんだけど。プイっ
  • まだ、仕方ないのでは? プイっ
  • 昨日の失敗のせいだね。 プイっ
  • 目線が低いのでは? プイっ

 

このあたり、マコなり社長の発信が、感動レベルなので、紹介しておきます。

 

【厳禁】実は気づいていないパワハラ発言 TOP5

    https://www.youtube.com/watch?v=AtpDeDkBzrg

叱り方

叱るときは、事前に内容をよく吟味すべき」ことを、学びました。具体的には、次のように叱ればよいとなりました。

  • 人格否定しない。行動を叱る
  • 本質をつかみ、伝えることを絞る
  • 事実と感情を分ける。冷静になる
  • 短時間で伝える
  • 過去のことをひっぱり出さない
  • 他人と比較しない

 

このあたりについても、マコなり社長の発信が、感動レベルなので、紹介しておきます。

 

  絶対にやってはいけない「人の叱り方」トップ 5

    https://www.youtube.com/watch?v=QxiyXkGE0g0

 

| アクションプラン

スタートまでの時間が短いので、もうやるしかないです。 

 

◆『指導プラン』は、他の部隊が作成済み。明日と明後日で、しっかり理解する

◆ 明日と明後日で、新人さんの情報をインプットする

 

 

◆ 次のような箇所をピックアップする。今すぐ、それらを暗記する

  • 意識しなければ、やることを忘れてしまいそうな箇所
  • ダメだとはわかっていても、やってしまいそうな箇所

 

- おまけ 1

部下の育成については、やはり マコなり社長 の動画が感動レベルなので、紹介しておきます。

部下の育成に関するエッセンスが、さらに圧縮されて 15 分程度にまとめられているため、ものすごく濃い内容となっています。おススメです。

 

上司の 9 割は「育て方」を知らない

    https://www.youtube.com/watch?v=0NHkILdM-bk

 

ちなみに私は、この動画を繰り返し繰り返し見ています。控え目に言って、20 回くらいは見たかな。メモも、完璧にとっています。

 

 - おまけ 2

最近は、↓ この書籍の影響を受けています。

すべての知識を「20字」でまとめる 紙1枚!独学法
 

本エントリでも、自分が学んだ内容をヒトコトで言うときは、だいたい 20 字くらいにしています。

*1:とはいえ、情報の密度が小さいため、「超おススメ」というわけではありません

*2:書籍中の言葉ではありません。私が勝手につけた名前です

*3:when(期限、日程), who(担当者や関係者), where(場所), what(要件、目的), why(理由), how(手段、方法), how much/many(予算や費用、量や数), result(事後の対応)

応用情報・午後・セキュリティを解く(R01春)その 1

あしです。こんにちは。

今回は、応用情報処理技術者試験、2019 年度(令和元年度)、午後 問 1 を解いていこうと思います。「早速、設問 1 から」といきたいところですが、先に、電子メールに関する知識が問われている、空欄 b と c を片づけておこうと思います。

 

今回は、「送信ドメイン認証」、「S/MIMEPGP」、「OP25B」 について解説します。これらのタームについて、「知らんぞ」という方は、ハイライトの箇所だけでも、眺めていただけると、勉強になると思います。

 

電子メールに関するセキュリティについては、午前問題はもちろんのこと、「平成 27 年度 春期 午後」にも、がっつり出題されています。過去問をしっかりつぶしていた人は、ごっそり得点できたはずです。

 

|【おさらい】SMTP

 

まずは、メールに関するプロトコルのおさらいから。この絵は、左の人から、右の人までメールが届くまでのイメージを表したものです。

f:id:higher_tomorrow:20200219101727p:plain

 

まず、クライアントからメールサーバに SMTP で送信、次に、メールサーバから次のメールサーバまで SMTP で転送、最後に、メールを見るために、IMAP4 や POP3 を使いました。

 

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

f:id:higher_tomorrow:20200219101813p:plain

 

まずは、ポート番号 25 番に対して、TCP のコネクションを張ります(3 ウェイハンドシェイクと呼ばれる通信によって、コネクションを確立します)。

そのコネクションを用いて、メールサーバに対し、HELO、MAIL FROM、RCPT TO などのテキスト(SMTP のコマンド)を送信します。

DATA コマンドの後に、メールの From、To、タイトル、本文などを送信します。

QUIT コマンドを送信し、TCP のコネクションを切断します。

 

これを見ると、メール中の「送信元アドレス」は、簡単に書き換えられることがわかると思います。だから、送信ドメイン認証が必要になるんです。

 

| 送信ドメイン認証

 

空欄 b、c で問われているのは、送信ドメイン認証についてです。有名な方式に、SPF と DKIM(ディーキム)があります。

 

1. ポイント

もぅ細かいことはよいので、コレをおさえます。 

  • 送信ドメイン認証 = メールの送信元ドメインが詐称されていないことを検証する

  • SPF = IP アドレスによる検証(送信元の DNS サーバに IP アドレスを登録)
  • DKIM = デジタル署名による検証(送信元の DNS サーバに公開鍵を登録)

 

2. 過去問知識

送信ドメイン認証についての、過去問を見ていきます。

「平成 27 年度 春期 午後」の問 1 には、次のような記述がありました(ハイライト等は筆者にて加工)。

メールサーバでのメール受信時の送信元メールアドレス偽証されていないかのチェックは [    a    ] と呼ばれ、送信元 IP アドレスを基にチェックする技術(SPF、又は受信メールの中の電子署名を基にチェックする技術(DKIMを導入します。

《平成 27 年度 春期 午後 p.6 》

 

上記の空欄 a の解答が、まさに「送信ドメイン認証」でした。

 

SPF については、平成 28 年度 秋期の午前問題でも出題されています(ハイライト等は筆者にて加工)。

(問 43)

受信した電子メールの、送信元ドメイン詐称されていないことを検証する仕組みである SPF(Sender Policy Framework)の特徴はどれか。

(正 解)

受信側のメールサーバが、受信メールの送信元 IP アドレスと、送信元ドメインの DNS に登録されているメールサーバの IP アドレスとを照合する 。

 

この 問 43 にある通り、SPF の動作は、こんな雰囲気になります。だいたいのイメージがあれば十分です。

f:id:higher_tomorrow:20200219145658p:plain

 

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)は公開鍵の交換を事前に当事者間で行ない、その間で電子署名暗号化されたメールのやり取りを可能にする仕組みである。

《 IPA 電子署名・認証技術の適用分野と利用技術に関する調査PGP を利用した電子メールの例」》

 

公開鍵の交換は、手渡しや 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 があるとします。

f:id:higher_tomorrow:20200219161924p:plain

 

攻撃者は、右の人(青)に、スパムメールなどを送ろうとします。

しかし、OP25B により、ISP-A から外へ出ていく SMTP の通信がブロックされます。つまり、この経路では、ISP-A のメールサーバを通らずに、ISP-B のメールサーバに直接アクセスすることができません。

例えば、ISP-A のメールサーバに、送信元 IP アドレスによる制限がかかっていたりすると、レンジ外の攻撃者は、右の人に、標的型攻撃のメール、スパムメールなどを送ることができなくなります。

あ。仮に、攻撃者や攻撃者のボットが、 ISP-A と契約しているのであれば、普通にメールサーバ経由で、メールを送信することができますよ。当たり前ですが。

 

では、「ISP-A の管理下にいない人には、ISP-B のメールサーバへアクセスする方法はないのか」というと、あります。

f:id:higher_tomorrow:20200219162030p:plain


それは、ISP-B のメールサーバで認証をかける方法です。

「きちんと認証された人なら、メール送信してもいいよ」ということです。

認証をかけるには、SMTP-AUTH などの認証機能のついたプロトコルを用います。このとき使うポートを、「サブミッションポート」と呼びます。 

 

今回は、いったんこれで、終わりにします。次回は、残りの問題の解説をします。

最後まで読んでいただき、ありがとうございました。 

(次回へ続く)




 

 

安全確保支援士対策 BOF 編 [3]

こんにちは、あし です。

このエントリでは、安全確保支援士試験の対策として、情報処理技術者試験の過去問を解説します。

過去問を解きながら、知識のインプットができるようにしたつもりです。問題に取り組んでいただき、その後、本エントリを見ていただければと思います。

時間がなければ、問題を見ながら、さらっと読んでいただければよいと思います。さらに時間がなければ、絵だけ見ながら、流せばよいと思います。

 

さて、今回は、BOF(バッファオーバフロー)編 第三弾。「2016 年度(平成 28 年度)秋期 情報セキュリティスペシャリスト 午後 1 問 2」を解いていきます。

 

《問題》

    情報処理技術者試験のページからダウンロードしておいてください

《凡例》

  • 『・・・』は、問題文からの引用を表します
  • (解答)は、IPA が発表した解答例を表します

 

それでは、午後 1 の 問 2 を、解き進めましょう。

前回同様、まずは、設問をながめます。

f:id:higher_tomorrow:20200217093742p:plain

ざっと、こんなことがつかめれば、十分だと思います。

  • 選択式の穴埋め a ~ d → 選択肢が 4 つしかない → サービス問題?
  • 設問 2 とは、ガチで BOF っぽい
  • 設問 3 は、変な文字列選択するようになっているし、修正用のコードもある、もっとガチかも
  • 設問 4 は、BOF の対策っぽい

 

頭から、設問 1 a からいきましょう。6 ページの真ん中らへんです。

f:id:higher_tomorrow:20200217093746p:plain

速攻で、CVE-ID → CVE 識別子です。出血、大サービス問題です

  このあたりをおさえている人が多いと思います

  • 脆弱性情報のデータベースの 1 つ
  • 各ベンダーが公表する脆弱性情報がバラバラだったので、それらをまとめて、共通したユニークな識別番号をつけた
  • アメリカの MITRE(マイター)社が運営している

 

設問 1 b と c です。

f:id:higher_tomorrow:20200217093751p:plain

これらは、もしや 「マグネット売場」 なのでは?

もとい。

ここに挙げられた、「ゼロデイ攻撃 + 標的型攻撃」 には、高い確率でヤラレると思います。出題の裏には、相当な危機感があると思われます。

 

本問を選択したほぼ全ての受験生が正解したでしょうね。

 

設問 1 d です。

f:id:higher_tomorrow:20200217093755p:plain

 ファジング(Fuzzing)とは、ファズ(fuzz)と呼ばれる、問題を引き起こしそうなデータを大量に送り込み、その応答や挙動を監視することで、脆弱性を検出する検査手法になります。

ちょっと脱線しますが、ここに出てくる 「静的解析ツール」 とは、ソースコードの段階で、脆弱性を含む不具合を検知してくれるツールです。

特に、セキュリティ面を重視した静的解析を、SAST(Static Application Security Testing)と呼んだりします。これは、DevSecOps(セキュリティを維持したまま、リリースの頻度を高めること)を実現するための、重要な要素となってきています。このあたり、SE っぽいでしょ?

 

戻ります。

設問 2 に入ります。

f:id:higher_tomorrow:20200217093758p:plain

また、この問題ですか。何度でも、きいてきますね。

『関数呼び出し時にスタックに必ず積まれる』 は、スタックフレームです。

『何の値を書き換える』 は、スタックフレームに入っている値のいずれかです。

別に、怒っていませんよ。

 

# インプット ここから ---

念のため、スタックフレームのレイアウトを確認させてください。

またこの絵です。

f:id:higher_tomorrow:20200217093802p:plain

 

  • 左の絵は、メモリ空間の全体
    上のアドレスが 「低」 く、下のアドレスが 「高」 い
    ことに注意してください(スタック領域は低い方に、ヒープ領域は高い方に成長します
  • 真ん中は、スタック領域(スタックが積み重なっている)
  • 右の絵は、スタックフレームのレイアウト(ローカル変数、スタックフレームポインタ、リターンアドレス、引数)

ここで、スタックフレームポインタ(SFP)と、リターンアドレス(RET)が何だったかというと、

  • スタックフレームポインタ →(呼び出し元関数の)スタックフレームの基準となるアドレス。1 つ下のスタックフレームがどこにあるのか
  • リターンアドレス → (呼び出し元関数の)命令があるアドレス。この関数が終わったとき、どこに戻ればよいのか

です。

# インプット ここまで ---

これを踏まえて、設問に戻ります。

f:id:higher_tomorrow:20200217093807p:plain

「リターンアドレス」 には、今の関数の処理が終わったとき、どこに戻ればよいのか、そのアドレスが格納されています。

 

リターンアドレスの領域が書き換えられるということは、次に実行する命令を、好きな場所に指定できるということです。

 

スタックベースの BOF 脆弱性がある場合には、ローカル変数に確保した領域より大きなデータが投入されると、データがリターンアドレスの領域にあふれます。

 

リターンアドレスを都合のよい値に書き換えれば、プログラムの制御を奪える = 好きなコードを実行できるのです。

 

過去には、① shell コードの実行、② 共有ライブラリ内の関数であって、かつ、任意のプログラムを実行できる関数(e.g. libc 共有ライブラリ)の実行なんかが、出題されました。

 

次に移ります。

f:id:higher_tomorrow:20200217093811p:plain

いわゆる、setuid や SUID(Set User ID)と呼ばれるものです。問題文中に、丁寧な説明がありますので、知らなくても解けます。

ただ、setuid、setgid を悪用し、権限昇格を図る手法は、とても有名なので、ここで覚えてしまいましょう。再び問われる可能性があります。

 

ls コマンドの結果です。

f:id:higher_tomorrow:20200217093816p:plain

上の 2 行は、ディレクトリなのでムシしましょう。「.」 が、現在のディレクトリを表し、「..」 が、一つ上のディレクトリを表します。

 

本問では、所有ユーザに注目します。

まず、4 つのファイルとも、ユーザ suzuki に、読み取り権限、実行権限があります(書き込み権限はありません)。

パーミッションが、「rwx(リード / ライト / 実行)」 や 「r-x(リード / 実行)」 であれば、すべて、suzuki 権限で動作します。

さて、『実行権限の属性に "s" が表示されているファイルは、ファイルの所有権限で実行される』 とあるので、suzuki で起動しても、root 権限で実行されるケースは

  • 所有ユーザの実行権限 s になっている
  • 所有ユーザが root である

場合になります。それって、sample2 ファイルのみですね。

まとめます。

f:id:higher_tomorrow:20200217093820p:plain

この 3 つの条件を満たすファイルを選べばよいです。

  • 実行権限の属性が "s" である
  • 一般利用者 suzuki によって起動できる
  • ファイルの所有者が root である

ア の、sample2 ですね。

 

設問 3 です。まいります。

f:id:higher_tomorrow:20200217093825p:plain

まずは、プログラムを見ましょう。スライドには、「図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 引数で指定した文字列と一致したときに、認証が成功します

 

プログラムがやっていること(左)と、メモリのレイアウト(右)をまとめてみました。↓ ココまで整理できていれば、正解は、すぐそこです。

f:id:higher_tomorrow:20200217093829p:plain

なお、右のメモリのレイアウトは、一例です。ヒープ BOF の脆弱性があるということは、uid の領域があふれ、pass の領域を侵食するだろうことだけ意識して書けばよいと思います。

この問題は、けっこう悩みました。正解以外の選択肢が、あまりにも意味不明だったからです。

 

整理できたら、あとは具体的に値を入れてみればよいです。

f:id:higher_tomorrow:20200217093834p:plain

第 1 引数をメモリ領域にコピー(strcpy)し、パスワードの領域まで侵食します。

その後、パスワードの領域にある値と、第 2 引数とを比較します。

つまり、第 1 引数の下 8 桁が、第 2 引数の 8 桁と同じになる場合には、認証が成功します。

ふぅ。

 

設問 3 の (2) は、もうよいでしょう。

f:id:higher_tomorrow:20200217093838p:plain

次いきます。

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

f:id:higher_tomorrow:20200217093841p:plain

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 バイト以上の値はコピーできません。これらが正解となります。

 

 

ここでまた、少しだけ、知識の確認をさせてください。

f:id:higher_tomorrow:20200217093845p:plain

  • strcpy は、文字列 str をコピー cpy する関数として、これまで何度も問われてきました。対策として、str"n"cpy を使って、バッファの上限を指定することを、知っていなければなりません。
    ちなみに、"n" なしの、単なる strcpy は、バッファの上限を指定できませんでした。
  • memcpy も、有名な関数です。メモリ mem の内容を、コピー cpy します。見聞きしたことがあるのではないでしょうか。なければ、ココで覚えておきましょう

今回のケースでは、argv[1] の指す領域を、UID_SIZE+1 バイト分、uid が指す領域へ、コピーします。

memcpy、strncpy、どちらも、BOF に脆弱となりうる 「ど典型」 の関数なので、覚えておきたいです。

以上です。

 

設問 4 に突入です。

f:id:higher_tomorrow:20200217093849p:plain

設問で、『引数が同でも』 とあります。当然、プログラム Y の書き換えはないため、実行する 「処理も同じ」 となります。

となると、「メモリの配置が異なる」 しかありません。

「その実行環境」 では、メモリの配置が異なるということです。

とはいえ、新たなメモリの配置が固定であれば、その配置が悪用される可能性があります。なので、「メモリ配置が毎回異なる」 となればよいです。

全くわからなくても、ココまでは、書きたいです。

 

あとは知識があるかどうかです。基礎知識である 「ASLR」 を知っているかどうかです。

f:id:higher_tomorrow:20200217093853p:plain

ASLR は、2014 年度(平成 26 年度)秋 の試験で、出題されました。

なので...

あら?

IPA の解答が、ASLR に限定していない。なんで、この解答になるのか、わかりません。ごめんなさい。

後ろ髪を引かれつつも、スルーして、(2) に移ります。

f:id:higher_tomorrow:20200217093858p:plain

これも、知識問題と言わざるをえないです。DEP のざっくりとした仕組みがわかっていれば十分ですが(過去問をやれば、どの程度の深さで技術をおさえればよいか、わかります)。

 

スライドには、DEP を全く知らない場合の思考を書いてみました。いけなくはないですが、、かなり厳しいです

ただ、何か書かなければならない場合には、こんな感じで推測するしかありません

f:id:higher_tomorrow:20200217093902p:plain

DEP とは、テキスト領域以外、つまり、ヒープ領域やスタック領域にあるコードに印をつけ、そこからコードが実行されると、プログラムを異常終了させる仕組みです。

私は、「ヒープ領域にあるコードが実行されるわけではないから」 とか、

「ヒープ領域の操作が問題で、テキスト領域のコードを実行するから」 と解答を作成しました。

 

30 字でまとめるのは、まぢで厳しいです。

 

それでは、これまで見てきたこと、本問で得た知識を、簡単に復習しましょう。

f:id:higher_tomorrow:20200217093911p:plain

f:id:higher_tomorrow:20200217093915p:plain

な感じですかね。

 

総括です。

f:id:higher_tomorrow:20200217093920p:plain

総括です

よく出題される、重要な技術、受験生の正解しやすさなどを鑑み、独断と偏見で、問題ごとに、ランクをつけてみました("A" ~ "C")。

  • "A" は、絶対にとりたいです。これだけでも、合格ラインを超えるかもしれません
  • "B" が、いずれか取れていれば、十分合格ラインを超えると思います
  • "C" は、時間かけてもできませんでした。この道の専門の人ならできるのでしょうが

 

今回も、長文になってしまいました。だらだら書きすぎですね。慣れてきたら、だんだん「コンパクトに」まとめていこうと思います。

 

最後まて見ていただき、ありがとうございました。

安全確保支援士対策 BOF 編 [2]

このエントリでは、安全確保支援士試験の対策として、情報処理技術者試験の過去問を解説します。

過去問を解きながら、知識のインプットができるようにしたつもりです。問題に取り組んでいただき、その後、本エントリを見ていただければと思います。

時間がなければ、問題を見ながら、さらっと読んでいただければよいと思います。さらに時間がなければ、絵だけ見ながら、流せばよいと思います。

 

さて、今回は、BOF(バッファオーバフロー)編 第二弾。「2014 年度(平成 26 年度)秋期 情報セキュリティスペシャリスト 午後 1 問 1」を解いていきます。2007 年度に比べると、難易度が上がっているように感じました。

難易度が上がれば、他の受験生の出来も悪くなるので、過度に心配する必要はないです。

 

《問題》

    情報処理技術者試験のページからダウンロードしておいてください

《凡例》

  • 『・・・』は、問題文からの引用を表します
  • (解答)は、IPA が発表した解答例を表します

 

 

それでは、午後 1 の 問 1 を、解き進めましょう。

前回同様、まずは、設問をながめます。

f:id:higher_tomorrow:20200216061402p:plain

選択式の穴埋め、フリーの穴埋め。
記述問題 20 字 ~ 40 字(これだと、1 ~ 2 トピックしか入りません。フリーの穴埋めプラスアルファくらいのイメージです)。

問題も眺めます。四角 a ~ d の前後、下線部 ① ~ ⑤ を確認します。
テーマは BOF で、設問 2 はガチ。設問 3 には、IPS と WAF が登場 → なので、純粋な BOF の話ではなさそう。設問 4 は、BOF ではなさそうです。

 

頭から、設問 1 a からいきましょう。3 ページの上の方です。

f:id:higher_tomorrow:20200216061405p:plain

すぐに、「パッチ」 とか 「修正プログラム」 などが思いつかないと、ヤバいです。ほぼすべての受験生がとってきます。

「[  a  ] の適用」 が、「ソフトウェアの更新」 と並列になっているので、解答に 「セキュリティ」 という文言は入れたいです。
なので、答えは 「セキュリティパッチ」。これしかないんじゃないかなと思います。

 

設問 1 の b です。3 ページ真ん中らへんです。

f:id:higher_tomorrow:20200216061410p:plain

スタックバッファオーバフロー攻撃ときたら、だいたい、「ヒープ」 バッファオーバフロー攻撃ですw

これも、他の受験生は、間違いなくとってきます。

 

設問 1 の d です。5 ページの真ん中よりやや上です。

f:id:higher_tomorrow:20200216061413p:plain

で、私は、知らんかったです(チーン)。

ちょいと調べたところ、かなり有名な攻撃名であるため、名前、覚えておきます。

 

どのような攻撃なのかわからない、という方は、設問 2 の解説を見た後に、戻ってくるとよいです。

 

図1 のコードは、問題を解く際には、あまり関係ないのですが、一応、触れておきます。

f:id:higher_tomorrow:20200216061418p:plain

この 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 択であることがわかります。

f:id:higher_tomorrow:20200216061422p:plain

スタック BOF では、攻撃者がスタック領域に 「注入した」 shell コードが実行されます。この後、説明します。

通常のコードでは、事前に、テキスト領域に展開された命令が実行されます。ですので、この場合は、「スタック領域にあるコードは実行しない」とすればよいです。

解答は、そのまま、「スタック領域に適用すればよい」 となります。まんまなので、少し勇気いります?

 

いよいよ(?)、設問 2 (2) です。

f:id:higher_tomorrow:20200216061425p:plain

「リトルエンディアンってなんだっけ?」 という人は、すぐにとばしましょう。この 1 問で合否が決まるわけではありません。

 

「リトルエンディアン」 の説明の前に、まずは、「レジスタ」 について復習します。

レジスタとは、CPU の記憶回路のことです。CPU 内にあるメモリのイメージです。

左側の表を見てください。これは、Intel が作った CPU である、x86(今や、32 bit アーキテクチャを指すことの方が多い?)から、ピックアップしてきたものです。レジスタは、色々な用途に使われています。ちなみに、x86 のレジスタは、全部で 16 あるそうです。

で、「リトルエンディアン」 ですが、これは、バイトの順序を表すタームです。

右の絵を見てください。今、レジスタ上に、C8, 04, 80, 26 というデータが格納されているとします。これを、メモリ上に持ってきたときにはどうなるかというと、逆さまに格納されます。つまり、26, 80, 04, C8 となります。

このように、バイトの順序が入れ替わる方式が、リトルエンディアンです。逆に、バイトの順序が入れ替わらない方式を、ビッグエンディアンと呼びます。

 

どちらがよいというわけではありません。ちなみに、x86 は、リトルエンディアン方式です。

 

ここから、しばらく、基本知識の整理をさせてください。関数を呼び出したときの、メモリ、レジスタの変化について、確認します。ガチで書いたので、結構、長いです。なんとなく知っている方は、「# インプット ここまで ---」まで、すっ飛ばしてください

# インプット ここから ---

① 各種レジスタの名前、② リターンアドレス(ret)、③ ebp レジスタ保存値(sfp)などの用語になじみがないと、説明が難しく感じるかもしれません。が、気のせいです。単に慣れていないだけです。過去問を解く中で、慣れていってください。

こんな順で説明します。

  1. スタック領域 ~「スタック」のおさらい
  2. レジスタとメモリ ~ プログラム実行時のレジスタとメモリの様子
  3. スタックフレーム ~ スタックに PUSH / POP するデータのレイアウト
  4. 具体例 ~ プログラム実行時のレジスタとメモリの様子
    main 関数実行時 --> foo 関数呼び出し時 --> foo 関数終了時

 

まずは、「スタック領域」から。

f:id:higher_tomorrow:20200216061430p:plain

スタックというデータ構造は、みなさんご存じでしょう。「本」 が積まれているイメージです。新たに本を積むことを 「PUSH」 と呼び、本をとることを 「POP」 と呼びました。最初に積んだ本は、最後までとることができません(FILO)。最後に積んだ本が、最初にとれます(LIFO)。こんな特徴がありました。

 

「てか、このスタックの絵、逆さまぢゃね?」

 

はい。いつも見ているスタックのイメージと逆さまになっているので、少しわかりにくいです。問題中の、図 2 にあわせました。

続けます。「スタック領域」 は、「スタックフレーム」 という 「本」 を PUSH したり POP したりする領域になります。

ここで大事なことは、スタック領域は、高位のアドレスから、低位のアドレスに成長するということです。

逆さまになっていない図を使っている記事や書籍もあります(むしろ、そっちの方が多いと思います)。どうして逆さまになっていないかというと、低位のアドレスを上に、高位のアドレスを下に書いているからです。それだけです。

 

このスタック領域が、いつ使われるかというと、関数の呼び出し時です。関数を呼び出すときには、その関数が使う 「スタックフレーム」 なる 「本」 を作成し、スタックに PUSH します。関数を終えるとき、関数を呼び出した前の状態を復元して、「スタックフレーム」 なる 「本」 を、スタックから POP します。

 

次に、レジスタとメモリを使って、どのようにプログラムが実行されるのか、おさえましょう。

f:id:higher_tomorrow:20200216061434p:plain

今回、用途をおさえておいてほしいレジスタは、「スタックポインタ(esp)」、「ベースポインタ(ebp)」、それから、「インストラクションポインタ(eip)」 の 3 つです。

 

左の絵を見てください。esp と ebp は、スタック領域を指し示します。

  • esp には、スタックのトップのアドレスが格納されています。この値により、メモリを確保したり、開放したりしています
  • ebp には、スタックフレームの 「ベース(基準)」 となる、アドレスが格納されています

 

右の絵を見てください。eip は、これらとは少し毛色が異なります。ここには、実行する命令のアドレスが格納されています。

 

eip が指す命令をとってきて(フェッチ)、解釈して(デコード)、実行する。すると、eip がカウントアップし、そこから、フェッチ、デコード、実行します。このようにして、プログラムが実行されていきます。

 

次に、スタック領域に積まれる 「本」 である 「スタックフレーム」 が、どのようなデータなのか、説明します。

f:id:higher_tomorrow:20200216061438p:plain

スタックフレームのレイアウトは、問題文の図 2 に書いてあります。ちょっと見にくいので、簡潔に書きました。例えば、右側の絵のようなレイアウトになっています。

 

このスライドの、ちっちゃく描かれた 「スタック領域」 には、main 関数のスタックフレームがあり、その上に foo 関数のスタックフレームが積みあがっています。

 

 

スタックフレーム中の「リターンアドレス(ret)」と「ebp レジスタ保存値(sfp)」は、foo 関数が終了する際、foo 関数を 「呼び出す前の状態」 に復元するために使います。

 

それでは、関数が実行されるときのレジスタとメモリの様子を、具体的に見ていきましょう。丁寧に追っていきます。

f:id:higher_tomorrow:20200216061442p:plain

この絵は、main 関数が実行されているときの、レジスタとメモリの様子です。

左側が、メモリのスタック領域、右側が、メモリのテキスト領域(プログラム Vuln の命令がある領域です)です。

まずは、簡単に、状況を把握しましょう。

  • 左側にある、スタック領域を見てください。赤字の箇所がアドレスです。
    main 関数のスタックフレームは、B 番地にあります。もちろん、ebp に格納されているアドレスは、B 番地です
  • 右側にある、テキスト領域を見てください。こちらも、赤字の箇所がアドレスです

eip は、X 番地を指しています。

 

この状態で、foo 関数が呼ばれると、どうなるかというと、 こうなります。

f:id:higher_tomorrow:20200216061447p:plain

スタック領域に、foo 関数のスタックフレームが積まれました。つまり、esp が、新しいスタックの先頭を指しました。

 

ebp は、新しいスタックフレーム、C 番地を指し示しています。このとき、main 関数のスタックフレーム B 番地を見失わないように、sfp に退避しておきます。

 

eip は、カウントアップではなく、foo 関数の命令があるアドレスまでジャンプします。

このとき、呼び出し元である main 関数に戻ってこられないとまずいので、eip の値 X 番地(の次の番地)を、foo 関数のスタックフレームの ret に退避します。

 

そして、foo 関数の処理が終了しました。foo 関数のすべての命令が実行されました。

f:id:higher_tomorrow:20200216061451p:plain

となると、foo 関数を呼び出す前に、戻らなければなりません。ebp が main 関数のスタックフレームを指すように、eip が main 関数の続きの命令を指すように、復元します。

 

これは、「foo 関数のスタックフレーム」に退避していましたよね。退避したリターンアドレス(X の次の番地)を eip に、sfp(B 番地)を ebp に戻します。

そして、foo 関数のスタックフレームを POP します。イコール、esp からスタックフレーム分のバイトを引いて、メモリ領域を開放します。

 

これで、foo 関数を呼び出す前の状態に戻り、X の次の番地から、フェッチ、デコード、実行です。

 

これで、インプットはお終いです。お疲れさまでした。

設問に戻りましょう。

# インプット ここまで ---

 

設問 2 の (2) です。

f:id:higher_tomorrow:20200216061456p:plain

右の図は、図 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 ページの真ん中よりちょっと上、「アドレス空間配置ランダム化技術」 についてです。

f:id:higher_tomorrow:20200216061501p:plain

いわゆる ASLR(アスラー)です。この名前は知っておきましょう。

設問 2 (2) がわかれば、セットでとれます。

この問題の事例では、攻撃者は、shell コードが、どのアドレスに展開されるかわかっていました。だからこそ、リターンアドレスを shell コードの先頭に指定できたのです。

 

『具体的に述べよ』 とあったので、私は、そのまま 「リターンアドレスを shell コードの先頭に指定する(行為をできないようにする)」 と解答しました。

これだと、「shell コードの先頭」 って何? となるかもしれません。正直、25 字でまとめるのは厳しかったです。

 

IPA の解答は、『攻撃を成功させるためのジャンプ先アドレスの特定』 です。特にコメントはありません。

 

設問 3 (1) です。3 ページの、下線部 ① です。

f:id:higher_tomorrow:20200216061505p:plain

IPS とは、侵入防御システムのことです。4 層における不正なデータ(主に、OS への攻撃)を検知、破壊します。

WAF とは、Web アプリケーションファイアウォールの略です。7 層における不正なデータ(主に、アプリケーションへの攻撃)を検知、破壊します。

 

いずれも、あやしいと判断したデータについては、先に進めないようにします。

 

設問を見ると、また 『具体的に述べよ』 です。たった 25 字で、具体的に?

私は、「既知の攻撃を含むパケットを遮断する(処理)」 と解答しました。これは、ダメです。「アノマリ検知」 があることを忘れていました。あと、ぜんぜん具体的ではありません。

IPA の解答は、『インジェクションベクタを検知・破壊する』 となっています。

『インジェクションベクタ』、まんま使ってきました。本文中の言葉を使うと、2 つのメリットがあります。

  • いちいち、その定義は何なのか、それが何を指すのか、説明しなくてよいため、コンパクトに収めることができる
  • いっきに具体的になる

 

「そこまでわかっているなら、オマエ使えよ」、です。はい。ごめんなさい。

 

どんどんいきます。設問 3 (2) です。

f:id:higher_tomorrow:20200216061510p:plain

私は、『あらゆる命令の実行が shell コードで可能となる』 = 「誰でも、どこからでも実行できる」 と、とらえました。

このうち、「どこからでも実行できる」 は、「shell コードの展開箇所によらない」 という意味です。これは、p.5 の冒頭にあります。なので、スルーしました。

というわけで、自分は、「権限によらず、あらゆる命令が実行できる(条件)」 としました。まずくはないと思います。

 

しかし、問題文中に、『ルート特権化』 という文言が、何度も繰り返し出てきています。そう、これを使えば、コンパクトにできるのです。そこででしょう。IPA の解答例は、『ルート特権があること』 となっています。

 

設問 4 の (1) です。 

f:id:higher_tomorrow:20200216061514p:plain

正直、何を答えてよいのか、わかりませんでした。仕方がないので、一般的なファイルシステムのアクセス制御について言及しました。こんな感じです。

「読出すファイルに、利用者やアプリからの参照権限がない場合、処理を中断する仕様」

めちゃめちゃ苦しいですね。でも、何も書かないと、100 %、0 点になりますから。。何か書きましょう。

 

スマホのアプリは、サンドボックス内で実行されています。サンドボックスとは、「砂場」 のことです。ある砂場から、他の砂場のリソースやデータには、アクセスできません。アクセスするには、明示的に許可が必要です。

これについて、答えてほしかったのでしょう。

 

設問 4 の (2) です。

f:id:higher_tomorrow:20200216061519p:plain

この問題は、絵にある 2 箇所に着目できれば、それでおしまいです。多くの受験生がとってくると思います。

私は、本文中の言葉をできる限り使って、「データを盗み出すタイプのマルウェアに侵入された」(状況)としました。

 

ラスト、設問 4 の (3) です。

f:id:higher_tomorrow:20200216061523p:plain

ポイントは、p.2 の最初の段落にあります。これは、少し見つけにくいです。国語力が試されます。

とはいえ、1 箇所見つければよいだけなので、多くの受験生がたどり着くと思います。書き負けないでください。

少なくとも、スマホの管理に M システムを使っていることは、たどり着いてください。

 

 

それでは、これまで見てきたこと、本問で得た知識を、簡単に復習しましょう。

f:id:higher_tomorrow:20200216061530p:plain

f:id:higher_tomorrow:20200216061534p:plain

な感じですかね。

 

総括です。

f:id:higher_tomorrow:20200216061539p:plain

よく出題される、重要な技術、受験生の正解しやすさなどを鑑み、独断と偏見で、問題ごとに、ランクをつけてみました("A" ~ "C")

  • "A" は、絶対にとりたいです
  • "B" が半分くらい取れていれば、それで十分合格ラインを超えるという感覚です。全部とれれば、上位合格だと思います
  • "C" は、時間かけてもできませんでした。設問 4 (1) なんて、ムリぢゃね?

 

めちゃめちゃ長文になってしまいました。最後まで読んでいただき、ありがとうございました。

安全確保支援士対策 BOF 編 [1]

このエントリでは、安全確保支援士試験の対策として、情報処理技術者試験の過去問を解説します。

過去問を解きながら、知識のインプットができるようにしたつもりです。ぜひ、問題に取り組んでいただき、その後、本エントリを見ていただければと思います。

 

さて、今回は、BOF(バッファオーバフロー)編 第一弾。おそらく、BOF の過去問の中では最も易しいであろう、「2007 年度(平成 19 年度)春期 テクニカルエンジニア 情報セキュリティ試験 午後 1 問 1」を解いていきます。

 

《問題》

    情報処理技術者試験のページからダウンロードしておいてください

《凡例》

  • 『・・・』は、問題文からの引用を表します
  • (解答)は、IPA が発表した解答例を表します

 

それでは、午後 1 の 問 1 を、解き進めましょう。

まずは、設問をながめます。

f:id:higher_tomorrow:20200205164602p:plain

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

 

f:id:higher_tomorrow:20200205164606p:plain

設問 1、まずは、a からいきます。3 ページの下、T 君のセリフの箇所です。

『バッファオーバフローの結果 [  a  ] 領域に確保された変数の値が、意図に反して書き換えられる可能性』 とあります。

メモリには、いくつかの領域がありますが、バッファオーバフローの文脈では、まず、「スタック」 または 「ヒープ」 を思い浮かべてください。すぐあとに見ますが、ここは、「スタック」 が正解です。

ほぼ全ての受験生が正解したはずです。絶対に落とせません。

 

f:id:higher_tomorrow:20200205164611p:plain

次に、b と c です。4 ページの一番上、T 君のセリフです。ここでは、どの変数がバッファオーバフローを起こして、どの値が書きかえられるかが問われています。

 

『図1 脆弱性のあるプログラム例』 を見てください。

プログラムが何をやっているのか、全行にコメントがあります。C/C++ 言語をあまり知らなくても、BOF の原理がわかっていれば解けます。

このプログラムは、13 行目で、「外部から指定された、第一引数 argv[1]」 を処理しています。strcpy 関数を見たら、ぴくっと反応しなければなりません。こいつは、バッファの上限が指定できない関数です。使うべきではありません。

 

この strcpy 関数を用いて、プログラム外部からの入力 argv[1] を、"ノーチェック" で、128 バイトの領域(val2)にコピーしています。入力が 128 バイトを超えると、バッファがあふれます。

 

c を解くには、少し前提知識が必要となります。簡単に、確認させてください。

f:id:higher_tomorrow:20200205164615p:plain

ここでのゴールは、プログラムを実行した際の、メモリ空間がどのようになっているのか、把握することです。

この図の左の絵は、メモリ空間の全体像です。上のアドレスが 「低」 く、下のアドレスが 「高」 いことに注意してください。

その中に、「スタック領域」 と呼ばれる領域があります。

スタックというデータ構造は、ご存じだと思います。本を積み上げるイメージです。積み上がっている本の一番上に、本を置くことを、PUSH と呼び、一番上の本をとることを、POP と呼びました。このデータ構造の特徴は、「最初に積んだ本は、最後にならないととれません(FILO)」、同じことですが、「最後に積んだ本が、最初にとれます(LIFO)」 というものでした。

後でも説明しますが、関数が呼ばれるたびに、この 「本」 が積みあがっていきます。

大事なことは、スタック領域は、アドレスで言えば、高い方から低い方へと成長するということです。真ん中の絵は、上のアドレスを 「低」 く、下のアドレスを 「高」 く描いたので、イメージ通り、下から上に成長するようになっています。

逆に、「ヒープ領域」 は、上から下へ成長します。ヒープ領域とは、プログラムの実行中に、データを展開する領域です。

スタック領域に積みあがっている 1 冊 1 冊の 「本」 は、「スタックフレーム」 と呼ばれます。それが、真ん中の絵です。そのスタックフレーム(1 冊の本)のレイアウトが、右の絵になります。

「ローカル変数」 と 「引数」 は、ここに入ってきます。

 

このメモリのレイアウトが書けないと、本問を解くのは厳しいです。おそらく、この問題を選択した人の、大半が描けたと思います。

 

f:id:higher_tomorrow:20200205164619p:plain

設問 1 の c に戻ります。

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

データは、低いアドレスから高いアドレスに格納されていきます。ですので、val2 に 128 バイトより大きなデータがやってくると、val1 の領域にあふれます。

 

f:id:higher_tomorrow:20200205164623p:plain

図 1 のプログラム、13 行目にある strcpy 関数について補足します。繰り返しになりますが、こいつは、書き込みバイト数の上限を指定できない関数です。

strcpy 関数のように、文字列を扱う関数には、書き込みバイト数の上限を指定できる、代替関数があります。概ね、関数名の中に n がついた名称となっています。

この表の 3 つの関数、strcpy、strcat、sprintf 関数は、特に有名です。頭にいれておいて、損はありません。

 

f:id:higher_tomorrow:20200205164628p:plain

d いきます。4 ページ、図 2 のすぐ下、S 主任の発言です。

抽象度が高い設問なので、素直に 「権限昇格」 と答えましょう。おそらく、大半の人が正解してきます。とりこぼしは厳しいです。

e と f は、いったん、とばします。先に、下線部 ① があるので、そっちをやります。

 

f:id:higher_tomorrow:20200205164638p:plain

4 ページの真ん中、下線部 ① です。ふたたび、図 1 のプログラムを見てください。

19 行目のコメントに、『名前が val1 のファイルを入力ファイルとして開く』 とあります。そこで、val1 の値が 'afile' になるようにデータをいじればよいとわかります。

この絵の、ローカル変数の部分を拡大してみます。

 

f:id:higher_tomorrow:20200205232741p:plain
ローカル変数 val1, val2, val3 の箇所を拡大すると、これらは、メモリ内では、左の絵のように展開されています。上から val3, val2, val1 となっています。val1 には、'somefile' と格納されています。

最後の \n は、文字列の終端を表す値です(メモリ上には 0x00 と展開されます)。「文字列はココまでですよ」 と教えてくれる値です。NULL(ヌル, ナル)文字や、EOS(End of String)などと呼ばれています。

ですので、コマンドラインに、128 byte 分データのあとに、'afile' という文字列を入れてあげると、val2 がオーバフローし、右の絵のような状態になります。

val2 を 「c」 で埋めましたが、何でもよいです。

なお、コマンドラインの引数(文字列)は、メモリ内に展開した際に、自動的に NULL 文字が追加されます(でないと、どこまでが引数で指定した文字列なのか、わかりませんから)。

 

f:id:higher_tomorrow:20200205164647p:plain

ということで、[  ア  ] は、128 byte でした。面倒なバイト計算は、一切ありません。わかる人は、瞬殺です。

できれば正解したいところです。とれなくても、これが致命傷にはならないと思います。

 

f:id:higher_tomorrow:20200205164652p:plain

さて、設問 1 の [  e  ] に戻ります。

ここも、少しだけ、前提知識が必要なので、確認させてください。

 

f:id:higher_tomorrow:20200205164655p:plain

ここからのインプットのゴールは、関数呼び出し時のスタックの様子についてイメージをわかせることです。

右にある、main 関数から next 関数を呼び出すプログラムについて、検討していきます

(next 関数の処理は、何でもよいのですが、ここでは、引数に 1 を足して返します)。

大きな流れは、こんな感じです。

  • next 関数を呼び出す
    → スタックフレームを生成し、スタック領域へ PUSH します。後で戻ってこられるように、今、自分がいる位置を、スタックフレームに入れておきます
  • next 関数を終了する
    → next 関数が呼び出される前の状態に戻して、スタックフレームを POP します

なんとなくつかめたら、細部を見ていきましょう。

 

f:id:higher_tomorrow:20200205203537p:plain

左の絵も、右の絵も、メモリ空間の一部を表しています。左は、「命令コード領域」 で、まさに、ソースコードに書いた処理を実現するための命令が入っています。CPU は、ここから命令をとってきて、解釈して、実行します。とってくることを 「フェッチ」、解釈することを 「デコード」 と呼んだことを思い出してください。

まず、左の絵 「命令コード領域」 を見てください。

CPU がどの命令をとってきて実行するかというと、「EIP レジスタ」 に格納されているアドレスからです。

レジスタとは、CPU の記憶回路(CPU 内で、データを保持するところ)です。例えば、Intel の x86 という CPU には、16 個のレジスタがあります。その中に、EIP(インストラクションポインタ)と呼ばれるレジスタがあります。ここに、実行する命令を指し示すアドレスが入っています。

ごちゃごちゃ言いましたが、つまりは、「EIP が指すところから命令をフェッチ、デコード、実行する」 というわけです。

 

右の絵は、おなじみ、スタックフレームです。今は、main 関数のフレームがスタックされています。

 

左の絵では、EIP は main 関数の命令の先頭を指しています。ここから、順に命令を実行していきます。

 

f:id:higher_tomorrow:20200205203648p:plain

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

 

f:id:higher_tomorrow:20200205203751p:plain

main の命令を、次々に実行していきます。

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

 

f:id:higher_tomorrow:20200205203812p:plain

このとき、next 関数のスタックフレームをつくり、スタック領域に PUSH します。スタックフレームに、引数やローカル変数の情報が入るのは、これまで見てきた通りです。

ここでもう一つ、スタックフレームに、戻りアドレス(リターンアドレスとも呼びます)RET を入れています。

これは、next 関数の処理が終了した際に、元の処理、つまり、呼び出し元である main 関数の続きの処理ができるようにするためです。

そして、EIP の値に、next 関数の命令があるアドレスを格納し、ジャンプします。

f:id:higher_tomorrow:20200205203831p:plain

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

 

f:id:higher_tomorrow:20200205203846p:plain

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

f:id:higher_tomorrow:20200205203903p:plain

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

 

f:id:higher_tomorrow:20200205203917p:plain

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

この挙動を、おさえておきましょう。

 

f:id:higher_tomorrow:20200205164736p:plain

まとめます。もう一度、冒頭で説明したことを繰り返します。この ① ~ ④ の動きがわかっていれば、目標達成です。

 

● next 関数を呼び出す

    ① スタックフレームを生成し、スタック領域へ PUSH します。
    その際、後で戻ってこられるように、① 今自分がいる位置を、
    スタックフレームに入れておきます。

    ② next 関数の命令にジャンプします。

● next 関数を終了する

    ③ next 関数が呼び出される前の状態に戻して、
    ④ スタックフレームを POP します。

 

f:id:higher_tomorrow:20200205164740p:plain

ようやく [  e  ] です。解答の骨格は、「関数」 となります。

しかし、他の選択肢と異なり、これだけ 「6 字以内」 と、字数が少しだけ多くなっています。単に 「関数」 という答えでは、満点はもらえないと思います。

 

この問題文中に、こんなセリフがあります。『戻りアドレスが書き換えられてしまう』 と。この、最も典型的な例に、触れておきます。

攻撃者は、「偽の戻りアドレス」 と 「悪意のコード」 の両方が含まれるデータを使って、バッファをあふれさせます。もちろん、戻りアドレスの領域も、攻撃者の用意したデータで上書きされます。そのとき、戻りアドレスの領域を悪意のコードの先頭になるように調整します。そうすると、スタックフレームが POP したときに、自分の用意したコードを実行することができるのです(このようなコードを、「shell コード」 と呼びます)。

となると、BOF の脆弱性を悪用されると、任意のコードが実行される可能性があります。

 

f:id:higher_tomorrow:20200205164746p:plain

 続いて、5 ページの上、[  f  ] です。

『malloc 関数などによって、[  f  ] 領域に確保された変数』 とあります。そのすぐ下には、『[  a  ] 領域と [  f  ] 領域に確保された変数については』 ともあります。

malloc 関数は、指定されたバイト分、「ヒープ領域」 のメモリを確保する関数です。使用後には、free 関数を呼び出して、確保していたメモリを開放する必要があります

答えは、「ヒープ」 です。絶対におとせません。

 

f:id:higher_tomorrow:20200205164750p:plain

設問 2 の (2) です。'afile' の内容が表示されてしまうことによる、セキュリティ上の問題が問われています。

管理者のみが read/write できるところ、一般利用者でも read/write できるということは、すぐにわかります。

私は、それ以上は書けませんでした。。

採点講評には、次のようにあります。

『・・・ afile の内容の表示についてだけ記述した解答が多かった。・・・ 任意のファイルの内容を表示できることに気づいてほしかった』

これ、大部分の人は、わかってたと思いますけど、、まぁよいです。

『afile の内容の表示についてだけ記述した解答が多かった』 とあるので、合否に影響する問題ではないと、信じたいです。

 

f:id:higher_tomorrow:20200205164755p:plain

問題文中に、BOF の対策が書いてあるので、少しだけ補足します。

5 ページ [  f  ] の近く T 君のせりふに、『どちらもプログラム作成上の対策は同じと考えてよい』 とあります。

これは、「スタックオーバフローも、ヒープオーバフローも、想定したメモリ領域があふれることに起因しているから、メモリ領域を超えないように、チェックすればよい」 と、考えたからでしょう。

その後の S 主任のせりふに、『バッファオーバフローを防ぐ根本的な対策は、ループ文の中で配列への書き込みを行う場合や、組み込み関数を使う場合などで、方法が異なる』 とあります。なので、コーディングルールとしては、状況に応じて、対策を示す必要があります。

例えば、バッファへの書き込みを、ループで処理するときには、バッファの境界チェックを、ループの終了条件に含めることが対策になります。一方、組み込み関数を使うときには、危険な関数を使わず、安全な関数を使うことが対策になります。何が危険で、どうすれば安全に実装できるのか、示す必要があります。

 

f:id:higher_tomorrow:20200205164800p:plain

設問 2 の (3) です。

文章で解答する場合は、50 字以内です。かなり簡潔に書かなければなりません。

strcpy が、「無制限に」 文字列をメモリに書き込むからあふれます。なので、入力を、128 バイト未満に制限してあげないといけません。128 バイトぴったりだと、NULL 文字があふれてしまうので、「以下」 ではなく 「未満」 としなければなりません

解答には、「かつ」 と 「128 バイト未満」 が必須となるでしょう。

私は、次のようにしました。

「条件文を、コマンドライン引数が 1 より大きく、かつ、この引数の長さが 128 バイト未満であるとする」 です。

IPA の解答のように、『論理積として加える』 などという表現は、私には、なかなかでてきません。

 

f:id:higher_tomorrow:20200205164804p:plain

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

私は、文章で書きました。strlen 関数に自信がなかったからです。

 

f:id:higher_tomorrow:20200205164810p:plain

設問 3 です。下線部 ② にいきましょう。プログラミング以外で、BOF を緩和する方法についてです。

完全に知識問題です。もう、知らなかったら書けません。

結論、ローカル変数と SFP(スタックフレームポインタ)の間に、推測されない値(一定の桁数の疑似乱数)を挿入します。普通にプログラムを実行している場合には、この値は変わらないはずです。これが変わったことを検知し、プログラムを停止する仕組みがあります。

このような、推測されない値を、「カナリア」 や 「クッキー」 と呼びます。

 

f:id:higher_tomorrow:20200205164814p:plain

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

 

f:id:higher_tomorrow:20200205164820p:plain

コンパイラや実行環境で、BOF を緩和する方法については、5 ページ中央の T 君のセリフにあります。

    ・ DEP(Data Execution Prevention)

    ・ Libsafe など

もう 1 つ付け加えるのであれば、

    ・ ASLR(Address Space Layout Randomization)

です。ここに書いた程度のことを、おさえておきましょう。

 

それでは、これまでやってきたことを簡単に復習しましょう。

 

f:id:higher_tomorrow:20200205164827p:plain

まず、メモリ空間です。

  • メモリ空間には、「スタック領域」 と 「ヒープ領域」 がありました
  • 「スタック領域」 は、我々のイメージとは逆に、高いアドレスから低いアドレスに向かって成長しました

次に、関数呼び出しです。

  • スタック領域には、関数が呼び出されるたびに、スタックフレームが PUSH されました
  • スタックフレームには、引数、ローカル変数、リターンアドレス、スタックフレームポインタがありました
  • 関数が終了すると、リターンアドレスを使って、元のアドレスに戻り、スタックフレームは POP されました

最後に BOF です。

  • 想定を超えるサイズのデータにより、メモリ上のバッファがあふれると、例えば本問であれば、任意のファイルが開かれる可能性がありました。RET を書き換えることで、任意のプログラムを実行される可能性もありました
  • プログラミングでの対策は、プログラム外の値が、想定している領域からオーバフローしないように実装することでした。例えば、(1) サイズをチェックしてから、確保した領域にデータを格納する(2) strcpy 関数を strncpy 関数に変更し、サイズの上限を指定する
  • コンパイラや実行環境により BOF を緩和させる技術として、カナリア値をはさむこと、DEP、Libsafe、ASLR を紹介しました

 

f:id:higher_tomorrow:20200205164833p:plain

独断と偏見で、なんとなくランク付けしてみました。

  • [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 を入れて、つじつまを合わせておく)。

こんなもん。