この大会は2017/6/17 9:00(JST)~2017/6/19 9:00(JST)に開催されました。
今回もチームで参戦。結果は1002点で1977チーム中47位でした。
自分が得点した問題は1問も無く、本当に残念!
SHA2017 CTF Teaser round Writeup
この大会は2017/6/10 21:00(JST)~2017/6/11 5:00(JST)に開催されました。
今回もチームで参戦。結果は650点で462チーム中7位でした。
自分で解けた問題をWriteupとして書いておきます。
Crypto Engine (Crypto 200)
いろいろ試して出力される色のRGBの組を確認する。まずは以下の点がわかる。
・3文字で一つのセルが生成される。 ・3の倍数の文字でない場合は、3で割った余りの文字数分8ビットの16進数が表記されている。
このことからフラグの文字数は38文字であることがわかる。XORで算出された結果を色で表していると推測しながら、38文字でいろいろ試す。
■abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLの場合 RGB: 83 82 82 83 54 52 53 59 95 94 94 87 50 48 49 39 67 66 66 83 54 52 53 43 79 78 116 105 12 10 49 47 75 66 120 101 | 0x00 0x0e 文字列とRGBのXOR: [50, 48, 49, 55, 83, 82, 82, 83, 54, 52, 53, 59, 95, 94, 94, 87, 50, 48, 49, 39, 67, 66, 66, 83, 54, 52, 53, 43, 79, 78, 116, 105, 12, 10, 49, 47, 75, 66] ■ZUHadnaopwefvnsudhaaiTjaksUkladauULandの場合 RGB: 104 101 121 86 12 11 24 57 124 124 125 95 10 18 14 42 110 122 111 75 7 46 5 42 108 93 80 65 0 60 52 32 117 105 120 65 | 0x1b 0x0d 文字列とRGBのXOR: [50, 48, 49, 55, 104, 101, 121, 86, 12, 11, 24, 57, 124, 124, 125, 95, 10, 18, 14, 42, 110, 122, 111, 75, 7, 46, 5, 42, 108, 93, 80, 65, 0, 60, 52, 32, 117, 105] ■YZabcdefghijklMNOPqrstuVWxyzhaAjadsKKKの場合 RGB: 107 106 80 85 8 14 53 51 111 102 92 89 4 10 17 23 75 90 96 101 56 46 21 51 111 86 108 73 7 55 45 35 102 83 94 104 | 0x2d 0x18 文字列とRGBのXOR: [50, 48, 49, 55, 107, 106, 80, 85, 8, 14, 53, 51, 111, 102, 92, 89, 4, 10, 17, 23, 75, 90, 96, 101, 56, 46, 21, 51, 111, 86, 108, 73, 7, 55, 45, 35, 102, 83] ■ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklの場合 RGB: 115 114 114 115 54 52 53 59 127 126 126 119 50 48 49 39 99 98 98 115 54 52 53 43 111 110 84 73 12 10 49 47 107 98 88 69 | 0x00 0x0e 文字列とRGBのXOR: [50, 48, 49, 55, 115, 114, 114, 115, 54, 52, 53, 59, 127, 126, 126, 119, 50, 48, 49, 39, 99, 98, 98, 115, 54, 52, 53, 43, 111, 110, 84, 73, 12, 10, 49, 47, 107, 98]
以上を見ていて以下のことに気が付いた。
・XORキーの最初の4バイトは固定:50, 48, 49, 55 ・XORキーの5バイト以降はRGBの値を順に並べている。
このことから復号コードを書く。
from PIL import Image img = Image.open('flag.png').convert('RGB') w, h = img.size key = [50, 48, 49, 55] enc = [] for x in range(1, w, 40): r, g, b = img.getpixel((x, 1)) key.append(r) key.append(g) key.append(b) enc.append(r) enc.append(g) enc.append(b) del key[-2:] enc.append(0x2e) enc.append(0x29) flag = '' for i in range(len(enc)): flag += chr(key[i] ^ enc[i]) print flag
この結果フラグがゲットできた。
flag{deaf983eb34e485ce9d2aff0ae44f852}
Security Fest 2017 Writeup
この大会は2017/5/31 21:00(JST)~2017/6/2 1:00(JST)に開催されました。
今回もチームで参戦。結果は1460点で447チーム中14位でした。
自分で解けた問題をWriteupとして書いておきます。
#makeircgreatagain (Misc 10)
freenodeで#securityfest-ctfチャネルに入る。
21:01 *topic : DL server problems, WORKING ON IT! https://securityfest.ctf.rocks - SCTF{Welcome_to_SECURITYFEST_CTF_2017!} - start: https://goo.gl/L9Ltwj
SCTF{Welcome_to_SECURITYFEST_CTF_2017!}
Empty (Misc 100)
何も書かれていない空のPDFファイルが与えられている。
$ strings empty.pdf : /LastChar 25 /Widths[/Widths[83 67 84 70 123 115 116 114 52 110 103 51 95 111 98 106 51 99 116 95 99 104 114 95 49 110 95 112 108 52 49 110 95 115 49 116 51 125] /FontDescriptor 12 0 R :
Widthsの値がASCIIコードの羅列に見える。文字に置き換えてみる。
codes_str = '83 67 84 70 123 115 116 114 52 110 103 51 95 111 98 106 51 99 116 95 99 104 114 95 49 110 95 112 108 52 49 110 95 115 49 116 51 125' codes = codes_str.split(' ') flag = '' for code in codes: flag += chr(int(code)) print flag
フラグの文字列だった。
SCTF{str4ng3_obj3ct_chr_1n_pl41n_s1t3}
Qr code madness (Misc 200)
QRコードの画像が複数ある。1つの画像で1文字を読め、なんとなくBase64の文字種別になっていることがわかる。
あとはどの順番で読むかを考える。更新日付順で最後に読めたのが「=」になっていることがわかったので、その順で並び替えればよそさう。
まずはタイムスタンプをファイル名にして、QRコードをテキストにする。
import os import time import datetime from PIL import Image BLACK = 'X' WHITE = ' ' UNKNOWN = '?' quiet_zone_size = 12 cell_size = 3 QR_DIR = 'qrcodemadness\\' TXT_DIR = 'qrtext\\' files = os.listdir(QR_DIR) for file in files: img = Image.open(QR_DIR + file) width, height = img.size pixels = img.load() output = "" y = quiet_zone_size + 1 qrtxt = '' while y < height - quiet_zone_size: x = quiet_zone_size + 1 while x < width - quiet_zone_size: if pixels[x, y] == 0: qrtxt += BLACK else: qrtxt += WHITE x += cell_size qrtxt += '\n' y += cell_size utime = datetime.datetime.fromtimestamp(os.stat(QR_DIR + file).st_mtime) o_filename = TXT_DIR + str(int(time.mktime(utime.timetuple()))) + '.txt' with open(o_filename, 'w') as f: f.write(qrtxt)
次にQRコードを読み取り、最初の1文字を除いて、Base64デコードする。
import os import subprocess TXT_DIR = 'qrtext\\' CMD_FORMAT = 'python sqrd.py qrtext\\%s' files = os.listdir(TXT_DIR) b64str = '' for file in files: cmd = CMD_FORMAT % file ret = subprocess.check_output( cmd.split(" ") ) ret = ret.replace('\r\n', '') ret = ret.replace('\r', '') ret = ret.replace('\n', '') b64str += ret print b64str[1:].decode('base64')
SCTF{Th3s3_d4mn_QR_c0d3_k33p_p0p1ng_up}
I heart cats (Misc 50)
空白やタブが目立つHTMLが与えられている。
空白8バイトを0、タブを1として、2進数のコードにして読込む。
with open('index.html', 'r') as f: data = f.read() data = data.replace(' ', ' ') bin_code = '' for i in range(len(data)): if data[i] == ' ': bin_code += '0' elif data[i] == '\t': bin_code += '1' flag = '' for i in range(0, len(bin_code), 8): flag += chr(int(bin_code[i:i+8], 2)) print flag
SCTF{Wh1735p4c35_4r3_84d_4u!}
Fair play! (Crypto 50)
問題のタイトルからもPlayfair暗号と推測。オンラインのツールなどで復号してみたが、うまくいかない。CryptoCrackを使って、ブルートフォースで復号する。
この結果、キーはCOKBVQARNDXYEPWSHMZILFTGU。復号結果は以下の通り。
THEFLAGISTHENEXTFORTYONECHARACTERSPLAYFAIRISAFUNCIPHERTOCRACKDONTYOUTHINKSOIHOPEYOUENIOYEDTHECHALXLENGESPORTSMANSHIPISANASPIRATIONORETHOSTHATASPORTORACTIVITYWILLBEXENIOYEDFORITSOWNSAKEWITHPROPERCONSIDERATIONFORFAIRNESXSETHICSRESPECTANDASENSEOFXFELXLOWSHIPWITHONESCOMPETITORSASORELOSERREFERSTOONEWHODOESNOTXTAKEDEFEATWELXLWHEREASAGOXODSPORTMEANSBEINGAGOODWINXNERASWELLASBEINGAGOXODLOSERSOMEONEWHOSHOWSCOURTESYTOWARDSANOTHERINASPORTSGAMESPORTSMANSHIPCANBECONCEPTUALIZEDASANENDURINGANDRELATIVELYSTABLECHARACTERISTICORDISPOSITIONSUCHTHATINDIVIDUALSDIFXFERINTHEWAYTHEYAREGENERALXLYEXPECTEDTOBEHAVEINSPORTSITUATIONSINGENERALSPORTSMANSHIPREFERSTOVIRTUESSUCHASFAIRNESXSXSELFCONTROLCOURAGEANDPERSISTENCEANDHASBEENASSOCIATEDWITHINTERPERSONALCONCEPTSOFTREATINGOTHERSANDBEINGTREATEDFAIRLYMAINTAININGSELFCONTROLIFDEALINGWITHOTHERSANDRESPECTFORBOTHAUTHORITYANDOPPONENTSXSPORTSMANSHIPISALSOLOXOKEDATASBEINGTHEWAYONEREACTSTOASPORTGAMEPLAYERTHEFOURELEMENTSOFSPORTSMANSHIPAREOFTENSHOWNBEINGGOODFORMTHEWILLTOWINEQUITYANDFAIRNESSALXLFOURELEMENTSARECRITICALANDABALANCEMUSTBEFOUNDAMONGALXLFOURFORTRUESPORTSMANSHIPTOBEILXLUSTRATEDTHESEELEMENTSMAYALSOCAUSECONFLICTASAPERSONMAYDESIRETOWINMORETHANPLAYINEQUITYANDFAIRNESXSANDTHUSRESULTINGINACLASHWITHINTHEASPECTSOFSPORTSMANSHIPTHISWILXLCAUSEPROBLEMSASTHEPERSONBELIEVESTHEYAREBEINGAGOODSPORTSMANBUTTHEYAREDEFEATINGTHEPURPOSEOFTHISIDEAASTHEYAREIGNORINGTWOKEYCOMPONENTSOFBEINGSPORTSMANLIKEWHENATHLETESBECOMETOXOSELFCENTREDTHEIDEAOFSPORTSMANSHIPISDISMISSEDTODAYSXSPORTINGCULTUREINPARTICULARTHEBASEOFELITESPORTPLACESGREATIMPORTANCEONTHEIDEAOFCOMPETITIONANDWINXNINGANDTHUSXSPORTSMANSHIPTAKESABACKSEATASARESULTINMOSTIFNOTALXLSPORTSXSPORTSMENATXTHEXELITELEVELMAKETHESTANDARDSONSPORTSMANSHIPANDNOMATXTERWHETHERTHEYLIKEITORNOTXTHEYARESEXENASLEADERSANDROLEMODELSINSOCIETYSINCEEVERYSPORTISRULEDRIVENTHEMOSTCOMMONOFXFENCEOFBADSPORTSMANSHIPISTHEACTOFCHEATINGORBREAKINGTHERULESTOGAINANUNFAIRADVANTAGEACOMPETITORWHOEXHIBITSPOORSPORTSMANSHIPAFTERLOSINGAGAMEORCONTESTISOFTENCALLEDASORELOSERTHOSEWHOSHOWPOXORSPORTSMANSHIPAFTERWINXNINGARETYPICALLYCALXLEDBADCHAMPSSORELOSERBEHAVIOURINCLUDESBLAMINGOTHERSFORTHELOSSNOTACCEPTINGRESPONSIBILITYFORPERSONALACTIONSTHATCONTRIBUTEDTOTHEDEFEATREACTINGTOTHELOSXSINANIMXMATUREORIMPROPERFASHIONMAKINGEXCUSESFORTHEDEFEATANDCITINGUNFAVOURABLECONDITIONSOROTHERPETXTYISSUESASREASONSFORTHEDEFEATABADWINNERACTSINASHALLOWFASHIONAFTERHISORHERVICTORYSUCHASBYGLOATINGABOUTHISORHERWINRUBXBINGTHEWININTHEFACESOFTHEOPXPONENTSANDLOWERINGTHEOPXPONENTSXSXSELFESTEEMBYCONSTANTLYREMINDINGTHEOPPONENTSOFPOXORPERFORMANCEINCOMPARISONEVENIFTHEOPPONENTSCOMPETEDWELLNOTSHOWINGRESPECTTOTHEOTHERTEAMISCONSIDEREDTOBEINGABADSPORTSMANANDCOULDLEADTODEMORALISINGEFFECTSASLESLIEHOWEDESCRIBESIFAPITCHERINBASEBALXLDECIDESTOPITCHNOTTOHISMAXIMUMABILITYSUGGESTTHATTHEBATTERISNOTATANADEQUATELEVELANDCOULDLEADTOTHEBATXTERTOHAVELOWSELFCONFIDENCEORWORTHTHEREARESIXDIFXFERENTCATEGORIESRELATINGTOSPORTSMANSHIPTHEELEMENTSOFSPORTSTHEXELEMENTSOFSPORTSMANSHIPCLARIFICATIONSCONFLICTSBALANCEANDIRREDUCIBILITYALLSIXOFTHESECHARACTERIZEAPERSONWITHGOODSPORTSMANSHIPEVENTHOUGHTHEREISSOMEAFFINITYBETWEXENSOMEOFTHECATEGORIESTHEYAREDISTINCTELEMENTSINESSENCEPLAYHASFORITSDIRECTEDANDIMXMEDIATEXENDIOYPLEASUREANDXDELIGHTSANDWHICHISDOMINATEDBYASPIRITOFMODERATIONANDGENEROSITYATHLETICSONTHEOTHERHANDISESSENTIALXLYACOMPETITIVEACTIVITYWHICHXHASFORITSENDVICTORYINTHECONTESTANDWHICHISCHARACTERIZEDOFDEDICATIONSACRIFICEANDINTENSITYFEXELEZZPPHENCETHEVIRTUESOFAPLAYERARERADICALXLYDIFXFERENTFROMTHEVIRTUESOFANATHLETEFEXELEZZPPWHENTALKINGABOUTMISUNDERSTANDINGSPORTSMANSHIPRUDXDANDSTOLLPROVIDEANEXAMPLEFROMAUSHIGHSCHOOLATHLETICLEAGUEBANXNEDTHEPOSTGAMEHANDSHAKETHATWASAPARTOFSPORTSXSUCHASFOOTBALXLANDBASKETBALXLTHEHANDSHAKINGWASBANXNEDBECAUSEOFFIGHTSTHATWEREENSUINGAFTERTHEHANDSHAKEPXPMOSTPLAYERSAREINFLUENCEDBYTHELEADERSAROUNDTHEMSUCHASCOACHESANDOLDERPLAYERSIFTHEREARECOACHESANDADMINISTRATORSWHODONTUNDERSTANDSPORTSMANSHIPTHENWHATABOUTTHEPLAYERS
スペースを入れて読みやすくすると、先頭部分にはこう書いてある。
THE FLAG IS THE NEXT FORTYONE CHARACTERS
次の41文字がフラグ。
PLAYFAIRISAFUNCIPHERTOCRACKDONTYOUTHINKSO
WhiteHat Contest 13 Writeup
この大会は2017/5/27 11:00(JST)~2017/5/28 11:00(JST)に開催されました。
今回もチームで参戦。結果は1800点で108チーム中8位でした。
自分で解けた問題をWriteupとして書いておきます。
Da Nang (Cryptography 200)
makefile.pycファイルとn, c1~c4の値が与えられている。
EasyPythonDecompilerでmakefile.pycをデコンパイルすると、以下のようなコードで暗号化していることがわかる。
# Embedded file name: /root/Desktop/ctf-2017/rade/makefile.py from FLAG import * from Crypto.Util.number import * p = getPrime(1024) q = getPrime(1024) n = p * q e1 = 17 e2 = 23 m1 = pow(flag, e1, n) m2 = pow(flag, e2, n) c1 = pow(m1 + 12345, e1, n) c2 = pow(m1 + 56789, e1, n) c3 = pow(m2 + 12345, e2, n) c4 = pow(m2 + 56789, e2, n)
まず、Franklin-Reiter Related Message Attackでm1とm2を求める。
# related_message_attack.sage 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] n = 23992456508721632904544057999056395984840598682551527471151904763246778638836805311058576074076544471814362118450963752614808101805018226501728749753154687251596663180454809994272928278066817153483685668132338944992849111855590973474678454159123639456555256485147196164078477717189520027988101925788303558976065942012105491523422884349644306896086216721825961334666043695121350988761613913914655313225263251356627080558127266206207253980892813908459449433940028268804981985006285644508736389967109173883994849116220035021283230523958640143355551140077459561176550844398278642511471910168765368624465988996082307992457 c1 = 20373828497176435167633953604896280749084861536083536617122139289929021045377176745113967394233342868062933415554192920963948057887324013008257380015103546511196207444982065505097904316167335975881412955740451727799394577357107415462104942067847048630173382510001061068806873459709567970640047451719077689284250663779574472232440594570502056709748603086893912068708152949459839465110567129133452824619222918019880393381073202052633467737917229789195417254877277542398992729106705037414050409175283815504552780234997208287185820010853470529752628470226853313501197054312938111140137899570545855875031148908922559079288 c2 = 4360293477491071631082413589399984151934700148049881396354060511784164719699104502640364063839372357371432182276578283932647249629707984639755245731994004982047010862474568253438883825981211552726455647610616600152683140602219777227764342827766552684058977170125324805316413550680703753463380261978903747369677517090549750490497714726106808405188795507741435252228742048791254891796083781713724953974101730953449734214103419451007355326070889428042830527374106171411884042865409718813225704924308910578917985370161732700040769553579304781551439507813917217693054553136139858632877393572913681604198562756394542739717 c3 = 4345261358659519189634881349240932351623603440440060460588285817392306152201826610576491755629698765088135761317793967803519010356869269204503397215039512744495117601932620637450095192646479479541571697381615227131485964855439316795397514445542660502760126364064850197352955455820341422106740318181122113707487426652989875585231637716536188004952356846847687782788196021954904944243050038759261831381697585862182084930662578928342538660648403902072793943235882313263403348511364765676275877687747514403142706712995406077875195587485333137738286810493929324782535392363155178660765334428891921464976278013274433592459 c4 = 11163192691864487842504791707572292045010440994593022973064948393324184598662086767886111478358067883324039072186651857397731078118781186686459647088206129240315423019956385054334592265029781917246602461962626683725203283354094411740566113019140776580459728655850754495232498348144806199874330892136766891492831287879346899778473534258469040357585649045269842028785546606058644151580331160754603828262995696611984149905299109630697269974668616156412842759609194334129212734919638779629261074770920807952993453659743525451175541328430753432209789806184520128139906770561431423993324872179142853918272022140840732281811 e1 = 17 e2 = 23 diff = 56789 - 12345 m1 = related_message_attack(c1, c2, diff, e1, n) - 12345 print 'm1 =', m1 m2 = related_message_attack(c3, c4, diff, e2, n) - 12345 print 'm2 =', m2
以下の通り、m1とm2を算出することができた。
m1 = 19940708887759698510138918424450978321561069230659682994645881255326771243148984534641521276833375122703596885707253454427683279897828170878752612038114916127076079372073980486084679133895997151796999085785875836411210710632349923692939803228793799180641695640367708674225359974103741571982122048082035653192117956305119783207139142492158377892592169456609523577779421428356103367766774789680587969032302667151786683889761811812272622064633882550675704607685899902862193827181388950179113885788804816791465827265522578945146174815051717419478773041589332193216487854230882177980058898250512045181287339603392316697829 m2 = 2970132540488149339645289732236094260249062136537890152544022014880742014613667308336012839589875906076626365709335806489861391924524036985675821291443068706330596605582227620510725657401246096937011593605357908632053035718719770934145713092502591072370696481368118792860212738265793148704385419081990887592837829524490105986239282282260211257709359015566779069639346641105169115995195678357307965665965863966691547051261296196880300064216255207531200236387931460445195365540532178913046683294419159294042199243485508880751463979557947263693533936834072139357019316229736030987782295309538167642041408183532003721823
次にCommon Modules Attackでflagを求める。
import gmpy def commom_modules_attack(c1, c2, e1, e2, n): gcd, s1, s2 = gmpy.gcdext(e1, e2) if s1 < 0: s1 = -s1 c1 = gmpy.invert(c1, n) elif s2 < 0: s2 = -s2 c2 = gmpy.invert(c2, n) v = pow(c1, s1, n) w = pow(c2, s2, n) x = (v*w) % n return x n = 23992456508721632904544057999056395984840598682551527471151904763246778638836805311058576074076544471814362118450963752614808101805018226501728749753154687251596663180454809994272928278066817153483685668132338944992849111855590973474678454159123639456555256485147196164078477717189520027988101925788303558976065942012105491523422884349644306896086216721825961334666043695121350988761613913914655313225263251356627080558127266206207253980892813908459449433940028268804981985006285644508736389967109173883994849116220035021283230523958640143355551140077459561176550844398278642511471910168765368624465988996082307992457 e1 = 17 e2 = 23 m1 = 19940708887759698510138918424450978321561069230659682994645881255326771243148984534641521276833375122703596885707253454427683279897828170878752612038114916127076079372073980486084679133895997151796999085785875836411210710632349923692939803228793799180641695640367708674225359974103741571982122048082035653192117956305119783207139142492158377892592169456609523577779421428356103367766774789680587969032302667151786683889761811812272622064633882550675704607685899902862193827181388950179113885788804816791465827265522578945146174815051717419478773041589332193216487854230882177980058898250512045181287339603392316697829 m2 = 2970132540488149339645289732236094260249062136537890152544022014880742014613667308336012839589875906076626365709335806489861391924524036985675821291443068706330596605582227620510725657401246096937011593605357908632053035718719770934145713092502591072370696481368118792860212738265793148704385419081990887592837829524490105986239282282260211257709359015566779069639346641105169115995195678357307965665965863966691547051261296196880300064216255207531200236387931460445195365540532178913046683294419159294042199243485508880751463979557947263693533936834072139357019316229736030987782295309538167642041408183532003721823 flag = commom_modules_attack(m1, m2, e1, e2, n) flag_str = ('%x' % flag).decode('hex') print flag_str
この結果は以下の通り。
common_modulus_and_franklin_reiter_related_message
$ echo -n common_modulus_and_franklin_reiter_related_message | sha1sum 4111c011bc640806ef98a32a5caaf9d169a960a0 -
WhiteHat{4111c011bc640806ef98a32a5caaf9d169a960a0}
Ha Long bay (Cryptography 250)
以下のコードと、n, e, C1~C3の値が与えられている。
from Crypto.Util import number from secret import M, flag p = number.getPrime(512) q = number.getPrime(512) n = p * q e = 3 assert (len(flag) < 18),"Fail!" fsplit = len(flag)/3 m1 = M + chr(number.getRandomRange(32, 128)) + flag[:fsplit] m2 = M + chr(number.getRandomRange(32, 128)) + flag[fsplit:2*fsplit] m3 = M + chr(number.getRandomRange(32, 128)) + flag[2*fsplit:] m1 = int(m1.encode('hex'),16) m2 = int(m2.encode('hex'),16) m3 = int(m3.encode('hex'),16) C1 = pow(m1, e, n) C2 = pow(m2, e, n) C3 = pow(m3, e, n)
Coppersmith's Short Pad Attackで平文の差を求めながら、Franklin-Reiter Related Message Attackでm1~m3を求める。
# coppersmiths_short_pad-and-related_message_attack.sage def short_pad_attack(c1, c2, e, n): PRxy.<x,y> = PolynomialRing(Zmod(n)) PRx.<xn> = PolynomialRing(Zmod(n)) PRZZ.<xz,yz> = PolynomialRing(Zmod(n)) g1 = x^e - c1 g2 = (x+y)^e - c2 q1 = g1.change_ring(PRZZ) q2 = g2.change_ring(PRZZ) h = q2.resultant(q1) h = h.univariate_polynomial() h = h.change_ring(PRx).subs(y=xn) h = h.monic() kbits = n.nbits()//(2*e*e) diff = h.small_roots(X=2^kbits, beta=0.5)[0] # find root < 2^kbits with factor >= n^0.5 return diff 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] n = 103812409689464886276475047044770609297885893720146571798654593885477457188425375786047017735691464865799751262776976174291152757506033948402223696021505470811665108707476725788296289255777914656800454451779117367605227364391483323666809650532860469176398816220707851639905500304208833022438234033264200398959 e = 3 C1 = 9317106922634505445328279149755295612464875825943780841886193649700131610057100771444165757592479299555845021862440454968502065319770337331674061960123779876709748994547507057835826773522733671492329400557540100987018908395372213360970889608191940631081957498661950679566048064234326337242245437800870328713 C2 = 9314352234311777268152500810432217195086739647228997430466360767070638972017377674642639833356580951663634114522574738957708645348438979256455824440476178459296267056062724307782801856615506577790281367843133061096735566462588088807072141910079117362448136849082448630141871675817981866725491776400151339928 C3 = 102298788718908831383454512674839558060033746080468660252243145800572734468521296602058538109452538907204027081338987796558296639830757629468491322438048912956916198524821066676689795698612028521062296901313097979278633376983280108123961097977187251599033620058543603046291262367128490175209233898073639549204 diff = short_pad_attack(C1, C2, e, n) m1 = related_message_attack(C1, C2, diff, e, n) msg1 = ('%x' % m1).decode('hex') m2 = m1 + diff msg2 = ('%x' % m2).decode('hex') diff = short_pad_attack(C2, C3, e, n) m3 = m2 + diff msg3 = ('%x' % m3).decode('hex') print msg1 print msg2 print msg3
この結果は以下の通り。
ab688786fce01806bea4f1812740c15703837b12_part of flag is !uozt_ ab688786fce01806bea4f1812740c15703837b12_part of flag is \ficm_ ab688786fce01806bea4f1812740c15703837b12_part of flag is l41t0r
このことから以下のことがわかる。
flag = 'uozt_ficm_41t0r'
$ echo -n uozt_ficm_41t0r | sha1sum a1ac8b83a8c8495b94007c2745596206d431748f -
WhiteHat{a1ac8b83a8c8495b94007c2745596206d431748f}
RCTF 2017 Writeup
この大会は2017/5/20 9:00(JST)~2017/5/22 9:00(JST)に開催されました。
今回もチームで参戦。結果は574点で620チーム中102位でした。
自分で解けた問題をWriteupとして書いておきます。
Sign In (Misc)
freenodeで#rctf2017チャネルに入る。
09:03 *topic : RCTF{Welcome_To_RCTF_2017}
RCTF{Welcome_To_RCTF_2017}
RSA_sign1 (Crypto)
メッセージと対応するシグネチャがあっていればフラグが表示できそう。
何でもよいので、先にシグネチャを決める。それからメッセージを求め、メッセージから順に指定する。
#!/usr/bin/env python import socket import rsa with open('public.pem') as f: pub_pem = f.read() pub_key = rsa.PublicKey.load_pkcs1(pub_pem) sig = 'hogehoge' blocksize = rsa.common.byte_size(pub_key.n) encrypted = rsa.transform.bytes2int(sig) decrypted = rsa.core.decrypt_int(encrypted, pub_key.e, pub_key.n) clearsig = rsa.transform.int2bytes(decrypted, blocksize) sep_idx = clearsig.index('\x00', 2) msg = clearsig[sep_idx+1:] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('rsasign1.2017.teamrois.cn', 3000)) data = s.recv(256) print data print msg s.sendall(msg + '\n') data = s.recv(256) print data print sig.encode('hex') s.sendall(sig.encode('hex') + '\n') data = s.recv(256) print data
このコードを実行したらフラグを得られた。
RCTF{your_fir5t_sig_test}
UIUCTF 2017 Writeup
この大会は2017/4/29 9:00(JST)~2017/4/30 21:00(JST)に開催されました。
今回もチームで参戦。結果は600点で163チーム中57位でした。
自分で解けた問題をWriteupとして書いておきます。
babyrsa (crypto 200)
RSA暗号。nが大きく、eが小さいため、cのe乗根により復号する。
import gmpy e = 5 c = 199037898049081148054548566008626493558290050160287889209057083223407180156125399899465196611255722303390874101982934954388936179424024104549780651688160499201410108321518752502957346260593418668796624999582838387982430520095732090601546001755571395014548912727418182188910950322763678024849076083148030838828924108260083080562081253547377722180347372948445614953503124471116393560745613311509380885545728947236076476736881439654048388176520444109172092029548244462475513941506675855751026925250160078913809995564374674278235553349778352067191820570404315381746499936539482369231372882062307188454140330786512148310245052484671692280269741146507675933518321695623680547732771867757371698350343979932499637752314262246864787150534170586075473209768119198889190503283212208200005176410488476529948013610803040328568552414972234514746292014601094331465138374210925373263573292609023829742634966280579621843784216908520325876171463017051928049668240295956697023793952538148945070686999838223927548227156965116574566365108818752174755077045394837234760506722554542515056441166987424547451245495248956829984641868331576895415337336145024631773347254905002735757 m = gmpy.root(c, e)[0] flag = ('%x' % m).decode('hex') print flag
実行結果は次の通り。
welcome to uiuctf! your super secret flag is: flag{c4n_w3_get_s0m3b0dy_t0_sm1th_some_c0pper_pls}
flag{c4n_w3_get_s0m3b0dy_t0_sm1th_some_c0pper_pls}
WhiteHat Challenge 03 Writeup
この大会は2017/4/27 11:00(JST)~2017/4/27 19:00(JST)に開催されました。
今回は仕事の合間に個人で参戦。結果は70点で101チーム中42位でした。
自分で解けた問題をWriteupとして書いておきます。
Crypto001 (Cryptography 25)
単語ごとに反転して、11シフトする。
import string al_U = string.uppercase e = 'HJXAJY GPHTPR HPL P CPBDG APGTCTV SCP CPXRXIXADE DWL LTGWIGTKD TWI CPBDG RXAQJETG SCP STWHXAQPIHT TWI TAJG UD TWI HGDGTEBT. GPHTPR STHJ TWI HBTAQDGE SCP HEXWHSGPW UD TWI SDXGTE DI TIPTGR HXW CLD TBTGEJH APRXIXADE SCP NGPIXAXB GTLDE. VPAU HX TWI GPTN IPWI GPHPTR HPL CGDQ. CPBDG GDGTEBT HJXAJY GPHTPR HX STSGPVTG HP TCD UD TWI IHDB AJUGTLDE SCP AJUHHTRRJH HGTSPTA CX TWI NGDIHXW UD TWI SAGDL. HXW TUXA SCP HXW ICTADXK WIPTS TKPW CTTQ NATSXL STIPGQTATR CX TGJIPGTIXA SCP BAXU.' words = e.split(' ') m = '' for i in range(len(words)): if words[i][-1:] == '.': word = words[i][::-1][1:] + '.' else: word = words[i][::-1] #print word for j in range(len(word)): if word[j] in al_U: index = al_U.index(word[j]) + 11 if index > 25: index = index - 26 m += al_U[index] else: m += word[j] if i != len(words) - 1: m += ' ' print m
実行結果は次の通り。
JULIUS CAESAR WAS A ROMAN GENERAL AND POLITICIAN WHO OVERTHREW THE ROMAN REPUBLIC AND ESTABLISHED THE RULE OF THE EMPERORS. CAESAR USED THE PROBLEMS AND HARDSHIPS OF THE PERIOD TO CREATE HIS OWN SUPREME POLITICAL AND MILITARY POWER. FLAG IS THE YEAR THAT CEASAR WAS BORN. ROMAN EMPEROR JULIUS CAESAR IS REGARDED AS ONE OF THE MOST POWERFUL AND SUCCESSFUL LEADERS IN THE HISTORY OF THE WORLD. HIS LIFE AND HIS VIOLENT DEATH HAVE BEEN WIDELY CELEBRATED IN LITERATURE AND FILM.
フラグはCeaserが生まれた年なので、紀元前100年。
$ echo -n 100 | sha1sum 310b86e0b62b828562fc91c7be5380a992b2786a -
WhiteHat{310b86e0b62b828562fc91c7be5380a992b2786a}
Crypto002 (Cryptography 10)
n, p, q, e, cが与えられているので、そのままRSA暗号の復号を行う。
n = 132584825018166892036247821308754740533575984294912859418971244776769293548107490233355297115861255963076622070127865142205107181207673702587393494860613316425336008819081169031194442020498569601888048767385032364436395644961861833287918315793817245497784496450110641025476274978672298849300106831336352152221 p = 12476682960795779723419989287306239606331347310604553825605263028855086418051086300006278888049896375754096827163121306696417314531666670662341673511789487 q = 10626608485185909739187126602183513204215955466032868268570782358820047751795982373252873333276843831383542360202874683262678664975380865415068554992090483 e = 65537 c = 126028558760741438230925566962334702896791270808414391828894437291120207835997354509410869568173448979784329516392078311028442458946906210498176026685581176779209904039179175088984829699783861789249260322822491502790157863487861171337660785254139478229397872969136220001367017765809130698515063339265165085655 a = (p - 1) * (q - 1) x = 0 while True: if (a * x + 1) % e == 0: d = (a * x + 1) / e break x = x + 1 m = pow(c, d, n) flag = ('%x' % m).decode('hex') print flag
復号結果は simple_rsa_decryption
$ echo -n simple_rsa_decryption | sha1sum 100be37579e0f27c314efcb68a773b31537b5118 -
WhiteHat{100be37579e0f27c314efcb68a773b31537b5118}
Web001 (Web Security 20)
ソースに次のように書いてある。
<!--test/test-->
testアカウントでログインすると、You are not admin.と表示される。クッキーのuserの値がtestになっているので、adminに書き換え、ページを更新するとフラグが表示される。
Flag: don't_believe_cookies_at_all
$ echo -n "don't_believe_cookies_at_all" | sha1sum 92b2bc2f657574ab3481ebcb6705c36079b3e6d7 -
WhiteHat{92b2bc2f657574ab3481ebcb6705c36079b3e6d7}
For002 (Forensics 15)
POST /accounts/login/ の箇所が数か所ある。No.505に対して302 Foundで返ってきている。No.505で投入しているパスワードは"@Bkav123#$challange3"
$ echo -n "@Bkav123#\$challange3" | sha1sum 0d712cbea97819fa1e1c0a605283b1b912bcf350 -
WhiteHat{0d712cbea97819fa1e1c0a605283b1b912bcf350}