この大会は2018/7/28 10:00(JST)~2018/7/29 4:00(JST)に開催されました。
今回もチームで参戦。結果は11883点で320チーム中2位でした。
自分で解けた問題をWriteupとして書いておきます。
WELCOME !!! (Misc)
Telegram Channelにフラグが書かれていた。
ISITDTU{Y0u_4r3_0nl1n3!!_3nj0y_th3_CTF}
Somewhere (Misc)
ソースを見るとhidden.cssを読み込んでいることが分かる。https://ctf.isitdtu.com/themes/DuyTan/static/css/hidden.cssにアクセスすると、フラグが表示された。
ISITDTU{y4y_y0u_f0und_m3!!!}
Play with ... (Misc)
0xffとXORをとると、PNGファイルになる。
too low と書いてあるので、画像の高さを高くしてみる。
鏡文字になっているので左右反転し、文字に起こす。
KVXHA3DFMFZWC3TUEBXG64RAMRUW22LOOV2GS33OEBSXQY3FNRWGK3TDMUQGC4DBOJ2G2ZLOORZSA2LNOBZ HKZDFNZRWKIDUNBSSA3LFOQQG4ZLXFYQEI4TBO4QHAYLSOQQHI2DFNUQGQZJAMFXCA5DPEBUGKIDSN5XWMIDPN ZWHSLRAJV2XG2LDEBWGKYLWMUQHGYLZEBSG633SOMQGQ2LNFYQFI33SMUQGE4TFMQQGM33SNUQGSZRAONU WO2BAMNQXGZJAMFZSAZDPFYQFG5DBPFUW4ZZANBSSA3TPEBWG633LNFXGOIDJMYQGI3ZAN5YGS3TJN5XC4ICTM VXHI2LNMVXHI4ZAO5QXSIDVNZSGK4TTORXW6ZBAMVXGIIDQMFZHI2LBNRUXI6JAMFXGIIDINFZS4IAKBJKHK4TOMV SCA2LUEB2XAIDTNBXXK3DEEBXG6IDWMFWGYZLZEBRW65LTNFXCA2DFFYQFG4DFMFVWS3THEBXHK3LFOJXXK4ZAM FZWWIDENFSCA2DPOJZGSYTMMUQHAYLDNNQWOZLTEBZWK5BOEBAXG2DBNVSWIIDIMVZHGZLMMYQGQYLTEBSGS 43UMFXHIIDDMFXCA43UOVSGSZLEEBWXE4ZOEBGGKZBAORUGK4TFMZXXEZJANF2HGIDNNFSGI3DFORXW4IDQMVZ HAZLUOVQWYIDGOVWGM2LMNRSWIIDQOJXXM2LTNFXW4IDGOJQW423OMVZXGLRAIZWGCZZANFZSASKTJFKEIVCV PM2G4XZUNZTTG3C7GBTF6MLNGRTTGX3IGNZDGIL5FYQFG3LBNRWCA2DFEBSHEYLXNYQGCZTUMVZCAYLNN5XGOID FOZSXE6JAORUHEZLFEBXG6LRAIFWGYIDIMF3GS3THEBRHK5BAPFXXKIDFMR3WC4TEEBTWK3TJOVZSA5DIN52WO2BA OJSW2YLSNMQG63TFFYQAUCSJNZZWS4DJMRUXI6JAORUGKIDTOVTGM2LDNFSW45BAMRUXGY3SMV2GS33OEBUW 24DSOVSGK3TDMUQHEZLTN5WHK5DJN5XCA43JOIQGQ2LNEBSGKY3JONUXMZLMPEXCAUDSN5RWKZLEEBUG65ZAM FXHSIDFNZTWCZ3FMQQHM2LTNF2G64ROEBCXQ4DMMFUW4ZLEEBYHE33QOJUWK5DZEBXWMZRAN52XIIDQMVZH AZLUOVQWYIDINFZSA6LPOUXCARTFMVWCA43PNRSCA33GMYQGMZLMOQQG4YLZEBZG643FEBWWK5BAPFXXKLRAK 5SSA43PEBSW45DSMVQXI2LFOMQGG5LMORUXMYLUMVSCAYLTORXW42LTNBSWIIDJOMXCAV3BOMQHG2LTORSXE IDGN5ZCAZTFO4QGY33OM5SXEIDNOJZSA43VMRSGK3RAORQWYZLOOQQGEZLDN5WWKLRAIRXW4ZJANVQXSIDCN5 ZGKIDROVUXIIDFOZUWYIDPNRSCA3LINRSS4ICJMYQGY2LLMVWHSIDBNUQG6ZRAMJSWC5LUPEQHIYLTORSXGLRA
BASE32文字のようなので、デコードする。
Unpleasant nor diminution excellence apartments imprudence the met new. Draw part them he an to he roof only. Music leave say doors him. Tore bred form if sigh case as do. Staying he no looking if do opinion. Sentiments way understood end partiality and his. Turned it up should no valley cousin he. Speaking numerous ask did horrible packages set. Ashamed herself has distant can studied mrs. Led therefore its middleton perpetual fulfilled provision frankness. Flag is ISITDTU{4n_4ng3l_0f_1m4g3_h3r3!}. Small he drawn after among every three no. All having but you edward genius though remark one. Insipidity the sufficient discretion imprudence resolution sir him decisively. Proceed how any engaged visitor. Explained propriety off out perpetual his you. Feel sold off felt nay rose met you. We so entreaties cultivated astonished is. Was sister for few longer mrs sudden talent become. Done may bore quit evil old mhle. If likely am of beauty tastes.
文中にフラグがあった。
ISITDTU{4n_4ng3l_0f_1m4g3_h3r3!}
XOR (Crypto)
XOR keyは10バイト。計算して少し複雑な順番でXORをしているが、フラグの最初がISITDTU{で最後が}になることを使って、XOR keyを求め、復号する。
ISITDTU{*el*ome_to_ISITDTUCT*_C*ntest!_Hav3_a_g0*d_*ay._Hope_y0u_w1l*_3*j0y_and_hav3_a_h*gh*rank_1n_0ur_F1rs*_C*f_C0nt3st._Thank*}
1文字だけkeyがわからないが、{の後はWが来ると予想できることから復号する。
enc_flag = '1d14273b1c27274b1f10273b05380c295f5f0b03015e301b1b5a293d063c62333e383a20213439162e0037243a72731c22311c2d261727172d5c050b131c433113706b6047556b6b6b6b5f72045c371727173c2b1602503c3c0d3702241f6a78247b253d7a393f143e3224321b1d14090c03185e437a7a607b52566c6c5b6c034047' m = [] for i in range(0, len(enc_flag), 2): m.append(int(enc_flag[i:i+2], 16)) idxes = [] for a in range(10): i = a for b in range(len(m)/10): if b % 2 != 0: idxes.append(i) else: idxes.append(i+10-(a+1+a)) i += 10 FLAG_HEAD = 'ISITDTU{' FLAG_TAIL = '}' key = [-1] * 10 for i in range(len(FLAG_HEAD)): idx = idxes.index(i) key[9-i] = ord(FLAG_HEAD[i]) ^ m[idx] print key idx = idxes.index(len(m) - 1) key[0] = ord(FLAG_TAIL) ^ m[idx] FLAG_EXPECTED_FIRST = 'W' idx = idxes.index(len(FLAG_HEAD)) key[1] = ord(FLAG_EXPECTED_FIRST) ^ m[idx] flag = '' for i in range(len(m)): idx = idxes.index(i) k = key[idx//(len(m)/10)] if k == -1: flag += '*' else: flag += chr(m[idx] ^ k) print flag
ISITDTU{Welcome_to_ISITDTUCTF_C0ntest!_Hav3_a_g00d_day._Hope_y0u_w1ll_3nj0y_and_hav3_a_h1gh_rank_1n_0ur_F1rst_Ctf_C0nt3st._Thank5}
Love CryptoGraphy (Crypto)
mesに"ISITDTU"が含まれていることがわかっている。同じ文字は同じ数字になるので、該当箇所を探す。
I: 1470896290937720121923671834268680644293311486759008609851306976 S: 998119569566922793772397587105095499481847516084421474175736111 I: 1470896290937720121923671834268680644293311486759008609851306976 T: 2108440654988370562048343461399852810852299068780806568036885800 D: 549685894064591284908235658839357390847445522332458370260385633 T: 2108440654988370562048343461399852810852299068780806568036885800 U: 903564225292763328142142737672378470519554721949504047040621938
このことからm, c, nを求める。それから逆算すれば、復号できる。
from Crypto.Util.number import inverse enc_nums = [360575205516272353647725959973923332922859934062623515990157287L, 147121471099487603100103942210642238821212368870164629959708554L, 973776523698456974485285268207248463304785539161797442415515724L, 973776523698456974485285268207248463304785539161797442415515724L, 1989542264845745277130976293069288745712944297723265109141551240L, 2251682090999461666252822948628263912168715816760972058692440747L, 147121471099487603100103942210642238821212368870164629959708554L, 500999802327659646334011021043663318493321568487210306739944859L, 147121471099487603100103942210642238821212368870164629959708554L, 690110490875978577594520719909097376417907156757045161010173205L, 1516765543474947948979702045905703600901480327048677973465980375L, 1446553245069254302636559515370833608116249509836384578091086589L, 1989542264845745277130976293069288745712944297723265109141551240L, 1351997900795094837006304665938116579153956715701467150955972416L, 1516765543474947948979702045905703600901480327048677973465980375L, 1684350025354504872471293852031961738394959051951467495881755709L, 2251682090999461666252822948628263912168715816760972058692440747L, 595555146601819111964265870476380347455614362622127733875059032L, 1162887212246775905745794967072682521229371127431632296685744070L, 2273208297668223674021740841367439832599822680128017390546893759L, 1800431576297426345870466594203854687788358709453430254871322894L, 2251682090999461666252822948628263912168715816760972058692440747L, 2273208297668223674021740841367439832599822680128017390546893759L, 1800431576297426345870466594203854687788358709453430254871322894L, 2251682090999461666252822948628263912168715816760972058692440747L, 1516765543474947948979702045905703600901480327048677973465980375L, 1989542264845745277130976293069288745712944297723265109141551240L, 1705876232023266880240211744771137658826065915318512827736208721L, 690110490875978577594520719909097376417907156757045161010173205L, 2251682090999461666252822948628263912168715816760972058692440747L, 1257442556520935371376049816505399550191663921566549723820858243L, 973776523698456974485285268207248463304785539161797442415515724L, 336232159647806534360613641076076296745797957139999484229936900L, 52566126825328137469849092777925209858919574735247202824594381L, 1022462615435388613059509906002942535658909493007045505935956498L, 2251682090999461666252822948628263912168715816760972058692440747L, 1470896290937720121923671834268680644293311486759008609851306976L, 998119569566922793772397587105095499481847516084421474175736111L, 1470896290937720121923671834268680644293311486759008609851306976L, 2108440654988370562048343461399852810852299068780806568036885800L, 549685894064591284908235658839357390847445522332458370260385633L, 2108440654988370562048343461399852810852299068780806568036885800L, 903564225292763328142142737672378470519554721949504047040621938L, 1422210199200788483349447196472986571939187532913760546330866202L, 1446553245069254302636559515370833608116249509836384578091086589L, 690110490875978577594520719909097376417907156757045161010173205L, 147121471099487603100103942210642238821212368870164629959708554L, 336232159647806534360613641076076296745797957139999484229936900L, 2178652953394064208391485991934722803637529885993099963411779586L, 430787503921965999990868490508793325708090751274916911365051073L, 171464516967953422387216261108489274998274345792788661719928941L, 1754562323760198518814436382566831731180189869163760891256649495L, 1565451635211879587553926683701397673255604280893926036986421149L, 430787503921965999990868490508793325708090751274916911365051073L, 1705876232023266880240211744771137658826065915318512827736208721L, 879221179424297508855030418774531434342492745026880015280401551L, 2178652953394064208391485991934722803637529885993099963411779586L, 879221179424297508855030418774531434342492745026880015280401551L, 1989542264845745277130976293069288745712944297723265109141551240L, 1611320887749107414609956895338420629863773121183595400601094548L, 879221179424297508855030418774531434342492745026880015280401551L, 430787503921965999990868490508793325708090751274916911365051073L, 336232159647806534360613641076076296745797957139999484229936900L, 973776523698456974485285268207248463304785539161797442415515724L, 973776523698456974485285268207248463304785539161797442415515724L, 1327654854926629017719192347040269542976894738778843119195752029L] enc_S = enc_nums[37] enc_T = enc_nums[39] enc_U = enc_nums[42] m = enc_T - enc_S n = m - (enc_U - enc_T) c = (enc_S - m * ord('S')) % n mes = '' for enc_num in enc_nums: code = ((enc_num - c) * inverse(m, n)) % n mes += chr(code) print mes
実行結果は以下の通り。
Hello everybody, this is your flag: ISITDTU{break_LCG_unknown_all}
ISITDTU{break_LCG_unknown_all}
Baby (Crypto)
numerを指定。flagの値とのorのsha512を返す。各ビットの1とXORを取り変わらなければ1、変われば0になることを使って、1ビットずつフラグを割り出す。
import socket from hashlib import * def checkFlag(flag_bit, h): f = int(flag_bit, 2) if sha512(str(f)).digest().encode('hex') == h: return True else: return False def convFlag(flag_bit): flag = '' for i in range(0, len(flag_bit), 8): flag += chr(int(flag_bit[i:i+8], 2)) return flag s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('35.185.178.212', 33337)) data = s.recv(1024) data += s.recv(1024) print data + '0' s.sendall('0\n') data = s.recv(1024) data += s.recv(1024) print data h_flag = data.split('\n')[1] print 'h_flag =', h_flag bit = 0 flag_bit = '' while True: number = 2**bit print number s.sendall(str(number) + '\n') data = s.recv(1024) data += s.recv(1024) print data h = data.split('\n')[1] if h == h_flag: flag_bit = '1' + flag_bit else: flag_bit = '0' + flag_bit if len(flag_bit) % 8 == 0: flag = convFlag(flag_bit) print flag if checkFlag(flag_bit, h_flag): break bit += 1 flag = convFlag(flag_bit) print flag
ISITDTU{bit_flipping_is_fun}
Simple RSA (Crypto)
コードの以下の部分からおおよそpはNを10**6で割った数値の4乗根。
p = next_prime(p) p1 = next_prime(p*10) p2 = next_prime(p1*10) p3 = next_prime(p2*10) N = p*p1*p2*p3
その値から少しずつ調整し、各要素の乗算がNになるものを探す。素因数分解できれば、あとはMulti-prime RSAの復号の解き方で復号できる。
import gmpy from Crypto.Util.number import * def rev_next_prime(n): num = n - 1 while True: if isPrime(num): return num num += 1 def chinese_remainder(n, a): sum = 0 prod = reduce(lambda a, b: a*b, n) for n_i, a_i in zip(n, a): p = prod / n_i sum += a_i * gmpy.invert(p, n_i) * p return sum % prod N = 603040899191765499692105412408128039799635285914243838639458755491385487537245112353139626673905393100145421529413079339538777058510964724244525164265239307111938912323072543529589488452173312928447289267651249034509309453696972053651162310797873759227949341560295688041964008368596191262760564685226946006231 e = 65537 c = 153348390614662968396805701018941225929976855876673665545678808357493865670852637784454103632206407687489178974011663144922612614936251484669376715328818177626125051048699207156003563901638883835345344061093282392322541967439067639713967480376436913225761668591305793224841429397848597912616509823391639856132 tmp_p = gmpy.root(N // (10**6), 4)[0] while True: p = rev_next_prime(tmp_p) p1 = rev_next_prime(p*10) p2 = rev_next_prime(p1*10) p3 = rev_next_prime(p2*10) if p*p1*p2*p3 == N: break tmp_p -= 1 primes = [] primes.append(p) primes.append(p1) primes.append(p2) primes.append(p3) n_ary = [] a_ary = [] for p in primes: phi = p - 1 d = gmpy.invert(e, phi) mk = pow(c, d, p) n_ary.append(p) a_ary.append(mk) m = chinese_remainder(n_ary, a_ary) flag = ('%x' % m).decode('hex') print flag
ISITDTU{f6b2b7472273aacf803ecfe93607a914}
aes_cnv (Crypto)
$ nc 35.185.111.53 13337
******************************************************************
* Challenge created by chung96vn *
* My blog: https://chung96vn.blogspot.com *
* From: AceBear Team *
******************************************************************
Give me content of your request you want to encrypt: aaa
Your encypted: kO/CNrsWq0FJ7jA86Jjcb3zpu/AoSRxt4gXXpWlgOeYwqjZGfbXZZ8BKNaSvFbup
Give me encrypted of your request: kO/CNrsWq0FJ7jA86Jjcb3zpu/AoSRxt4gXXpWlgOeYwqjZGfbXZZ8BKNaSvFbup
Your request: aaa
Bye~~
以下、処理のメモ。
req: 暗号化する文字(Give me the flagで始まるものはダメ) game.encode(req)を表示 enc: 暗号化文字 game.decode(enc)を表示 Give me the flagで始まるものの場合、フラグを表示
Give me the flagは16文字なので、1ブロック目しか気にする必要はない。以下のように調整すれば、1ブロック目の暗号化は同じになり、フラグが得られるはず。
aaaaaaaaaaaaaaa ^ IV1 = Give me the flag ^ IV2
import socket import re from base64 import b64decode from base64 import b64encode def str_xor(s1, s2): return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2)) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('35.185.111.53', 13337)) data = s.recv(1024) data += s.recv(1024) plain1 = 'a' * 16 print data + plain1 s.sendall(plain1 + '\n') data = s.recv(1024) data += s.recv(1024) print data[:-1], pattern = 'Your encypted: (.+)' m = re.search(pattern, data) b64_enc = m.group(1) enc = b64decode(b64_enc) iv1 = enc[:16] enc_body = enc[16:] plain2 = 'Give me the flag' iv2 = str_xor(str_xor(plain1, iv1), plain2) enc = iv2 + enc_body b64_enc = b64encode(enc) print b64_enc s.sendall(b64_enc + '\n') data = s.recv(1024) data += s.recv(1024) print data
ISITDTU{chung96vn_i5_v3ry_h4nds0m3}