Zh3r0 CTF Writeup

この大会は2020/6/16 0:30(JST)~2020/6/18 0:30(JST)に開催されました。
今回もチームで参戦。結果は4252点で810チーム中63位でした。
自分で解けた問題をWriteupとして書いておきます。

Welcome to Phase 1 (Misc)

入力欄に書いてある。

zh3r0{is_this_a_real_flag?}

Flag 5 (Subset of subset of hacking machines challenges)

$ nmap -Pn hackit.zh3r0.ml

Starting Nmap 7.60 ( https://nmap.org ) at 2020-06-16 20:20 JST
Nmap scan report for hackit.zh3r0.ml (139.59.3.42)
Host is up (0.14s latency).
Not shown: 998 filtered ports
PORT   STATE SERVICE
22/tcp open  ssh
99/tcp open  metagram

Nmap done: 1 IP address (1 host up) scanned in 22.31 seconds

$ nmap -P0 -A hackit.zh3r0.ml -p 22,99

Starting Nmap 7.60 ( https://nmap.org ) at 2020-06-16 20:25 JST
Nmap scan report for hackit.zh3r0.ml (139.59.3.42)
Host is up (0.13s latency).

PORT   STATE SERVICE VERSION
22/tcp open  http    PHP cli server 5.5 or later
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
99/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 70:78:8f:70:79:59:72:5f:05:c9:2a:63:b4:34:c1:52 (RSA)
|   256 08:6d:42:16:2a:47:ae:b4:d7:fa:35:28:91:67:ab:63 (ECDSA)
|_  256 e4:89:6b:09:37:64:c2:47:01:bd:c2:32:d8:cd:06:2d (EdDSA)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 53.07 seconds

$ curl http://hackit.zh3r0.ml:22/
z3hr0{shouldve_added_some_filter_here}
z3hr0{shouldve_added_some_filter_here}

snakes everywhere (Reversing)

Pythonコードのアセンブリからコードにすると、以下のようになる。

from flags import flag1
flag = flag1
fake_flag = 'zh3r0{fake flag}'

key = 'I_l0v3_r3v3r51ng'

assert len(flag) == 38

def xor(str1, str2):
    return chr(ord(str1) ^ ord(str2))


ciphertext = ''

for i in range(len(flag)//3):
    ciphertext += chr(ord(key[i]) * ord(flag[i]) - i)

for i in range(len(flag)//3, len(flag)//3*2):
    ciphertext += chr(ord(flag[i]) * ord(key[i%len(key)]) + i)

for i in range(len(key)//2, len(flag)):
    ciphertext += xor(key[i%16], flag[i])

file = open('ciphertext.txt', 'w')
print(len(ciphertext))
file.write(ciphertext)
file.close()

以上から逆算していけばフラグになる。

#!/usr/bin/env python3
import codecs

def xor(str1, str2):
    return chr(ord(str1) ^ ord(str2))

key = 'I_l0v3_r3v3r51ng'

with codecs.open('snake.txt', 'r', 'utf-8') as f:
    ciphertext = f.read()

flag = ''
for i in range(12):
    flag += chr((ord(ciphertext[i]) + i) // ord(key[i]))

for i in range(12, 24):
    flag += chr((ord(ciphertext[i]) - i) // ord(key[i%len(key)]))

for i in range(8, 38):
    if i < 24:
        assert flag[i] == xor(ciphertext[i+16], key[i%16])
    else:
        flag += xor(ciphertext[i+16], key[i%16])

print(flag)
zh3r0{Python_disass3mbly_is v3ry_E4sy}

Web-Warmup (Web)

HTMLソースを見る。読み込んでいるbg.cssを見ると、コメントにフラグが書いてあった。

/*css is easy, I think. Don't you?zh3r0{y3s_th1s_1s_w4rmup}*/
zh3r0{y3s_th1s_1s_w4rmup}

LSB fun (Forensics)

Windowsのjstegツールで抽出する。

>jsteg reveal chall.jpg
zh3r0{j5t3g_i5_c00l}
zh3r0{j5t3g_i5_c00l}

Katycat (Forensics)

$ zsteg katy.png 
b1,rgb,lsb,xy       .. text: "https://pastebin.com/hvgCXNcP"
b2,r,msb,xy         .. file: PGP\011Secret Key -
b2,rgb,msb,xy       .. text: "EEQPUUU@U"
b2,abgr,msb,xy      .. text: "WSSWCCCCSSWWCC"
b3,bgr,msb,xy       .. text: "(Z0-X0-H"
b4,r,lsb,xy         .. text: "DfffdDB\""
b4,r,msb,xy         .. text: "@\"fa\"DD$DD"
b4,g,lsb,xy         .. text: "D\"\"$\"D\"\"\" "
b4,g,msb,xy         .. text: "&b\"fa\"DD$D\"DDD"
b4,b,lsb,xy         .. text: "vPUFwDT!"
b4,b,msb,xy         .. text: "USUs33UU&\"Q3"
b4,rgb,lsb,xy       .. text: "hDdD\"B$\"\"\"\"dF\"b$$"
b4,rgb,msb,xy       .. text: "QU3sUS53337uSp"
b4,bgr,lsb,xy       .. text: "fdDDB$\"\"\"\"b&Db$\""
b4,bgr,msb,xy       .. text: "Su3S5U3335WsuP"
b4,abgr,msb,xy      .. text: "?U?U?5?5?"

https://pastebin.com/hvgCXNcPにアクセスしてみると、以下の文字列がある。

UEsDBAoACQAAALq0vFDu3sG8JQAAABkAAAAIABwAZmxhZy50eHRVVAkAA+jvz179789edXgLAAEE
6AMAAAToAwAAt9tbOQhvceVTC9i83YoBgbIW5fmqoaO3mVwXSLOMqNulwvcwb1BLBwju3sG8JQAA
ABkAAABQSwECHgMKAAkAAAC6tLxQ7t7BvCUAAAAZAAAACAAYAAAAAAABAAAApIEAAAAAZmxhZy50
eHRVVAUAA+jvz151eAsAAQToAwAABOgDAABQSwUGAAAAAAEAAQBOAAAAdwAAAAAA
enc = '''
UEsDBAoACQAAALq0vFDu3sG8JQAAABkAAAAIABwAZmxhZy50eHRVVAkAA+jvz179789edXgLAAEE
6AMAAAToAwAAt9tbOQhvceVTC9i83YoBgbIW5fmqoaO3mVwXSLOMqNulwvcwb1BLBwju3sG8JQAA
ABkAAABQSwECHgMKAAkAAAC6tLxQ7t7BvCUAAAAZAAAACAAYAAAAAAABAAAApIEAAAAAZmxhZy50
eHRVVAUAA+jvz151eAsAAQToAwAABOgDAABQSwUGAAAAAAEAAQBOAAAAdwAAAAAA
'''
enc = enc.replace('\n', '')

with open('flag.zip', 'wb') as f:
    f.write(enc.decode('base64'))

base64デコードすると、zipになるが、パスワードがかかっている。fcrackzipでパスワードクラックしてみる。

$ fcrackzip -u -D -p dict/rockyou.txt flag.zip


PASSWORD FOUND!!!!: pw == kitkat

このパスワードで解凍する。

$ unzip -P kitkat flag.zip
Archive:  flag.zip
 extracting: flag.txt
$ cat flag.txt
K9bC_L`D?f0DEb8c?_06cDJN

rot47で復号すると、フラグになった。

zh3r0{1sn7_st3g4n0_e4sy}

Snow (Forensics)

タイトルからもsnowを使ったステガノグラフィと推測できる。.secret.txtの内容をパスワードとして抽出する。

>SNOW.EXE -C -p welc0me_to_zh3r0_ctf chall.txt
zh3r0{i5_it_sn0w1ng?}
zh3r0{i5_it_sn0w1ng?}

RSA-Warmup (Crypto)

$ nc crypto.zh3r0.ml 8451
N: 362204497165012221441752622398014284477672934484246574352668248354962122223480948879218151496432533426651807605790387028320471297675381207280285987455705667520240462620907047537189803348668442653464783479975255974364741816154041849217512816179839303882436285701309813781493647198306032967736450341404564444063064572857
e 65537
CT: 28279148543261010538786162189188416138622702190690046805887004409024981386725281303105636820548914828865663276341527926288823477904578678093032127397866691471033090624228990190190140386526912958442365620531660273304172392330422040873262164993051721152973279728450632330158105145649469394623518488176940748325366439174

Nを素因数分解する。

$ python -m primefac 362204497165012221441752622398014284477672934484246574352668248354962122223480948879218151496432533426651807605790387028320471297675381207280285987455705667520240462620907047537189803348668442653464783479975255974364741816154041849217512816179839303882436285701309813781493647198306032967736450341404564444063064572857
362204497165012221441752622398014284477672934484246574352668248354962122223480948879218151496432533426651807605790387028320471297675381207280285987455705667520240462620907047537189803348668442653464783479975255974364741816154041849217512816179839303882436285701309813781493647198306032967736450341404564444063064572857: 3964720609 91356878046538845391249767733132663845083802343724385839231338471084211074980428432811708245248646075946434389922073580423752703749567339886240641643080698481631763985139626653876483367776304928896638799693856555016772889621297864627795470513024314819363930040122989604964027163384423229540220633843045267673

Nを素因数分解できたので、あとはそのまま復号する。

from Crypto.Util.number import *

N = 362204497165012221441752622398014284477672934484246574352668248354962122223480948879218151496432533426651807605790387028320471297675381207280285987455705667520240462620907047537189803348668442653464783479975255974364741816154041849217512816179839303882436285701309813781493647198306032967736450341404564444063064572857
e = 65537
CT = 28279148543261010538786162189188416138622702190690046805887004409024981386725281303105636820548914828865663276341527926288823477904578678093032127397866691471033090624228990190190140386526912958442365620531660273304172392330422040873262164993051721152973279728450632330158105145649469394623518488176940748325366439174

p = 3964720609
q = 91356878046538845391249767733132663845083802343724385839231338471084211074980428432811708245248646075946434389922073580423752703749567339886240641643080698481631763985139626653876483367776304928896638799693856555016772889621297864627795470513024314819363930040122989604964027163384423229540220633843045267673

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(CT, d, N)
flag = long_to_bytes(m)
print flag
zh3r0{RSA_1s_Fun}

Mix (Crypto)

base65536でデコードする。

#!/usr/bin/env python3
import base65536

with open('chall_encrypted.txt', 'r', encoding='utf_8') as f:
    ct = f.read()

pt = base65536.decode(ct)
print(pt.decode())

実行結果は以下の通り。

flag 1:
Yjod od s lrunpstf djogy vo[jrtyrcy jrtr od upi g;sh xj4t-}U-i+dit4+

flag 2:
3030313130313030203031313130303130203030313130303131203031303131313131203030313130313030203031313130313131203030313130303131203031313130303131203030313130303030203031313031313031203030313130303131203031303131313131203031313130313131203031313031303031203030313130313131203031313031303030

flag 3:
MTExMTExMTExMTAwMTAwMDEwMTAxMDExMTAxMDExMTExMTEwMTAxMTExMTExMTExMDExMDExMDExMDExMDAwMDAxMTAxMDAxMDAxMDAxMDAwMDAwMDAwMDAwMDAwMDAwMTAxMDAxMTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMTAxMDAwMDAwMDAwMDAwMTAxMDAwMTAxMDAxMDAwMTAxMDAxMTExMTExMTAwMTAxMDAxMDExMTExMTExMTAwMTAxMDAxMTAwMDAwMDAwMDAwMDAwMTAxMDAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMTAxMDExMTExMTExMTExMTExMTExMTExMDAxMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxMDEwMDAwMDAwMDAxMDEwMDExMDAwMDAwMDAxMDEwMDAxMDEwMTExMTAwMTAxMDAxMDExMTExMTExMTExMTExMTExMTExMDAxMDEwMDExMDExMDExMTExMTExMTExMTAwMTAxMA==

flag1~3について、それぞれ復号する必要がある。まずflag1については、各文字をUS配列キーボード上で左の文字に変える。

This is a keyboard shift ciphertext here is you flag zh3r0{Y0u_sur3_

次にflag2はhexデコードすると、2進数のASCIIコードが並んでいるのがわかるので、デコードする。

import base64

ct2 = '3030313130313030203031313130303130203030313130303131203031303131313131203030313130313030203031313130313131203030313130303131203031313130303131203030313130303030203031313031313031203030313130303131203031303131313131203031313130313131203031313031303031203030313130313131203031313031303030'
codes = ct2.decode('hex').split(' ')

flag2 = ''
for code in codes:
    flag2 += chr(int(code, 2))
print flag2

デコード結果は以下の通り。

4r3_4w3s0m3_wi7h

最後にflag3については、base64デコードすると、0,1の並んだ文字列になるが、ASCIIコードにはなりそうにない。

1111111111001000101010111010111111101011111111110110110110110000011010010010010000000000000000001010011000000000000000000000000000000000000000000000000000000001010000000000001010001010010001010011111111001010010111111111001010011000000000000001010010000000000000000000000000000001010111111111111111111110010100000000000000000000000000010100000000010100110000000010100010101111001010010111111111111111111110010100110110111111111111001010

問題を見ると、SPOONというキーワードがあるので、調べてみると、Spoon Languageというものがあることがわかる。
https://www.dcode.fr/spoon-languageでデコードする。

_411_7h3_ski115}

flag1~3を結合すると、フラグになる。

zh3r0{Y0u_sur3_4r3_4w3s0m3_wi7h_411_7h3_ski115}

Hastad's message (Crypto)

$ nc crypto.zh3r0.ml 7419
N: 22857403917033452762301692151936680227099179828447116694851576122227087851149555427000138614019347046657401967421147503016546446657912243103301489550801502213543799142440722257289782903210973777123770395462277652515090800990170935194739452788926924406411625140822688653866031925496143186166969089756967341706986678103581032106577269283579684740814341978215925969756042680055259503028748627289133764296953426402876584404716806524279688134865241125740556757179831843282004974142256384849751862870211107430066634096097714894315793983740153650155659957823284584625222819243597312146000907539885211491273592108608676263997
CT: 21006791237991463493340715948837281319345332975431116155246886857329226729176905006985301880229589771867164219946980507403131176313843758775517084997896302863517136186936942094292340604242114096356212545068140977209543062639322853952829213905545327059774710190550607656944699178883239469025363244471355734382420605349807467572623064978145945360251167254005860156200061225217268443957714842188064887796139342976650738189179581667380553718551142665142086887013363723794633316229945140842423696160124298510198972514083898687854267419336322673376025386514986398539403721584892994795627805100546778227736928427965280816039

$ nc crypto.zh3r0.ml 7419
N: 24255028471131132079553905484198967796113853854803832085857908151952952553438604497305380360218255010195759694646983763016990035030508175202633392488210643722838705715759466198971587743605730499883974472311824555697152669592357863583927334616520558312740769160009255637189341430484907205847141876471366729441606996227896102150555964555972937245587927782688252918165407439303880665315125498637886009255567255874696729407591739218027242787230753662154898772475316535468193123937724482351740172029114212735258050226173549824091790974175866156475826591910151603770169641134890040540391370445465191312108856014264989983419
CT: 4080653980915597905639514646198687473573442849454819707783099713713422382104870992346376322305324753220468980472324072065019769335937812772641959339576410882752539996679965165219562794135836515575063660680045105348959510487942209928320980889028161465222578675623217424488964105504097617934299285784701174152694716817179016013110373107461312130891720745243058109317442985903785433116301947585694340522495090274741149337040549108069094609388063239087266931938935205446241123974559960107196840388273379246802454394826076801079280490108853216721513492813056227181113503696807736676905961129314440189516070951160240768528

$ nc crypto.zh3r0.ml 7419
N: 18170781317829964454680876495568985113697632391187407846578744087052531477112675213533542625672700822419610345901567198182263091158570601201787845714888045495826219850734105016410092117287277362378896745761380158857097548540976713621657106454534379363303323375130629105535594640138008735015400277243571219812012584396420515815878989240581459952456797172991674149087707378266680425895017939205927487902023669063943408647789564745167286117702947615719992719924064383905809432619142537197018133574831738605207342838580303912716997382979289558793912617558864411334676100405687905822983720599084620562783990512841069780401
CT: 16421004495511763958782822739048726299470163120688526903461320430488416917368074624661373617529321882858883043268395753857587802837859712349474497032398844368474587293204872415008847994460996019119277400038454245204198348047373004175429102952579524430005982588506808607416160075948392466286975076688338000579281720715833339965992184047365696237560807592187133148808044698570623096872957459722460928209621248015591145194604248730523613931253283523316930243593394425608043954849400410380900216653789971518865354330515457388937591390035942970879666182575102575041672419570372174753138366738036997445784549007667425022295

eの値はわからないが、とりあえずe=3として3つのデータを集め、Hastad's Broadcast Attackで復号してみるが、うまくいかなかった。さらに2つのデータを集める。

$ nc crypto.zh3r0.ml 7419
N: 18381521670468669483125585535872682141850263297128579361275636911380507573797401758589301007911962912929657515275269863194175875752890317760263717055015302034421756983390372419334702052084367063446373277862931097423244154285118179117892587143633004715840167349173688639034638801842458735448404548970627564765423490499776295630455197197223957539093720798843471184912396633300558792099829828026289655503505196822190051132389391628953432211739874968197367189223781866012905951782997344495708430917952820714445618318673029669347893710046232869414785081166992164976832492308617162252015602581429407743510730957911298012421
CT: 1818892344291150537872012729215705122734238326815668996961579488232419188824050503233307373549204308663271437843774188077568286368923059868354156657642490397060779759446489103790176917775051873835530733346890879137836113716115814508550855715821953590672459496312656022341509256040734847291970639809901518117832540714387827314693528653612061512064870782976670018665074687028614426300382563677842204341520468146624639048010518108375189941778370046173224264766679336949866012929878305757088219461570251770129940691519585417412368422989271566419214088150943534964026343300089924340622123992441664730270764149871235142536

$ nc crypto.zh3r0.ml 7419
N: 24734494903694969744575863846845904407753451836991665788830976839955898670258636144673676463220033110047190799495183607210280172541939189869982701604224204422324525455826659132479539317246176913090534409398141536909955246566256622784342406536057772835527020520414060722692873534272745699558390874305048328998316865423785482997405348891762811594525859452959439903945538655453636380296676586240884908596590906244873206042296763628632887732787926635197575233002004463287098051749689831983198984586683992196167915209070530685176685511999474083049088414885221523468506180076982155175996087885097390199263784159028723755969
CT: 12234027254738065079308678164515853762386657938164876547464782059807602392721470637458014128343488029878456988990625453370008672737998196811664785626635975123287666874966033053311723420277382605028538477470057448860946203384350301962098533905082391988247355522230150210738399620642541614854621638391571546534083090214981674398127144628767303126200529760600329589741832571931960007009869597427838973352486821367509562025643864799572949058480884145061530932914189605837814509387660323215110814788732659079516894101010991761217221401823561781414765493231103098860170642291471339517281171816879226186688416616775070727473

今度はeの値を5にして試してみる。

import functools
from Crypto.Util.number import *

def chinese_remainder(n, a):
    sum = 0
    prod = functools.reduce(lambda a, b: a*b, n)
    for n_i, a_i in zip(n, a):
        p = prod // n_i
        sum += a_i * mul_inv(p, n_i) * p
    return sum % prod
 
def mul_inv(a, b):
    b0 = b
    x0, x1 = 0, 1
    if b == 1: return 1
    while a > 1:
        q = a // b
        a, b = b, a%b
        x0, x1 = x1 - q * x0, x0
    if x1 < 0: x1 += b0
    return x1

def inv_pow(c, e):
    low = -1
    high = c+1
    while low + 1 < high:
        m = (low + high) // 2
        p = pow(m, e)
        if p < c:
            low = m
        else:
            high = m
    m = high
    assert pow(m, e) == c
    return m

N1 = 22857403917033452762301692151936680227099179828447116694851576122227087851149555427000138614019347046657401967421147503016546446657912243103301489550801502213543799142440722257289782903210973777123770395462277652515090800990170935194739452788926924406411625140822688653866031925496143186166969089756967341706986678103581032106577269283579684740814341978215925969756042680055259503028748627289133764296953426402876584404716806524279688134865241125740556757179831843282004974142256384849751862870211107430066634096097714894315793983740153650155659957823284584625222819243597312146000907539885211491273592108608676263997
CT1 = 21006791237991463493340715948837281319345332975431116155246886857329226729176905006985301880229589771867164219946980507403131176313843758775517084997896302863517136186936942094292340604242114096356212545068140977209543062639322853952829213905545327059774710190550607656944699178883239469025363244471355734382420605349807467572623064978145945360251167254005860156200061225217268443957714842188064887796139342976650738189179581667380553718551142665142086887013363723794633316229945140842423696160124298510198972514083898687854267419336322673376025386514986398539403721584892994795627805100546778227736928427965280816039

N2 = 24255028471131132079553905484198967796113853854803832085857908151952952553438604497305380360218255010195759694646983763016990035030508175202633392488210643722838705715759466198971587743605730499883974472311824555697152669592357863583927334616520558312740769160009255637189341430484907205847141876471366729441606996227896102150555964555972937245587927782688252918165407439303880665315125498637886009255567255874696729407591739218027242787230753662154898772475316535468193123937724482351740172029114212735258050226173549824091790974175866156475826591910151603770169641134890040540391370445465191312108856014264989983419
CT2 = 4080653980915597905639514646198687473573442849454819707783099713713422382104870992346376322305324753220468980472324072065019769335937812772641959339576410882752539996679965165219562794135836515575063660680045105348959510487942209928320980889028161465222578675623217424488964105504097617934299285784701174152694716817179016013110373107461312130891720745243058109317442985903785433116301947585694340522495090274741149337040549108069094609388063239087266931938935205446241123974559960107196840388273379246802454394826076801079280490108853216721513492813056227181113503696807736676905961129314440189516070951160240768528

N3 = 18170781317829964454680876495568985113697632391187407846578744087052531477112675213533542625672700822419610345901567198182263091158570601201787845714888045495826219850734105016410092117287277362378896745761380158857097548540976713621657106454534379363303323375130629105535594640138008735015400277243571219812012584396420515815878989240581459952456797172991674149087707378266680425895017939205927487902023669063943408647789564745167286117702947615719992719924064383905809432619142537197018133574831738605207342838580303912716997382979289558793912617558864411334676100405687905822983720599084620562783990512841069780401
CT3 = 16421004495511763958782822739048726299470163120688526903461320430488416917368074624661373617529321882858883043268395753857587802837859712349474497032398844368474587293204872415008847994460996019119277400038454245204198348047373004175429102952579524430005982588506808607416160075948392466286975076688338000579281720715833339965992184047365696237560807592187133148808044698570623096872957459722460928209621248015591145194604248730523613931253283523316930243593394425608043954849400410380900216653789971518865354330515457388937591390035942970879666182575102575041672419570372174753138366738036997445784549007667425022295

N4 = 18381521670468669483125585535872682141850263297128579361275636911380507573797401758589301007911962912929657515275269863194175875752890317760263717055015302034421756983390372419334702052084367063446373277862931097423244154285118179117892587143633004715840167349173688639034638801842458735448404548970627564765423490499776295630455197197223957539093720798843471184912396633300558792099829828026289655503505196822190051132389391628953432211739874968197367189223781866012905951782997344495708430917952820714445618318673029669347893710046232869414785081166992164976832492308617162252015602581429407743510730957911298012421
CT4 = 1818892344291150537872012729215705122734238326815668996961579488232419188824050503233307373549204308663271437843774188077568286368923059868354156657642490397060779759446489103790176917775051873835530733346890879137836113716115814508550855715821953590672459496312656022341509256040734847291970639809901518117832540714387827314693528653612061512064870782976670018665074687028614426300382563677842204341520468146624639048010518108375189941778370046173224264766679336949866012929878305757088219461570251770129940691519585417412368422989271566419214088150943534964026343300089924340622123992441664730270764149871235142536

N5 = 24734494903694969744575863846845904407753451836991665788830976839955898670258636144673676463220033110047190799495183607210280172541939189869982701604224204422324525455826659132479539317246176913090534409398141536909955246566256622784342406536057772835527020520414060722692873534272745699558390874305048328998316865423785482997405348891762811594525859452959439903945538655453636380296676586240884908596590906244873206042296763628632887732787926635197575233002004463287098051749689831983198984586683992196167915209070530685176685511999474083049088414885221523468506180076982155175996087885097390199263784159028723755969
CT5 = 12234027254738065079308678164515853762386657938164876547464782059807602392721470637458014128343488029878456988990625453370008672737998196811664785626635975123287666874966033053311723420277382605028538477470057448860946203384350301962098533905082391988247355522230150210738399620642541614854621638391571546534083090214981674398127144628767303126200529760600329589741832571931960007009869597427838973352486821367509562025643864799572949058480884145061530932914189605837814509387660323215110814788732659079516894101010991761217221401823561781414765493231103098860170642291471339517281171816879226186688416616775070727473

N = [N1, N2, N3, N4, N5]
C = [CT1, CT2, CT3, CT4, CT5]
e = len(N)
a = chinese_remainder(N, C)
for n, c in zip(N, C):
    assert a % n == c
m = inv_pow(a, e)
flag = long_to_bytes(m)
print flag

実行結果は以下の通り。

Its great that you have come till here. As promised here is your flag: zh3r0{RSA_1s_0n3_of_th3_b4st_encrypt10n_Bu66y}
zh3r0{RSA_1s_0n3_of_th3_b4st_encrypt10n_Bu66y}

Help me (Crypto)

Pythonコードのアセンブリからコードにすると、以下のようになる。

from flag import flag, key
from binascii import hexlify
from Crypto.Util.number import *


assert len(flag) == 48

fake_flag = 'zh3r0{l0l_thi5_i5_n0t_th3_fl4g}'

def xor(str1, str2, num):
    return chr((ord(str1[num]) + num) ^ ord(str2[num]))

def first_half(half_flag):
    return [hexlify(half_flag[i:i+4].encode()) for i in range(0, len(half_flag), 4)]

def second_half(half_flag):
    return [bytes_to_long(half_flag[i:i+4].encode()) for i in range(0, len(half_flag), 4)]

def encrypt(flag, key):
    final = []
    first_xor = [xor(flag[:len(flag)//2], key[len(key)//2:], i) for i in range(len(flag)//2)]
    second_xor = [xor(flag[len(flag)//2:], key[:len(key)//2], i) for i in range(len(flag)//2)]
    final += first_half(''.join(first_xor))
    final += second_half(''.join(second_xor))
    return final

print(encrypt(key, flag))

このコードを見ると、フラグを前半、後半に分け、以下のような処理になっている。

・フラグの前半、鍵の後半とXORを取り、4バイトごとに16進数表示にする。
・フラグの後半、鍵の前半とXORを取り、4バイトごとに数値表示にする。

鍵がわかれば、復号できる。鍵は以下の文字列であるようだが、エンコードされている。

5Nzwbdkvm1VF1X3zc8d6kPd7MMTgSW9Dv1otpwkbPyggHqk5CaEHYwCD14vBdc3w86

試した結果、base58デコードして、rot47にすると、正しい鍵になる。あとはXORで元に戻していく。

#!/usr/bin/env python3
import base58
from binascii import unhexlify
from Crypto.Util.number import *

def rot47(s):
    d = ''
    for c in s:
        code = ord(c) + 47
        if code > 126:
            code -= 94
        d += chr(code)
    return d

def rev_xor(str1, str2, num):
    return chr((ord(str1[num]) ^ ord(str2[num])) - num)

key = '5Nzwbdkvm1VF1X3zc8d6kPd7MMTgSW9Dv1otpwkbPyggHqk5CaEHYwCD14vBdc3w86'
key = rot47(base58.b58decode(key).decode())
print('key =', key)

ct = [b'03367345', b'46c39f41c3a8', b'1544651a', b'03451b28', b'77c3aac3a275',
    b'c39e16c3b6c3b2', 391124763, 121061897, 1396123432, 389813723487,
    295339258400, 131682038629031]

ct1 = ''
for i in range(6):
    ct1 += (unhexlify(ct[i])).decode()

flag1 = ''
for i in range(24):
    flag1 += rev_xor(ct1, key[len(key)//2:], i)

ct2 = ''
for i in range(6):
    ct2 += (long_to_bytes(ct[i+6])).decode()

flag2 = ''
for i in range(24):
    flag2 += rev_xor(ct2, key[:len(key)//2], i)

flag = flag1 + flag2
print(flag)

実行結果は以下の通り。

key = H3ll0_tbh_Th15_15_7h3_k3y_F0r_7hi5_ch4ll3ng3_atb
zh3r0{pyth0n_di54ss3mbly_byt3c0d3_i5_s0_aw350m3}
zh3r0{pyth0n_di54ss3mbly_byt3c0d3_i5_s0_aw350m3}

We are related (Crypto)

$ nc crypto.zh3r0.ml 9841
__        __   _                            _        
\ \      / /__| | ___ ___  _ __ ___   ___  | |_ ___  
 \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | __/ _ \ 
  \ V  V /  __/ | (_| (_) | | | | | |  __/ | || (_) |
   \_/\_/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/ 
                                                     
 ______     _____       ___     ____ _____ _____ 
|__  / |__ |___ / _ __ / _ \   / ___|_   _|  ___|
  / /| '_ \  |_ \| '__| | | | | |     | | | |_   
 / /_| | | |___) | |  | |_| | | |___  | | |  _|  
/____|_| |_|____/|_|   \___/   \____| |_| |_|    
                                                 
Enter the Selection from below:
1.Print PublicKey
2.Encrypt
0.Exit
1
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAl/DEzNkDSy545CVnRDY6
MvnY3uT9AqXvUawLjvPxkpGFvjNZgXUZDXz4d+OM+kI0wCitG/qKKyALNBCRV4H1
Ff032MF4M83DZauv9mekDRYTHt1kc3yjXGgkDKrbwx/52oK1zzjDpdL35+0DGrCV
MuM6UUGmwULkt9pwkltaQ7CnK/mD8r9/kxCvYrsOdXKfG7oa6M8jmJ2Fg8KI30K7
BNLBQnrHEd+gk9cbeZO2EPfCgpeRBIkpN/m+wCaVeF4MhvHAqO7WY8HWGnWOXTvX
s/s38/18neVZpi6sb+Xzd5bS3MXF6LAYnpsPFtlZQwkef0isv+fIbRehCBxOOXMO
cwIBAw==
-----END PUBLIC KEY-----
-
Enter the Selection from below:
1.Print PublicKey
2.Encrypt
0.Exit
2
Enter the string to encode: abcd
Enc(flag + txt )=  8970069242936796240592467432599156013080215640242622142716638380716496388318218827228177466775343321619498071518451653744711981856521130553675889757562908518677580048412886296996915808378746450183982256985464602144653407697809249520698602827527280781562784845946163489064901426799558385428176157519796179474332484171830380047013723814868909474003768621828427343543355871057472154281785885153866549296559467827664976305001529862210453635791629571086504961684919394576382581049981522305048694616340885019017787650425307937177838677302828709346413542174337381942446754224559359173158887030894762785463508182475761729429

差異が小さい2つの平文を指定して得られた暗号文から、Franklin-Reiter Related Message Attackで復号する。

import socket
import re
from Crypto.PublicKey import RSA
from Crypto.Util.number import *

def recvuntil(s, tail):
    data = ''
    while True:
        if tail in data:
            return data
        data += s.recv(1)

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(('crypto.zh3r0.ml', 9841))

data = recvuntil(s, 'Exit\n').rstrip()
print data
print '1'
s.sendall('1\n')
data = recvuntil(s, 'Exit\n').rstrip()
print data

pattern = '(-----BEGIN.+)\n-\n'
m = re.search(pattern, data, re.DOTALL)
pub_data = m.group(1)
pubkey = RSA.importKey(pub_data)
n = pubkey.n
e = pubkey.e

print '2'
s.sendall('2\n')
data = recvuntil(s, ': ')
print data + '0'
s.sendall('0\n')
data = recvuntil(s, '\n').rstrip()
print data
c1 = int(data.split('= ')[1])

data = recvuntil(s, 'Exit\n').rstrip()
print data
print '2'
s.sendall('2\n')
data = recvuntil(s, ': ')
print data + '1'
s.sendall('1\n')
data = recvuntil(s, '\n').rstrip()
print data
c2 = int(data.split('= ')[1])

m = related_message_attack(c1, c2, 1, e, n) - ord('0')
flag = long_to_bytes(m)
print flag

実行結果は以下の通り。

__        __   _                            _        
\ \      / /__| | ___ ___  _ __ ___   ___  | |_ ___  
 \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | __/ _ \ 
  \ V  V /  __/ | (_| (_) | | | | | |  __/ | || (_) |
   \_/\_/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/ 
                                                     
 ______     _____       ___     ____ _____ _____ 
|__  / |__ |___ / _ __ / _ \   / ___|_   _|  ___|
  / /| '_ \  |_ \| '__| | | | | |     | | | |_   
 / /_| | | |___) | |  | |_| | | |___  | | |  _|  
/____|_| |_|____/|_|   \___/   \____| |_| |_|    
                                                 
Enter the Selection from below:
1.Print PublicKey
2.Encrypt
0.Exit
1
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAl/DEzNkDSy545CVnRDY6
MvnY3uT9AqXvUawLjvPxkpGFvjNZgXUZDXz4d+OM+kI0wCitG/qKKyALNBCRV4H1
Ff032MF4M83DZauv9mekDRYTHt1kc3yjXGgkDKrbwx/52oK1zzjDpdL35+0DGrCV
MuM6UUGmwULkt9pwkltaQ7CnK/mD8r9/kxCvYrsOdXKfG7oa6M8jmJ2Fg8KI30K7
BNLBQnrHEd+gk9cbeZO2EPfCgpeRBIkpN/m+wCaVeF4MhvHAqO7WY8HWGnWOXTvX
s/s38/18neVZpi6sb+Xzd5bS3MXF6LAYnpsPFtlZQwkef0isv+fIbRehCBxOOXMO
cwIBAw==
-----END PUBLIC KEY-----
-
Enter the Selection from below:
1.Print PublicKey
2.Encrypt
0.Exit
2
Enter the string to encode: 0
Enc(flag + txt )=  13169774813221511932243873546844686383429967108387653396065460783119889477620840823513401679577611996837338005483588575134052478350079942715431961589620136843875590673217399575273596108447574506950030016546674713998660920813377509803665385450453818464732354501901994635510858425018006454080817781883348815744626138292034308959728140477817938045617359712978850536365597757007166295857825722644656280282334225559119248341906162439090046230116071626572773985654425634020373645249892360206543799112345973352843561359517466444973871246937018740694815587461488742430916233108821158490464189819556074363093373542390633034484
Enter the Selection from below:
1.Print PublicKey
2.Encrypt
0.Exit
2
Enter the string to encode: 1
Enc(flag + txt )=  7173580354976976582846590191301810085856396752549786919532282832533101326381038480413419787621164385989627028836508242290734402539094318654342082710202448254109164534425787618048338637638538182485709796170229306721213213871796048985877100141346650130649164671419423764444799227908522501862169358337016555547839809907903306641248006682666090175543733313599888473230020267536267560168443530120397567559212060988777001875141401939586720334705305599527225657558531710039260966722747077329579035916023580488134685249195364073768587522245963657969409482612377689329215793636904499387493478394264950062032110440994873062374
RSA is secure and all but the only thing I want to say is zh3r0{Hey_y0u_Sh0u1dn't_S3nd_r3l4ted_m3ssag3s_0r_h4v3_shot_p4ddings_wh3n_e_1s_sm411!!!!!}.
zh3r0{Hey_y0u_Sh0u1dn't_S3nd_r3l4ted_m3ssag3s_0r_h4v3_shot_p4ddings_wh3n_e_1s_sm411!!!!!}

Analyse me (Crypto)

サーバの処理概要は以下の通り。

・msgの長さは80
・4バイトごとに以下を繰り返し、順に行う。
 ・base64
 ・base32
 ・base85
 ・hexlify
 →結果を数値化して、|区切りで表示

このことからmsgを求めることが可能。msgを正しく入力できたら、次のステージに進める。

・keyを表示
 →final_keyに設定
・list_flag: flagを4バイトごとに16進数表記した配列
・rand_num = 2~4ランダム整数
・flagの各文字について以下の処理を行う。
 ・chr = <flagの4バイト16進数表記(8バイト)>
 ・rand_num回実行
  ・chr=table[chr[0]][chr[1]]+table[chr[2]][chr[3]]+table[chr[4]][chr[5]]+table[chr[6]][chr[7]]
  ・final_listに追加
・key_list: final_keyを4バイトごとに16進数表記した配列
・xor_list: final_listとkey_listをXORしたデータを表示
・フラグを入力したら、正しいかどうかをチェックできる。

key_listとkey_listをxorしたら、final_listになる。あとはテーブルの参照の仕方から元に戻して、先頭がフラグの先頭4バイトの16進数表記と同じになるまで戻す。

#!/usr/bin/env python3
import socket
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
from binascii import *
from base64 import *
import string

table = {'0':{'0':'63','1':'7c','2':'77','3':'7b','4':'f2','5':'6b','6':'6f','7':'c5','8':'30','9':'01','a':'67','b':'2b','c':'fe','d':'d7','e':'ab','f':'76'},
       '1':{'0':'ca','1':'82','2':'c9','3':'7d','4':'fa','5':'59','6':'47','7':'f0','8':'ad','9':'d4','a':'a2','b':'af','c':'9c','d':'a4','e':'72','f':'c0'},
       '2':{'0':'b7','1':'fd','2':'93','3':'26','4':'36','5':'3f','6':'f7','7':'cc','8':'34','9':'a5','a':'e5','b':'f1','c':'71','d':'d8','e':'31','f':'15'},
       '3':{'0':'04','1':'c7','2':'23','3':'c3','4':'18','5':'96','6':'05','7':'9a','8':'07','9':'12','a':'80','b':'e2','c':'eb','d':'27','e':'b2','f':'75'},
       '4':{'0':'09','1':'83','2':'2c','3':'1a','4':'1b','5':'6e','6':'5a','7':'a0','8':'52','9':'3b','a':'d6','b':'b3','c':'29','d':'e3','e':'2f','f':'84'},
       '5':{'0':'53','1':'d1','2':'00','3':'ed','4':'20','5':'fc','6':'b1','7':'5b','8':'6a','9':'cb','a':'be','b':'39','c':'4a','d':'4c','e':'58','f':'cf'},
       '6':{'0':'d0','1':'ef','2':'aa','3':'fb','4':'43','5':'4d','6':'33','7':'85','8':'45','9':'f9','a':'02','b':'7f','c':'50','d':'3c','e':'9f','f':'a8'},
       '7':{'0':'51','1':'a3','2':'40','3':'8f','4':'92','5':'9d','6':'38','7':'f5','8':'bc','9':'b6','a':'da','b':'21','c':'10','d':'ff','e':'f3','f':'d2'},
       '8':{'0':'cd','1':'0c','2':'13','3':'ec','4':'5f','5':'97','6':'44','7':'17','8':'c4','9':'a7','a':'7e','b':'3d','c':'64','d':'5d','e':'19','f':'73'},
       '9':{'0':'60','1':'81','2':'4f','3':'dc','4':'22','5':'2a','6':'90','7':'88','8':'46','9':'ee','a':'b8','b':'14','c':'de','d':'5e','e':'0b','f':'db'},
       'a':{'0':'e0','1':'32','2':'3a','3':'0a','4':'49','5':'06','6':'24','7':'5c','8':'c2','9':'d3','a':'ac','b':'62','c':'91','d':'95','e':'e4','f':'79'},
       'b':{'0':'e7','1':'c8','2':'37','3':'6d','4':'8d','5':'d5','6':'4e','7':'a9','8':'6c','9':'56','a':'f4','b':'ea','c':'65','d':'7a','e':'ae','f':'08'},
       'c':{'0':'ba','1':'78','2':'25','3':'2e','4':'1c','5':'a6','6':'b4','7':'c6','8':'e8','9':'dd','a':'74','b':'1f','c':'4b','d':'bd','e':'8b','f':'8a'},
       'd':{'0':'70','1':'3e','2':'b5','3':'66','4':'48','5':'03','6':'f6','7':'0e','8':'61','9':'35','a':'57','b':'b9','c':'86','d':'c1','e':'1d','f':'9e'},
       'e':{'0':'e1','1':'f8','2':'98','3':'11','4':'69','5':'d9','6':'8e','7':'94','8':'9b','9':'1e','a':'87','b':'e9','c':'ce','d':'55','e':'28','f':'df'},
       'f':{'0':'8c','1':'a1','2':'89','3':'0d','4':'bf','5':'36','6':'42','7':'68','8':'41','9':'99','a':'2d','b':'0f','c':'b0','d':'54','e':'bb','f':'16'}}

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

def decode(msg, count):
    count = (count % 4) + 1
    if count == 1:
        return b64decode(msg)
    elif count == 2:
        return b32decode(msg)
    elif count == 3:
        return b85decode(msg)
    else:
        return unhexlify(msg)

def search(s):
    for a in string.hexdigits[:16]:
        for b in string.hexdigits[:16]:
            if table[a][b] == s:
                return a + b
    return ''

def rev_rand(lst):
    rev = []
    for e in lst:
        d = b''
        for i in range(0, len(e), 2):
            d += search(e[i:i+2].decode()).encode()
        rev.append(d)
    return rev

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.zh3r0.ml', 3871))

data = recvuntil(s, b'message:')

codes = data.split('\n')[-2].split('|')[:-1]
msg = b''
for i in range(len(codes)):
    b = long_to_bytes(int(codes[i]))
    msg += decode(b, i)

print(data + msg.decode())
s.sendall(msg + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)
key = long_to_bytes(int(data.split(' ')[-1]))

data = recvuntil(s, b'DECODING!!! \n').rstrip()
print(data)

data = recvuntil(s, b'flag:')

key_list = [hexlify(key[i:i+4]) for i in range(0, len(key), 4)]
xor_list = eval(data.split('\n')[-2])
final_list = [strxor(i, j) for i, j in zip(xor_list, key_list)]

for i in range(5):
    final_list = rev_rand(final_list)
    if final_list[0] == b'7a683372':
        break

flag = unhexlify(b''.join(final_list))
print(data + flag.decode())
s.sendall(flag + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

Hello!
Welcome to Xor analysis..
There are two parts.
All the best ;)

Here is the first part:


5943134639005711677|5491378081737038141|366970695973|3833466206172886320|5640277313745009981|5351739078059639101|302416945480|3762814891798442803|6354696933901548861|5139258452082510141|305635213400|3688506584576963897|5568232986773634365|5139251786226882877|357308525154|3847819437120304993|7008813202989464893|5786655223480211773|306693940071|3689633605503693413|
Enter the decoded message:G00D_TH3_FIRST_P4RT_I5_D0N3_HER3_I5_4_F14G_F0R_Y0U_H4RD_W0RK_=_zh3r0{f4k3_f14g}.
You have done well.
Here is the key:  140262390255733908276964893730429404145946321017929888946337794323005965712203877415028

You completed the first part
 Here is the second and final part ;)
GOOD LUCK DECODING!!!

[b'\x01Z\nU\x05R\x06R', b'\x0b\t\x00RV\x04\x0e\x01', b'\x06\x0b\x00W\n\x06\x05W', b'\x07\x07\x01\\\x0e\x07\x04P', b'T\x01\x06W\x03\x04\x05R', b'\x04QS\x06\x0b\n\r_', b'W\x0b\x04P\x0cST\r', b'\nUS\x01\x01U\r\x00', b'\x05T\x03\x02\x05\x08\x03\x03']
Enter the flag:zh3r0{Y0u_4r3_4_v3ry_G00d_4nalys3r!}
Perfect you got the flag ;)
Go submit it!!!
zh3r0{Y0u_4r3_4_v3ry_G00d_4nalys3r!}

Uncipher Me (Crypto)

key.txtの内容をbase64デコードする。

N: GI3DONZWGQZDGMRVGEYDKOBVHE2DMMJYG4ZDANBTGA4TIMBRGEYTGMBZGM4TSMBYGI2TMMBQGU4DINJXGQ2TKNBQGA3TKNZSG43DMOBTHE2DIOJYG43DQMZWHE4TMMZZGQYTSMBTHEZDANJXHE4DMMJWGMYTENJSG44TCMZUHE4DINJQGQYTMNRWGM4TAMRXGM4TQNRUGIYTCMRZGI2DINBXGA3TSMRVGI4DCNZYG44DANZUGYYDMMBTGQ3DAOBXG4ZDGNJVHEYDSNBRHA2TKMJWGY4TOOJUGQ3TKOBTG44TOOBVGI4DOMJQGUZTMNBUGE4DONRZGAYTSOBTG44DAMZTGEZTCOJUGQ3DINZSGQZDONRTGY3DKOJTGEZDGOBVGE3TEOJSHA4TMNRVGMYDSMRWGA2DONJUG44TOMBXGEYDGMRXGUZTMOJVG4YDQNJVHA4DMNRRGMZTQNRWGI3DONZSGA3DCOJRGM3DANRTGY2TSMJUHA4DONZRGI3DKNZRGY2DCOJYGE3DSNZQGIYDQNZRGQZDMMBTHAZDANBXHE4TCMJZGA3TAMRTHEZTAMBVGAZDCNZUGY2TIMZSG4YTQMZWGE4DQOJXGAZTSOBSGY4TAOBTGM2TGNBZGI2DEMBRG44TGMZRHE3DKNZVGQ4DMNJZGI2DQNBXHA3DCNBZGA4DEMZTGYYTENBYGE4TEMRQGM4DOMBVGYYTKMJRGMZTEOBRGI2TQOBXGU2TKNBYGIYDMNBSGAYDGMJXHAZTEMRSGE3TQOBSGE4DMNJYGA2TOMJTGEZTENRYGM4DMMJQGI4DIMJYG4YTOOJUHE4DOOBQGIZTMMJWGM2TEOBXGI2TOOJSGM3TQOJRG4ZTIMRSGIYTOOJRGQYTINJYG43TGOBRGYZTGOBSHA3DQNZYGQZTSNBZGY3DAMZSGU3TGNBRGQZTCOBTGQ3TMMZUGQ2DGMZSGAYDAOJRGI2DSMJSGU3DINZTHEZQ====
 e: GY2TKMZX
 ct:  GB7kTHaRdkH#IRfHZ?RjH8(afGc-0eG&eLbI5IRiHaIplG&VOmGcz+eFf=(ZF)=hYH8D9dH83?ZH#9gnI59LaIW{seGc-9iGBP(YGB7YWIWaafIWspgHa0jnG%z_gIXE~mH90gjIW#yoIXE;iGdDRkI5jspH#jvjIWaRcGc_<ZGdVahH8?jmGB!0bH!?FfG&eUmF*!CdH#9UjHZ?FeFflhaFfceWGcz<bI5RggH!?OfHZwIgI5aXaH83_eG&4ClH#RXfH#IdiFgP?YH#askGBGzaFgQ3fI5{~oF*P<bF*PtTHZe9gI5apkIW#pnHZU|ZIXO5mHaImhHZd_XGBPtUFflYVIW#yqF*i9eH83+XH#apfGc`6gFg7qbHa9piHZ?LgGdVdjGBh+dHZe3gH90dkF*r6iIWaLgIW{&mIWaRbI5s&rI5RdkIWaLgHaIdcGBP(YG&nRjH#IgiGBP$dGc`FjG&nRfGB`3YI5;;lHZnFfG%++VF)}bSH#9UjFgZ9fGB+|XG&DIhGcq+fHa9RhFgP$XIXN;gGBP(bF)%VVFf}wdFf%bVH#9RgH#9aiHaIjeI5jykGc-3jG%+?XH!?IhG%_?YF*!6cF)}eWI59XhIXE#iI5jgfF*!3hH!v_WGB7zZI503WF)=nYHZ(FbHZd|VIW;gfFf}tcFgGwVF*P(bHa9pmGdM6cI5IgfGBh<ZGdVIfF*P(cH#s&mGB+|aF*h|bHZU+ZF*!6eGdVLkIX5{tGdMXnHZ(LhH#IOdI503XFf=hUG5

N, eはbase32、ctはbase85でデコードできる。NはFermat法で素因数分解できたので、そのまま復号する。

#!/usr/bin/env python3
import base64
from Crypto.Util.number import *

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n):
    x = isqrt(n) + 1
    y = isqrt(x * x - n)
    while True:
        w = x * x - n - y * y
        if w == 0:
            break
        elif w > 0:
            y += 1
        else:
            x += 1
    return x - y, x + y

with open('key.txt', 'r') as f:
    key = f.read()

param = base64.b64decode(key).decode()
N = int(base64.b32decode(param.split('\n')[0].split(' ')[1]).decode())
e = int(base64.b32decode(param.split('\n')[1].split(' ')[2]).decode())
ct = int(base64.b85decode(param.split('\n')[2].split(' ')[3]).decode())

p, q = fermat(N)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(ct, d, N)
pt = long_to_bytes(m).decode()
print(pt)

この実行結果は以下の通り。

key: kD87Ef4y043nhee-W_Hytc0d3Bkiw4Gw21m-7AHpZkc=
This is one of the keys for the encryption.Totally 3 keys to decrypt the encrypted text

次にkey_2.txtの内容をrot47で復号する。

key: iQZijGdoX0hepv2wnFZOUsTWU-v6xyGWyqSan_p75CE=
Here's another key for the encryption.
if you are a good cryptographer you can identify the common symmetric encryption.

さらにkey_3.txtの内容をVigenere暗号と推測して、https://www.guballa.de/vigenere-solverで復号する。

key: XeQVPB98P3fve4lJvfk345uARbNDE4F17NFZJBHC1dY= 
The last key and you can go decrypte the cipher,
 if you couldn't identify then see the starting part of the ciphertext, 
if the decryptions with the keys doesn't work then try rearranging the keys.

ct.txtの内容からFernat暗号であると推測でき、3つの各キーで復号を試す。
この結果key2を使って、Fernat暗号として復号することができた。

from cryptography.fernet import Fernet

token = 'gAAAAABe5zDHy1Vk74P8AspzQ4bqK9dzfI52djZeMbsXRk8G5ng1BtYmDj7v6SCbx7cvnUFu2fDh6XTVtQPQqlJcVVCxGoA0P4L_gtSIGHQPLZysxuoN1E7kP_5lZFbZLo6b6G-YqFxs'
key = 'iQZijGdoX0hepv2wnFZOUsTWU-v6xyGWyqSan_p75CE='

f = Fernet(key)
flag = f.decrypt(token)
print flag
zh3r0{Symm3tric_3ncrypti0n_i5_5tr0ng}