この大会は2017/11/25 8:00(JST)~2017/11/27 8:00(JST)に開催されました。
今回もチームで参戦。結果は3226点で948チーム中11位でした。
自分で解けた問題をWriteupとして書いておきます。
I'm Playing (Misc 1)
Discordにログインしたら、ダイレクトメッセージにフラグがあった。
@XXXXXXXX, Welcome to TUCTF! Please read the rules before posting! If you have a question about a challenge, please use @Challenge: ChallengeName to automatically tag the challenge creator! And finally, here's your "I'm playing" flag: TUCTF{I’m_Mr_m33seek5_G1V3_M3_th3_fl4g!} Thank you for playing TUCTF!
TUCTF{I’m_Mr_m33seek5_G1V3_M3_th3_fl4g!}
High Source (Web 25)
ソースを見ると、scripts/login.jsを参照していることがわかる。scripts/login.jsを見ると、次のコードが書いてある部分がある。
var password = "I4m4M4st3rC0d3rH4x0rsB3w43";
このパスワードを認証パスワードとして入れる。
Welcome! Here's the flag: TUCTF{H1gh_S0urc3_3qu4ls_L0ng_F4ll}
TUCTF{H1gh_S0urc3_3qu4ls_L0ng_F4ll}
The Never Ending Crypto (Crypto 50)
$ nc neverending.tuctf.com 12345 ------------------------------------------ Welcome to The Neverending Crypto! How fast can you solve it? Round 1. Give me some text:abcdef abcdef encrypted is 234567 What is H6=4@>6\P924<6C decrypted?
シーザー暗号なので、シフト数を計算して復号するプログラムにする。
#!/usr/bin/env python import socket import re def ceaser(s, rot): p = '' for i in range(len(s)): code = ord(s[i]) - rot if code < 32: code = code + 95 p += chr(code) return p s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('neverending.tuctf.com', 12345)) for i in range(50): data = s.recv(256) print data + 'abcdefgh' s.sendall('abcdefgh\n') data = s.recv(256) pattern = 'encrypted is (.+)' m = re.search(pattern, data) test_enc = m.group(1) rot = ord(test_enc[0]) - ord('a') if rot < 0: rot = rot + 95 pattern = 'What is (.+) decrypted?' m = re.search(pattern, data) enc = m.group(1) dec = ceaser(enc, rot) print data + dec s.sendall(dec + '\n') data = s.recv(256) print data
50回正解したら、フラグが表示された。
TUCTF{wh0_w@s_her3_la5t_ye@r?!?}
Crypto Clock (Crypto 300)
添付ファイルはpcapngファイル。パケットNo.6とNo.7のData部分をデコードすると、サーバの処理コードが得られる。
{ "n": 14558832750877392629213532071, "e": 3 } #!/usr/bin/env python import sys import random import json import arrow with open('flag') as f: flag = f.read() with open('keys') as f: keys = json.load(f) #now to get some randomness in here! with open('/dev/urandom', 'rb') as f: rand = f.read(8) rand_int = int(rand.encode('hex'),16) #now lets use something easier. random.seed(rand_int) offset = random.randint(-1511521829,1511521829) while True: sys.stdout.write( '''Welcome to the ntp server What would you like to do? 1) get current time 2) enter admin area 3) exit :''') sys.stdout.flush() response = raw_input('') if response == '1': time = arrow.utcnow().timestamp - offset # to increase size for security! enc_time = pow(time,keys['e'],keys['n']) sys.stdout.write('HAHAHAHAHAHA, this NTP server has been taken over by hackers!!!\n') sys.stdout.write('here is the time encrypted with sweet RSA!\n') sys.stdout.write(str(enc_time)) sys.stdout.write('\n') sys.stdout.flush() elif response == '2': # lets get even more random! time = arrow.utcnow().timestamp - offset random.seed(time) guessing_int = random.randint(0,999999999999) sys.stdout.write('''ACCESS IS ONLY FOR TRUE HACKERS! to prove you are a true hacker, predict the future:''') sys.stdout.flush() response = raw_input('') if response == str(guessing_int): sys.stdout.write('''Wow, guess you are a hacker.\n''') sys.stdout.write(flag) sys.stdout.write('\n') break else: sys.stdout.write('''I knew you weren't a hacker''') sys.stdout.write('\n') break else: print 'Good by.' break
時間をおいて、2回暗号化すると、(n, e, mの暗号), (n, e, m+bの暗号) (bは小さい)の2組が得られる。Franklin-Reiter Related Message Attackで1回目の平文を復号できる。その結果から、offsetを取得できるので、それをseedにした乱数の1回目を答えればよい。
# crypto_clock.sage import socket import time, datetime import random def related_message_attack(c1, c2, diff, e, n): PRx.<x> = PolynomialRing(Zmod(n)) g1 = x^e - c1 g2 = (x+diff)^e - c2 def gcd(g1, g2): while g2: g1, g2 = g2, g1 % g2 return g1.monic() return -gcd(g1, g2)[0] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('cryptoclock.tuctf.com', 1230)) data = s.recv(256) print data + '1' s.sendall('1\n') data = s.recv(256) c1 = int(data.split('\n')[2]) now1 = datetime.datetime.now() cur1 = int(time.mktime(now1.timetuple())) time.sleep(3) print data + '1' s.sendall('1\n') data = s.recv(256) c2 = int(data.split('\n')[2]) now2 = datetime.datetime.now() cur2 = int(time.mktime(now2.timetuple())) n = 14558832750877392629213532071 e = 3 diff = cur2 - cur1 m = related_message_attack(c1, c2, diff, e, n) offset = cur1 - m print data + '2' s.sendall('2\n') data = s.recv(256) print data now3 = datetime.datetime.now() time = int(time.mktime(now2.timetuple())) - offset random.seed(time) guessing_int = random.randint(0, 999999999999) print guessing_int s.sendall(str(guessing_int) + '\n') data = s.recv(256) print data
TUCTF{g00d_th1ng_th3_futur3_i5_r3lated!}