KOSEN SECCON 2020 Write-Up(hk)
hk君のwriteupを載せています。
その他のwriteupは以下のリンクからどうぞ。
tk , つた , olton
1.デコードせよ(encode/crypto)【50】
FLAG%7B%25encoding%3C!%3E%7D
ヒントの通り、これはエンコードされたURLなので、デコードすればよい。
FLAG{%encoding<!>}
10.rotten3(encode/crypto)【100】
与えられたファイルを読むと、シーザー暗号で暗号化されたHTMLファイルだったので、Cryptii で復号した。
復号されたHTMLファイルをブラウザで開くと、Of courseの左側にFLAGらしき画像があった。
これをダウンロードして、GIMPなどで見てみると、FLAGが読める。
FLAG{rot_ten_plus_3_is_rot13}
11.ECCp-20(encode/crypto)【250】
楕円曲線に関する問題が2問出題される。
スカラー倍
$ nc (IPアドレス) (ポート番号) ##################################### Let's play with ECC! ECC : y^2 = x^3 + x + 3 (mod 0xddccb) P(x, y) = (0xaaaef, 0xbcdea) ##################################### 2P = (?, 0x47231) :
最初に接続すると、楕円曲線の式やP点などの情報が与えられる。
Elliptic Curve Calculator に各パラメータを入力して計算すると、 $$ 2P = (558440, 291377) $$ が得られ、?部分を16進数変換した0x88568が答えとなる。
離散対数問題
$ nc(IPアドレス) (ポート番号) ##################################### Let's play with ECC! ECC : y^2 = x^3 + x + 3 (mod 0xddccb) P(x, y) = (0xaaaef, 0xbcdea) ##################################### 2P = (?, 0x47231) : 0x88568 Right!! Q(x, y) = (0xcddee, 0xcddef) ?P = Q :
$$ Q=nP $$
を満たすnを求める問題となっている。この場合、値が小さいのでnを求める事ができる。
今回はPollard's rho algorithmを用いて解いた。
参考:楕円曲線上の離散対数問題に対するアプローチ(Baby-step giant-stepとPollard's rho algorithm)
from random import randint def pollards_rho(E, P, Q, div): n = E.order() R = [] Rab = [] a = randint(0, n) b = randint(0, n) R.append((a*P) + (b*Q)) Rab.append([a, b]) M = [] Mab = [] for i in range(div): a = randint(0, n) b = randint(0, n) M.append((a*P) + (b*Q)) Mab.append([a, b]) S = R[0] i = 0 while True: m = int(S[0]) % div S = S + M[m] Sa = Rab[i][0] + Mab[m][0] Sb = Rab[i][1] + Mab[m][1] if S in R: Ra, Rb = Rab[R.index(S)] d = (Sa - Ra)*inverse_mod((Rb - Sb), n) % n return d else: R.append(S) Rab.append([Sa, Sb]) i += 1 p = 0xddccb a = 1 b = 3 E = EllipticCurve(GF(p), [a, b]) P = E([0xaaaef, 0xbcdea]) Q = E([0xcddee, 0xcddef]) print(hex(pollards_rho(E, P, Q, 20)))
$ sage solve.sage 0x975b2
$ nc(IPアドレス) (ポート番号) ##################################### Let's play with ECC! ECC : y^2 = x^3 + x + 3 (mod 0xddccb) P(x, y) = (0xaaaef, 0xbcdea) ##################################### 2P = (?, 0x47231) : 0x88568 Right!! Q(x, y) = (0xcddee, 0xcddef) ?P = Q : 0x975b2 Excellent!! FLAG{Su-gaku_is_tanosii}
FLAG{Su-gaku_is_tanosii}
17.熱血計算塾(programming)【50】
15-14や5+31のような計算問題が100問出題される。
渡されたauto_calc_sample_v3.py
を読むと、
# ここに計算する処理を記述する
と書かれた行があり、その辺りを変更して実行するとFLAGが得られる(過去の自分よ、なぜevalを使わなかったんだ…)。
equation = data.decode().split("=") nums = equation[0].split("+") if len(nums) == 1: nums = nums[0].split("-") nums[1] = "-" + nums[1] answer = int(nums[0]) + int(nums[1])
18.15game(programming)【200】
2人で交互に数字を言い合う(プレイヤーは先攻)
最初は1からはじめ、1度に1~k個の数字を言うことができる
(例.2から5なら、2:5と入力)
nを言ったら負け
このようなゲームに5回勝利したらフラグが表示される(5ラウンド目は地獄)。
このゲームは先攻必勝であることが知られており、 $$ n-1,n-1-(k+1),n-1-2(k+1),n-1-3(k+1),\dots $$ を言えばよい。
import ptrlib def must_nums(k, n): i = 0 nums = [] while True: x = n - 1 - i * (k + 1) i += 1 if x < 1: break else: nums.append(x) return nums def send_num(sock): # kとnを受け取る d = sock.recvlineafter("Up to ").decode() k = int(d.split()[0]) n = int(sock.recvlineafter("BadNum is ")) nums = must_nums(k, n) nums.reverse() # 初手 sock.recvuntil("Your turn:") sock.send("1:" + str(nums[0])) # それ以降 for i in range(1, len(nums)): m = sock.recvlineafter("My turn: ").decode() s = int(m.split(":")[1]) sock.recvuntil("Your turn:") sock.send(str(s + 1) + ":" + str(nums[i])) sock = ptrlib.Socket("(IPアドレス)", (ポート番号)) # 5ラウンド for _ in range(5): send_num(sock) # 4は適当 for _ in range(4): print(sock.recvline().decode().strip())
FLAG{このゲームには必勝法がある・・・}
19.値段の比較はお手の物(programming)【200】
ページ内には名前や値段などが書かれた商品列があり、数秒ごとに更新される仕組みになっている。
「"最高"値の商品名を入力してね」「"最安"値の商品名を入力してね」「〇〇番目に高い商品名を入力してね」「〇〇番目に安い商品名を入力してね」の4パターンの指示が出され、それを連続で150問正解するとFLAGが表示される。
ということで、問題を自動で解くプログラムをPythonで書いた(汚いof汚い)。
import time from selenium import webdriver from bs4 import BeautifulSoup # chromeを起動 driver = webdriver.Chrome("c:\\webdriver\\chromedriver.exe") url = "(URL)" # urlを開く driver.get(url) # 待機(待たないと読み込みが間に合わない) time.sleep(10) for _ in range(150): # ソースを取得 html = driver.page_source # BeautifulSoupでhtml解析 soup = BeautifulSoup(html, "html.parser") lead = soup.find_all(class_="lead") message = lead[0].text.split()[0] results = soup.find_all(class_="card") # 名前 d1 = [] # 値段 d2 = [] for r in results: datas = r.text.split() d1.append(datas[0].split(":")[1]) d2.append(int(datas[1].split(":")[1].split("円")[0])) if message == '"最高"値の商品名を入力してね': sort_d2 = sorted(d2, reverse=True) x = sort_d2[0] name = d1[d2.index(x)] elif message == '"最安"値の商品名を入力してね': sort_d2 = sorted(d2) x = sort_d2[0] name = d1[d2.index(x)] else: m = message.split("に") # 番号 find_n = int(m[0].split("番")[0]) if m[1] == "高い商品名を入力してね": sort_d2 = sorted(d2, reverse=True) else: sort_d2 = sorted(d2) x = sort_d2[find_n - 1] name = d1[d2.index(x)] driver.find_element_by_id("name").send_keys(name) driver.find_element_by_class_name("btn").click() time.sleep(1)
FLAG{けんじつなありのさんもわすれないでね}
20.おいしく焼けました(web)【100】
Cookieに適当な値を入れると、hintとflagが出現した(ほとんど覚えていない)。
FLAG{cookie_yakiyaki}