オンサイトを夢見てチームKogCoderとして参加しました
が、welcome問除いて2問しか解けなかったです
順位は163位でした
Reversing
Meow
- flagをエンコードした画像とエンコードに使ったソフトが渡される
- ソフトはNeko Bytecodeなので、実行にはNekoVMが必要
また、その関係上普通の逆アセンブラが使えない - Nekoの逆アセンブラを見つけられなかったのでコードの解析は放棄して、白1色や黒1色などの他の画像を読ませてどう変換されるかを調べた
- その結果、以下のことが推測できた
- R, G, B をそれぞれ共通の変換テーブルで変換している
- 変換テーブルは100pxごとにループしている
- つまり、R, G, Bのいずれか1つを 0x00~0xFFの間で変化させて、色の変化を見ることで変換テーブルを求めることができる
-
Code
-
make_dct_color.py
#!/usr/bin/env python3 from PIL import Image import subprocess import time sbname = './buf_i.png' ebname = './buf_e.png' l = [] for i in range(0xff+1): lb = [] buf = Image.new('RGBA', (768, 768)) for h in range(768): for w in range(768): buf.putpixel((w, h), (i, 0, 0)) buf.save(sbname) p = subprocess.Popen(['neko', './meow.n', sbname, ebname]) p.wait() enc = Image.open(ebname) enc.convert('RGBA') for j in range(100): r,g,b,a = enc.getpixel((j, 0)) lb.append(r) l.append(lb) buf.close() enc.close() print(l)
-
dec_with_color_dct.py
#!/usr/bin/env python3 from PIL import Image import math import sys lst = [## 長いので省略] img = Image.open(sys.argv[1]) img.convert('RGBA') w,h = img.size out = Image.new('RGBA', (w, h)) for i in range((w)*(h)): x = i % w y = math.floor(i / w) cur = i % 100 r,g,b,a = img.getpixel((x,y)) cr = lst[r][cur] cg = lst[g][cur] cb = lst[b][cur] out.putpixel((x,y), (cr, cg, cb, 0xff)) out.save(sys.argv[2])
-
- 求まった辞書を元に変換すると、色はそれっぽいが画素の配置が違う画像が出力された
-
配置変更も特定の表によって変換されると仮定し、それぞれ違う色を持ったflagと同じ大きさ(768*768)の画像を生成し、対応表を求めた
- 768^2 < 256^3 なので出来たこと
- 愚直に全探書くとO(n^4)になって死ぬので先に辞書を作っておく
- 13MBほどの辞書ができる
-
Code
-
make_dct_pos.py
#!/usr/bin/env python3 from PIL import Image import subprocess import math import sys sbname = './buf_i.png' ebname = './buf_e.png' dbname = './buf_d.png' def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) # create src src = Image.new('RGBA', (768, 768)) for h in range(768): for w in range(768): i = h*768 + w r = i % 256 g = math.floor((i % 65536) / 256) b = math.floor(i / 65536) src.putpixel((w, h), (r, g, b)) src.save(sbname) # create enc p = subprocess.Popen(['neko', './meow.n', sbname, ebname]) p.wait() p = subprocess.Popen(['./dec_with_dct.py', ebname, dbname]) p.wait() dec = Image.open(dbname) dec.convert('RGBA') pos = {} hashes = {} # compare ## make hash for y in range(768): for x in range(768): dr, dg, db, a = dec.getpixel((x, y)) hashes[(dr, dg, db)] = (x,y) ## run search for y in range(768): for x in range(768): #eprint((r, g, b)) sr, sg, sb, a = src.getpixel((x, y)) pos[hashes[(sr, sg, sb)]] = (x, y) print(pos)
-
dec.py
#!/usr/bin/env python3 from PIL import Image import math import sys colors = [## 省略] pos = {## 省略} img = Image.open(sys.argv[1]) img.convert('RGBA') w,h = img.size out = Image.new('RGBA', (w, h)) for i in range((w)*(h)): x = i % w y = math.floor(i / w) cur = i % 100 r,g,b,a = img.getpixel((x,y)) cr = colors[r][cur] cg = colors[g][cur] cb = colors[b][cur] out.putpixel((pos[(x, y)]), (cr, cg, cb, 0xff)) out.save(sys.argv[2])
-
- 出来上がった辞書と先の色対応の辞書の2つの辞書をを用いてflag_enc.pngを変換すると、懐かしのNyanCatの画像が出てくる
その中にflag - TWCTF{Ny4nNyanNy4n_M30wMe0wMeow}
- reversingを放棄したがために、13.4MB(内辞書13.4MB)の酷いソルバーを生み出してしまった
- 実質forensic問だった
Crypto
Real Baby RSA
- 暗号化に用いたPythonスクリプトと暗号化されたflagが渡される
- Nが1024bitなので開催期間中に普通に解くのは現実的ではない
- 1字ごとに暗号化しているので0x21~0x7eくらいまでをNとEを用いて暗号化し、対応表を作れば解けた
- Code
- dec.py
#!/usr/bin/env python3 flag = '' dct = {} # Public Parameters N = 36239973541558932215768154398027510542999295460598793991863043974317503405132258743580804101986195705838099875086956063357178601077684772324064096356684008573295186622116931603804539480260180369510754948354952843990891989516977978839158915835381010468654190434058825525303974958222956513586121683284362090515808508044283236502801777575604829177236616682941566165356433922623572630453807517714014758581695760621278985339321003215237271785789328502527807304614754314937458797885837846005142762002103727753034387997014140695908371141458803486809615038309524628617159265412467046813293232560959236865127539835290549091 e = 65537 for i in range(0x21, 0x7f): dct[chr(i)] = pow(i, e, N) t = open('output', 'r').readlines() for i in t: s = int(i) for c, n in dct.items(): if n == s: flag += c break print(flag)
- dec.py
- TWCTF{padding_is_important}
感想
- あらためて自分の実力不足を感じた
- せめてWarmup問くらいは全完できるようになりたい