高専セキュコン2020に出た(ごく一部のWriteUp)
はじめに
2020年11月14日に開催された高専セキュリティコンテストに同級生自分を含めて3人でチームを組んで出ました.僕はwebやネットワーク方面の知識が皆無なのと競技プログラミングをやっているという理由でprogrammingとcrytpto担当でした.が,楕円曲線暗号の問題は解くことができませんでした(追記:勉強しました(自己顕示欲)自分なりに楕円曲線暗号についてまとめてみた - 競プロやってる高専生).というか,パズルしかやってない気がするので暗号勉強したい...
writeUp
足し算しよう
1000から10000の整数の和を求める問題です.プログラムを書いて求めます.プログラムを書かなくても,$(1000+10000)\times (10000-1000+1)\div 2$という式で求めることができます.
熱血計算塾
指定されたポートに接続すると,13+58=
のような計算問題が出されます.正しい答えを入力すると次の問題,間違えると追い返されます.頑張って計算をしていきますが,解いても解いても終わらないので自動化します.問題には対話型のプログラムのサンプル添付されているので,そのコードを書き換え,実行してたくさん問題を解くとFLAGが手に入ります.解くのに使ったPythonのコードは次の問題を解く際に上書きしてしまいまったのでありません.
15game
問題を見て,「お!これはわかるぞ!」と調子に乗っていたらめちゃくちゃ時間かかりました.
必勝法を考えます.相手に15を言わせたいので,自分の最後に言う数字を14にする必要があります.そのためには,その前のターンで自分が最後に言う数字を10にすれば良いです.なぜなら相手が11から1~3個の数字をいくつ言ったとしてもその次のターンで自分は必ず14を言うことができるからです(相手11→自分12,13,14 or 相手11,12→自分13,14 or 相手11,12,13→自分14).同様に考察すると,それぞれのターンで最後に言う数字は14,10,6,2にする必要があることがわかり,それにしたがって数字を言うとFirstRoundを勝利することができます
SecondRoundは,言ったら負けになる数字が30になります.さらにFourthRoundでは一度に417個まで数字を言ってよく,1993を言うと負けのルールになります.先ほどの考察を一般化すると,一度に $N$ 個まで数字を言うことが可能で $ M $ を言うと負けのルールの場合,はじめに1から $ ( M - 1 ) を ( N + 1 ) で割った余り$ の数字を言い,その後は $ (N+1)-(相手の言った数字の数) $ の個数だけ数字を言えば良いことになります.これでFourthRoundまでは勝ち進むことができます.
FinalRoundは一度に5555個まで数字を言ってよく999999を言ったら負けのルールになります.少なくとも100ターン程度かかることがわかるので,人力は厳しいです.そこで,対話型のプログラムを作成します.実際に作成した下記のコードはFinalRound中(はじめの1回は人力)に-1を入力することでオートモードに切り替わります(FourthRoundまでは人力でやる必要があります).
めちゃくちゃ汚いコードです.pythonに慣れたい.
import socket import decimal import re import time def netcat(hostname, port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) at=0 s.connect((hostname, port)) nop = re.compile("ok",re.IGNORECASE) while 1: data = s.recv(1024) if data == "": continue if data.decode('utf-8').strip() == "Let's play with 15game :)": s.sendall(bytes("", "utf-8")) elif nop.search(data.decode('utf-8')): print (data.decode('utf-8')) pass else: #data 変数に、サーバから送られてくる問題文が含まれる print (data.decode('utf-8')) try: answer=0 q=data.decode('utf-8') if at==0: answer=input()#-1を入力するとオートモードになる print(answer) if answer=="-1": print("auto") at=1 else : s.sendall(bytes(str(answer) + "","utf-8")) if at==1: a=q.find(":",11) b=q.find("\n") l=int(q[11:a]) r=int(q[a+1:b-1]) nr=r+5556-(r-l+1) answer=str(r+1)+":"+str(nr) print(answer) s.sendall(bytes(str(answer) + "","utf-8")) except: print ("flag?\n") break shutdown(s) def shutdown(s): print ("Connection closed.") s.shutdown(socket.SHUT_WR) s.close() if __name__ == '__main__': netcat("52.175.155.247", 10001)
全部自動化できたらかっこよかった
※もう一つのProgrammingの問題は解けませんでした(チームの人が解きました)
感想
netcatについてのサンプルが添付されていてとても助かりました,なかったらだいぶしんどかったと思います.純粋に6時間楽しかったので来年も参加したいです.