├── xnuca-2016-re ├── s16384 └── solve.sage ├── 0ctf-2017-final └── crypto │ ├── send.bak │ ├── key │ ├── alice_public_key.py │ ├── bob_public_key.py │ ├── communication.py │ ├── keygen.sage │ └── solve.sage ├── twctf-2018 └── REVersiNG │ ├── REVersiNG │ ├── REVersiNG_mips │ ├── solve.py │ └── README.md ├── README.md ├── polictf-2017 ├── HanoiPub │ ├── hanoipub.bin │ ├── solve.py │ ├── README.md │ └── hanoipub.hex └── kompreplicants │ ├── kompressor │ ├── flag.txt.short008 │ └── solve.py ├── volgactf-quals-2017 └── transformer │ ├── transformer │ ├── ciphertext.zip.enc │ └── solve.py ├── ctfzone-2017-quals └── signature-server │ ├── PubDSA.pdf │ ├── README.md │ ├── collect.py │ ├── solve.sage │ └── datas ├── 0ctf-2017-quals ├── oneTimePad2 │ ├── ciphertxt │ ├── solve.sage │ └── oneTimePad2.py └── oneTimePad1 │ ├── ciphertext │ ├── solve.sage │ └── oneTimePad.py ├── pctf-2018 ├── Transducipher │ ├── data.txt │ ├── transducipher.py │ ├── solve_right_half.py │ └── solve_left_half.py ├── lcg │ ├── gen.py │ ├── try_lcg.py │ ├── lcg.py │ └── test.sage └── macsh │ ├── fmac.py │ ├── solve.py │ └── macsh.py ├── ASIS-CTF-2016-quals └── putnam.py ├── seccon-2016 └── solve.sage └── Volga-CTF-Quals-2016 └── transformer ├── transformer.py └── solve.py /xnuca-2016-re/s16384: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/xnuca-2016-re/s16384 -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/send.bak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/0ctf-2017-final/crypto/send.bak -------------------------------------------------------------------------------- /twctf-2018/REVersiNG/REVersiNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/twctf-2018/REVersiNG/REVersiNG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ctf 2 | sea0breeze's ctf writeups 3 | 4 | (Well, most of them look really ugly because I'm so lazy:p) 5 | -------------------------------------------------------------------------------- /polictf-2017/HanoiPub/hanoipub.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/polictf-2017/HanoiPub/hanoipub.bin -------------------------------------------------------------------------------- /twctf-2018/REVersiNG/REVersiNG_mips: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/twctf-2018/REVersiNG/REVersiNG_mips -------------------------------------------------------------------------------- /polictf-2017/kompreplicants/kompressor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/polictf-2017/kompreplicants/kompressor -------------------------------------------------------------------------------- /volgactf-quals-2017/transformer/transformer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/volgactf-quals-2017/transformer/transformer -------------------------------------------------------------------------------- /ctfzone-2017-quals/signature-server/PubDSA.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/ctfzone-2017-quals/signature-server/PubDSA.pdf -------------------------------------------------------------------------------- /polictf-2017/kompreplicants/flag.txt.short008: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/polictf-2017/kompreplicants/flag.txt.short008 -------------------------------------------------------------------------------- /volgactf-quals-2017/transformer/ciphertext.zip.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sea0breeze/ctf/HEAD/volgactf-quals-2017/transformer/ciphertext.zip.enc -------------------------------------------------------------------------------- /0ctf-2017-quals/oneTimePad2/ciphertxt: -------------------------------------------------------------------------------- 1 | 0da8e9e84a99d24d0f788c716ef9e99cc447c3cf12c716206dee92b9ce591dc0722d42462918621120ece68ac64e493a41ea3a70dd7fe2b1d116ac48f08dbf2b26bd63834fa5b4cb75e3c60d496760921b91df5e5e631e8e9e50c9d80350249c 2 | -------------------------------------------------------------------------------- /0ctf-2017-quals/oneTimePad1/ciphertext: -------------------------------------------------------------------------------- 1 | af3fcc28377e7e983355096fd4f635856df82bbab61d2c50892d9ee5d913a07f 2 | 630eb4dce274d29a16f86940f2f35253477665949170ed9e8c9e828794b5543c 3 | e913db07cbe4f433c7cdeaac549757d23651ebdccf69d7fbdfd5dc2829334d1b 4 | -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/key: -------------------------------------------------------------------------------- 1 | (24026804398012972212113994455719720580116668737586578755649231129252713479391L, 58171428514449411989239711L, 162747161083965920245583561789308690051, 155217205127554729896503363866176054391, 141617720150572576318703138971094612551, 153098689845489335265055840555899501217, 55328954130152551515239328, 64463913742831817764086370L) 2 | -------------------------------------------------------------------------------- /ctfzone-2017-quals/signature-server/README.md: -------------------------------------------------------------------------------- 1 | # signature-server 2 | 1. Convert the secret recovery to Hidden Number Problem(HNP) 3 | 2. Convert the HNP to Closest Vector Problem(CVP) 4 | 3. Convert the CVP to Shortest Vector Problem(SVP) 5 | 4. Solve the SVP by LLL and capture the flag! 6 | 7 | May the third step is not necessary according to the paper, but I think it can simplify the code because the answer is just showed in the matrix after LLL:) 8 | -------------------------------------------------------------------------------- /polictf-2017/HanoiPub/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from struct import unpack 5 | 6 | str = bytearray("To beer or not to beer, that is the question") 7 | offset = 0xf85 8 | tmp_array = bytearray() 9 | 10 | f = open('./hanoipub.bin', 'rb') 11 | f.seek(offset) 12 | index = 1 13 | while 1: 14 | tmp = unpack('H', f.read(2))[0] 15 | if tmp is 1: 16 | break 17 | tmp = tmp / index - 0x30 18 | tmp ^= str[index-1] 19 | tmp_array.append(tmp) 20 | index += 1 21 | 22 | print tmp_array 23 | -------------------------------------------------------------------------------- /ctfzone-2017-quals/signature-server/collect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from pwn import * 5 | 6 | debug = False 7 | 8 | if debug: 9 | r = remote('127.0.0.1', 1337) 10 | f = open('locals', 'w') 11 | else: 12 | r = remote('185.143.173.36', 1337) 13 | f = open('datas', 'w') 14 | 15 | for i in range(80): 16 | if i % 5 == 0: 17 | print i 18 | r.recvuntil('-> ') 19 | r.sendline('s') 20 | r.sendlineafter('sign: ', '1') 21 | f.write(r.recvline()) 22 | 23 | r.close() 24 | f.close() 25 | -------------------------------------------------------------------------------- /0ctf-2017-quals/oneTimePad1/solve.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sage 2 | # coding=utf-8 3 | 4 | from sage.all import * 5 | 6 | def str2num(s): 7 | return int(s.encode('hex'), 16) 8 | 9 | P. = GF(2^256) 10 | 11 | m = [None, "I_am_not_a_secret_so_you_know_me", "feeddeadbeefcafefeeddeadbeefcafe"] 12 | c = [] 13 | f = open("./ciphertext") 14 | for line in f: 15 | c.append(int(line.strip(),16)) 16 | 17 | k2 = P.fetch_int(c[2] ^^ str2num(m[2])) 18 | k1 = P.fetch_int(c[1] ^^ str2num(m[1])) 19 | k = k2 + (k1 * k1) 20 | k0 = (k1 + k).sqrt() 21 | print hex(k0.integer_representation() ^^ c[0])[2:].strip('L').decode('hex') 22 | -------------------------------------------------------------------------------- /pctf-2018/Transducipher/data.txt: -------------------------------------------------------------------------------- 1 | (13079742441184578626, 15822063786926281121) 2 | (13416567443684297300, 1953576081095923750) 3 | (4616590709284765790, 12242300051344248099) 4 | (8927700908577296018, 9212645445239734194) 5 | (7046689723092979039, 14605811860901350724) 6 | (11723181797717683420, 4856237318714098520) 7 | (462956565916497673, 11917849788719540909) 8 | (15062759243211353209, 1178676016977386894) 9 | (5006958167746643506, 12231044178199617742) 10 | (17215578442192296916, 7867686081879292369) 11 | (3264652127960099870, 11088704409660527687) 12 | (67438940002497203, 13146678993523844395) 13 | (10567909756016925586, 16545327010848548669) 14 | (15707806635548046505, 14743926144157706447) 15 | (6478276705282625651, 18007098612493695685) 16 | (10970386673164693022, 12683515533170128309) 17 | -------------------------------------------------------------------------------- /xnuca-2016-re/solve.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sage 2 | # coding=utf-8 3 | 4 | from sage.all import * 5 | from struct import * 6 | f = open('s16384','rb') 7 | ff = f.read() 8 | f.close() 9 | pos1 = 0x12080 10 | pos2 = 0x2080 11 | result = unpack('16384i',ff[pos1:pos1+16384*4]) 12 | base = list(unpack('16384i',ff[pos2:pos2+16384*4])) 13 | G = SymmetricGroup(16384) 14 | x = G([i+1 for i in base]) 15 | y = G([i+1 for i in result]) 16 | 17 | cyclex = x.cycles() 18 | cycley = y.cycles() 19 | assert len(cyclex) == len(cycley) 20 | 21 | exp = [] 22 | order = [] 23 | for i in range(len(cyclex)): 24 | xi = cyclex[i] 25 | yi = cycley[i] 26 | tmp = xi 27 | order.append(xi.order()) 28 | expi = 1 29 | while tmp != yi: 30 | expi += 1 31 | tmp *= xi 32 | exp.append(expi) 33 | 34 | print CRT_list(exp,order) 35 | -------------------------------------------------------------------------------- /0ctf-2017-quals/oneTimePad2/solve.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sage 2 | # coding=utf-8 3 | 4 | from sage.all import * 5 | 6 | p. = GF(2^128) 7 | 8 | print 'Start' 9 | c = file("./ciphertxt").read().strip() 10 | m = "One-Time Pad is used here. You won't know that the flag is flag{".encode('hex') 11 | 12 | x = [] 13 | for i in range(0, len(m), 32): 14 | ci = int(c[i:i+32], 16) 15 | print ci 16 | mi = int(m[i:i+32], 16) 17 | x.append(p.fetch_int(ci^^mi)) 18 | 19 | a = p.fetch_int(264046295839861049478585915471640894461L) 20 | k = p.fetch_int(139842438333098917680069068063480255258L) 21 | 22 | n = [] 23 | for i in range(len(x)-1): 24 | n.append((x[i+1]+k)/(x[i]+k)) 25 | 26 | print "Log start." 27 | e = [] 28 | for i in n: 29 | print 'try...' 30 | e.append(i.log(a)) 31 | 32 | print [i for i in e] 33 | e0 = e[-1] 34 | e1 = (p.fetch_int(e0)**2).integer_representation() 35 | xx = (x[-1]+k)*(a**e1)+k 36 | xx = xx.integer_representation() 37 | 38 | print xx 39 | print hex(xx^^int(c[-64:-32], 16))[2:-1].decode('hex') 40 | -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/alice_public_key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | # Generated by genKey(1024, 342) in keygen.sage 5 | 6 | e = 16140311304784625807971244520043756160102111440186500282911137675250199677022940503982292569233803572106227632954920805936151799049981849612210588147943318190599476331582153430089688143361226994947530603424082905816220548156412649246782363716825121201733242060234874574393149811078415952220812029904096645141 7 | 8 | N1 = 73871864906066571406532457145607595847175670495017175565388132342574183187410380661917315431292987479576202710800243301821110154265031908769855345111418669574603508401169110155260587673272035301147668990301239964950207744512780378527326467318883681760821710529273075846801071296284930852211925448126134456371 9 | 10 | N2 = 10548244241379959973012698997313565838321599691374783075397881482031959048170291643267402594849260277539547268187806692681844616430159988384126260317181183835757828333838579492655650376150221839149317599035426574857154820265992983356076281713571392012617269312376565128009638293040584673854656713040776519371 11 | -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/bob_public_key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | # Generated by genKey(1024, 342) in keygen.sage 5 | 6 | e = 57019382772166837488750427040015464490863175936396575556290232679668259683514801918298546850349718538222635977304361506235546587039055174992606638351023434322917005735910505716857963030159773221874370814472973319422853023944637626372539074831161749650232791256091117301145054914651557523038888181457290682237 7 | 8 | N1 = 68253958478963934124300215757460723273691925280596309221863375905836387105252457670797482776100691909463871547306272253629697109054703333176926409544379734932863965587299902358818026560280727724874176607409038276642286734734838152097800253007709025880304435661500771500046972983240470823245360867996258239121 9 | 10 | N2 = 58831168144192031952989136031836716698976227434725683505500936300434624499242689272670040374754049533739858144785202063762391111213777476380071324869525517503277889732429358219404717664025176836710995641523459333571168229803403205064106761733957455221168205091994936332421038092333687260644067187030525515969 11 | -------------------------------------------------------------------------------- /ctfzone-2017-quals/signature-server/solve.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sage 2 | # coding=utf-8 3 | 4 | from hashlib import sha1 5 | 6 | ''' 7 | The paper about this attack is attached in git. 8 | It seems that the attack works whether it is ECDSA or DSA. 9 | ''' 10 | 11 | q = 0x100000000000000000001f4c8f927aed3ca752257 12 | d = 80 13 | l = 5 14 | bound = q / (2 ** (l+1)) 15 | # h = int(sha1('1').hexdigest(), 16) 16 | h = 304942582444936629325699363757435820077590259883 17 | t = [] 18 | u = [] 19 | 20 | for line in open('datas'): 21 | r, s, a = map(Zmod(q), line.strip().split(', ')) 22 | tt = (r / s) / (2**l) 23 | tt = tt.lift() 24 | uu = (a - h / s) / (2**l) 25 | uu = uu.lift() + bound 26 | if uu >= q: 27 | uu -= q 28 | t.append(tt) 29 | u.append(uu) 30 | 31 | m = [] 32 | for i in range(d): 33 | tmp = [0] * (d+2) 34 | tmp[i] = q 35 | m.append(tmp) 36 | m.append(t+[1/(2**(l+1)), 0]) 37 | m.append(u+[0, bound]) 38 | 39 | ma = matrix(QQ, m) 40 | print 'Ready to LLL...' 41 | mb = ma.LLL() 42 | 43 | flag_num = -mb[1][-2] * (2**(l+1)) 44 | print hex(int(flag_num))[2:].rstrip('L').decode('hex') 45 | -------------------------------------------------------------------------------- /pctf-2018/lcg/gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | import binascii 5 | import os 6 | 7 | N = 128 8 | assert N % 8 == 0 9 | OUTPUT = 32 10 | HIDDEN = N-OUTPUT 11 | 12 | def gcd(u, v): 13 | while v: 14 | u, v = v, u % v 15 | return abs(u) 16 | 17 | def nextstate(state, mult, inc, modulus): 18 | return (state*mult + inc) % modulus 19 | 20 | def init_test(): 21 | while 1: 22 | m = int(binascii.hexlify(os.urandom(N // 8)), 16) 23 | a = 0 24 | b = 0 25 | s = 0 26 | while not (1 <= a < m and gcd(a, m) == 1): 27 | a = int(binascii.hexlify(os.urandom(N // 8)), 16) 28 | while not (1 <= b < m and gcd(b, m) == 1): 29 | b = int(binascii.hexlify(os.urandom(N // 8)), 16) 30 | while not (1 <= s < m): 31 | s = int(binascii.hexlify(os.urandom(N // 8)), 16) 32 | 33 | x = [] 34 | y = [] 35 | for i in xrange(40): 36 | y.append(s>>HIDDEN) 37 | x.append(s) 38 | s = nextstate(s, a, b, m) 39 | if gcd(x[1]-x[0], m) == 1: 40 | break 41 | else: 42 | print "Fail init" 43 | return m, a, b, x, y 44 | -------------------------------------------------------------------------------- /twctf-2018/REVersiNG/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from pwn import * 5 | from struct import unpack 6 | 7 | def xor(a): 8 | a = bytearray(a) 9 | b = bytearray('KNOWN_PLAIN_TEXT'*8) 10 | return str(bytearray([i^j for i,j in zip(a,b)])) 11 | 12 | def getkey(k): 13 | # r = process(['qemu-mips', '-L', '/usr/mips-linux-gnu', 'mips.elf']) 14 | r = remote('pwn1.chal.ctf.westerns.tokyo', 16625) 15 | r.send('\x00') 16 | r.send(p32(0x412320+k, endian='big')) 17 | rand = r.recvline().strip() 18 | # log.info(rand) 19 | rand = rand.decode('hex') 20 | c1 = r.recvline().strip() 21 | c2 = r.recvline().strip() 22 | # log.info(c1) 23 | # log.info(c2) 24 | c1 = xor(c1.decode('hex')) 25 | c2 = xor(c2.decode('hex')) 26 | i1 = unpack('>16I', c1[:64]) 27 | i2 = unpack('>16I', c2[:64]) 28 | res = [(i-j)&0xffffffff for i,j in zip(i1, i2)] 29 | res = [format(i, '08x') for i in res] 30 | res = ''.join(res).decode('hex')[k] 31 | log.info('%d: %s', k, repr(res)) 32 | r.close() 33 | return res 34 | 35 | if __name__ == '__main__': 36 | flag = '' 37 | for i in range(16, 48): 38 | flag += getkey(i) 39 | print flag.encode('hex') 40 | -------------------------------------------------------------------------------- /polictf-2017/kompreplicants/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from cStringIO import StringIO 5 | 6 | def tob(c): 7 | res = bin(c)[2:] 8 | return res.rjust(8, '0') 9 | 10 | with open('./flag.txt.short008', 'rb') as f: 11 | c = f.read() 12 | 13 | tmp = map(ord, c) 14 | raw = [tmp[0]] 15 | # Every byte in the compressed file is actually a sum of previous bytes and the current byte of the true content! 16 | for i in range(1, len(tmp)): 17 | raw.append((tmp[i]-tmp[i-1])%256) 18 | 19 | # Get the conversion table of Huffman Coding 20 | raw = ''.join(map(tob, raw)) 21 | raw = StringIO(raw) 22 | table = {} 23 | while True: 24 | size = int(raw.read(4), 2) 25 | if not size: 26 | break 27 | oldch = chr(int(raw.read(8), 2)) 28 | newch = raw.read(size) 29 | table[newch] = oldch 30 | 31 | print table 32 | 33 | # Decode it and get the cute flag! 34 | mes = '' 35 | flag = 0 36 | while True: 37 | bits = '' 38 | while True: 39 | bit = raw.read(1) 40 | if not bit: 41 | flag = 1 42 | break 43 | bits += bit 44 | if table.has_key(bits): 45 | mes += table[bits] 46 | break 47 | if flag: 48 | break 49 | print mes 50 | -------------------------------------------------------------------------------- /0ctf-2017-quals/oneTimePad1/oneTimePad.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from os import urandom 5 | 6 | def process(m, k): 7 | tmp = m ^ k 8 | res = 0 9 | for i in bin(tmp)[2:]: 10 | res = res << 1; 11 | if (int(i)): 12 | res = res ^ tmp 13 | if (res >> 256): 14 | res = res ^ P 15 | return res 16 | 17 | def keygen(seed): 18 | key = str2num(urandom(32)) 19 | while True: 20 | yield key 21 | key = process(key, seed) 22 | 23 | def str2num(s): 24 | return int(s.encode('hex'), 16) 25 | 26 | P = 0x10000000000000000000000000000000000000000000000000000000000000425L 27 | 28 | true_secret = open('flag.txt').read()[:32] 29 | assert len(true_secret) == 32 30 | print 'flag{%s}' % true_secret 31 | fake_secret1 = "I_am_not_a_secret_so_you_know_me" 32 | fake_secret2 = "feeddeadbeefcafefeeddeadbeefcafe" 33 | secret = str2num(urandom(32)) 34 | 35 | generator = keygen(secret) 36 | ctxt1 = hex(str2num(true_secret) ^ generator.next())[2:-1] 37 | ctxt2 = hex(str2num(fake_secret1) ^ generator.next())[2:-1] 38 | ctxt3 = hex(str2num(fake_secret2) ^ generator.next())[2:-1] 39 | f = open('ciphertext', 'w') 40 | f.write(ctxt1+'\n') 41 | f.write(ctxt2+'\n') 42 | f.write(ctxt3+'\n') 43 | f.close() 44 | -------------------------------------------------------------------------------- /ASIS-CTF-2016-quals/putnam.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha1 2 | 3 | def check(flag): # These bignums are hard-coded and can be known using gdb, this function is at 0x402B26 4 | tmp = flag + 927000317028443242660218700625015177618729308292 5 | tmp1 = 58083098340436592572428949667026971680998552113001298964050042091817127554826077890574096402833663439016381224578837061641047295828109375 % tmp 6 | tmp4 = pow(flag, 3, tmp) 7 | v7 = (tmp4 + tmp1) % tmp 8 | return v7 9 | 10 | # There are factors of a bignum, but it seems factoring is not needed... 11 | f = '17 41 1277 201812749 5114084777490587 79446245382102257493817667075063441 10915057861749906024158514424195715948375317244103006997979908370684387984168819'.split() 12 | f = map(int,f) 13 | from itertools import combinations 14 | for i in range(1, len(f)+1): 15 | for k in combinations(f, i): 16 | tmp = reduce(lambda x,y: x*y, k) - 927000317028443242660218700625015177618729308292 17 | assert check(tmp) == 0 18 | if tmp > 0: 19 | flag = hex(tmp)[2:].strip('L') 20 | if len(flag) % 2 != 0: 21 | flag = '0'+flag 22 | if 'f8502be39225bb1bcaf0d3591da722ca541162fc' == sha1(flag.decode('hex')).hexdigest(): 23 | print flag.decode('hex') 24 | -------------------------------------------------------------------------------- /polictf-2017/HanoiPub/README.md: -------------------------------------------------------------------------------- 1 | # HanoiPub Writeup 2 | Some Googling tells us that this file is Intel HEX format. Convert it to binary format by objcopy and we can load it by IDA. As its architectrue is AVR, its code address space and its data address space is separated and its way to load/store data is so strange. So it seems that IDA can't deal with it properly(But I think it's at least better than using objdump). 3 | 4 | After hours of reading documentation of avr and analyzing the program, I got the following deduction: (The address showed in IDA is different from raw file) 5 | 6 | * sub_87 is used to print bytes, given str pointer and length; 7 | * sub_4c5 is "printf" 8 | * sub_2e9 is "main" 9 | * the data section is loaded by lpm instructions in _RESET 10 | * the strings about "%d bottles of beer" have nothing to do with the flag 11 | * The fun part is around 0x425-0x426 ---- the eor instructions 12 | 13 | In fact, there is an int16 array ended with 0x1(not included). For each word, it tries to minus it with index+1 and ++tmp(init as 1) again and again, until the word is decreased to 0(namely, tmp = array[i] / (i+1)). Then tmp -= 0x30, and xor it with the corresponding byte in "To beer or not to beer, that is the question". I try to find out the result and it appears to be flag :) -------------------------------------------------------------------------------- /pctf-2018/macsh/fmac.py: -------------------------------------------------------------------------------- 1 | from Crypto import Random 2 | from Crypto.Cipher import AES 3 | from functools import reduce 4 | 5 | N = AES.block_size 6 | 7 | def to_int(b): 8 | return int(bytes.hex(b), 16) 9 | 10 | def to_block(b): 11 | return bytes.fromhex('{:0{width}x}'.format(b, width=N*2)) 12 | 13 | def xor(x, y): 14 | return bytes([xe ^ ye for xe,ye in zip(x,y)]) 15 | 16 | def to_blocks(m): 17 | m += to_block(len(m)) 18 | padb = N - len(m) % N 19 | m += bytes([padb]) * padb 20 | blocks = [m[N*i : N*(i+1)] for i in range(len(m) // N)] 21 | if len(blocks) > 128: 22 | tmp = blocks[128:] 23 | else: 24 | tmp = blocks[:] 25 | # print(tmp) 26 | return blocks 27 | 28 | def rot(n, c): 29 | return (n >> c) | ((n & ((1 << c) - 1)) << (8 * N - c)) 30 | 31 | def f(k0, i): 32 | return to_block(rot(to_int(k0), i % (8 * N))) 33 | 34 | def fmac(k0, k1, m): 35 | C = AES.new(k1, AES.MODE_ECB) 36 | bs = [C.encrypt(xor(b, f(k0, i))) for i,b in enumerate(to_blocks(m))] 37 | if len(bs) > 128: 38 | tmp = bs[128:] 39 | else: 40 | tmp = bs[:] 41 | # print([bytes.hex(i) for i in tmp]) 42 | return reduce(xor, bs, b"\x00" * N) 43 | 44 | def keygen(): 45 | R = Random.new() 46 | return R.read(N), R.read(N) 47 | -------------------------------------------------------------------------------- /pctf-2018/lcg/try_lcg.py: -------------------------------------------------------------------------------- 1 | import string 2 | import pickle 3 | from pwn import * 4 | from hashlib import sha256 5 | from subprocess import check_output 6 | import random 7 | 8 | context.log_level='debug' 9 | 10 | def dopow(): 11 | tab=string.ascii_letters+string.digits 12 | c.recvuntil('with ') 13 | pre=c.recv(10) 14 | print pre 15 | i=0 16 | while True: 17 | cur=''.join(random.sample(tab,6)) 18 | if sha256(pre+cur).hexdigest()[-6:] == ('ffffff'): 19 | return pre+cur 20 | i+=1 21 | 22 | c = remote('lcg.chal.pwning.xxx',6051) 23 | work=dopow() 24 | c.sendline(work) 25 | ''' 26 | c = remote('127.0.0.1', 6051) 27 | ''' 28 | c.recvuntil('seconds.\n') 29 | #oracle = c.recvline().strip() 30 | #m,a,b,state = map(int,oracle.split(' ')[1:]) 31 | stat = c.recvline().strip() 32 | stat = map(int,stat.split(' ')[1:]) 33 | assert len(stat)==40 34 | f=open('lcg_stats','w') 35 | pickle.dump(stat,f) 36 | f.close() 37 | 38 | import os 39 | print 'Ready to sage' 40 | raw_input() 41 | 42 | with open('output') as f: 43 | m, a, diff, s0 = pickle.load(f) 44 | d = diff[-1] 45 | 46 | for i in range(200): 47 | d = d * a % m 48 | s0 = (s0 + d) % m 49 | output = s0 >> 96 50 | c.sendline(str(output)) 51 | print c.recvline() 52 | 53 | c.recv() 54 | c.interactive() 55 | -------------------------------------------------------------------------------- /pctf-2018/macsh/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from pwn import log, process, context, remote 5 | 6 | # context.log_level = 'debug' 7 | N = 16 8 | 9 | def to_block(b): 10 | return '{:0{width}x}'.format(b, width=N*2).decode('hex') 11 | 12 | def to_blocks(m): 13 | m += to_block(len(m)) 14 | padb = N - len(m) % N 15 | m += chr(padb) * padb 16 | blocks = [m[N*i : N*(i+1)] for i in range(len(m) // N)] 17 | return blocks 18 | 19 | # r = process('./macsh.py') 20 | r = remote('macsh.chal.pwning.xxx', 64791) 21 | 22 | def e(m, mac = '0'): 23 | global r 24 | r.sendlineafter('> ', mac+'<|>'+m) 25 | return r.recvline() 26 | 27 | 28 | def test(cmd): 29 | global r 30 | 31 | echo = 'echo ' + '3' * (len(cmd)-5) 32 | p = 'tag ' + echo 33 | p1 = echo + '\x00' * (16-len(echo)) 34 | p2 = cmd + '\x00' * (16-len(cmd)) 35 | 36 | gg = 'tag ' + p1+'s'*(16*8-1)*16+p2+'s'*(16*8-1)*16 37 | res1 = e(gg) 38 | log.info(res1) 39 | res1 = int(res1, 16) 40 | 41 | gg = 'tag ' + p1+'s'*(16*8-1)*16+p1+'s'*(16*8-1)*16 42 | res2 = e(gg) 43 | log.info(res2) 44 | res2 = int(res2, 16) 45 | 46 | res3 = e(p) 47 | log.info(res3) 48 | res3 = int(res3, 16) 49 | log.info(e(cmd,mac = format(res1^res2^res3, 'x'))) 50 | 51 | test('cat flag.txt') 52 | r.interactive() 53 | -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/communication.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | from os import urandom 4 | from secret_socket import socket_with_bob 5 | import alice_private_key 6 | import bob_public_key 7 | 8 | def str2int(s): 9 | return int(s.encode('hex'), 16) 10 | 11 | def int2str(i): 12 | tmp = hex(i)[2:].strip('L') 13 | tmp = ('0' if len(tmp)%2 else '') + tmp 14 | return tmp.decode('hex') 15 | 16 | def sign_and_encrypt(m): 17 | m = urandom(126-len(m)) + '\x00' + m 18 | sig = pow(str2int(m), alice_private_key.d, alice_private_key.N2) 19 | assert sig < bob_public_key.N1 20 | sig_enc = pow(sig, bob_public_key.e, bob_public_key.N1) 21 | return int2str(sig_enc) 22 | 23 | def decrypt_and_verify(c): 24 | sig = pow(str2int(c), alice_private_key.d, alice_private_key.N1) 25 | assert sig < bob_public_key.N2 26 | message = pow(sig, bob_public_key.e, bob_public_key.N2) 27 | message = int2str(message) 28 | message = message[message.rindex('\x00')+1:] 29 | return message 30 | 31 | s = socket_with_bob() 32 | recv_enc = s.recv() 33 | recv_message = decrypt_and_verify(recv_enc) 34 | assert recv_message == "Ooops, my flag have been encrypted by wannacry! Could you please send it to me again, Alice?" 35 | 36 | with open('flag.txt') as f: 37 | flag = f.read() 38 | send_message = "Well, OK... Here is what you what: {}".format(flag) 39 | assert len(send_message) < 128 40 | to_send = sign_and_encrypt(send_message) 41 | s.send(to_send) 42 | s.close() 43 | 44 | with open('send.bak', 'wb') as f: 45 | f.write(to_send) 46 | -------------------------------------------------------------------------------- /pctf-2018/Transducipher/transducipher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | import os 3 | 4 | BLOCK_SIZE = 64 5 | 6 | T = [ 7 | ((2, 1), 1), 8 | ((5, 0), 0), 9 | ((3, 4), 0), 10 | ((1, 5), 1), 11 | ((0, 3), 1), 12 | ((4, 2), 0), 13 | ] 14 | 15 | def block2bin(b, length=BLOCK_SIZE): 16 | return list(map(int, bin(b)[2:].rjust(length, '0'))) 17 | 18 | def bin2block(b): 19 | return int("".join(map(str, b)), 2) 20 | 21 | def transduce(b, s=0): 22 | # print s, 23 | if len(b) == 0: 24 | return b 25 | d, t = T[s] 26 | b0, bp = b[0], b[1:] 27 | return [b0 ^ t] + transduce(bp, s=d[b0]) 28 | 29 | def rtransduce(b, s=0): 30 | if len(b) == 0: 31 | return b 32 | d, t = T[s] 33 | b0, bp = b[0] ^ t, b[1:] 34 | return [b0] + rtransduce(bp, s=d[b0]) 35 | 36 | def transduceblock(b): 37 | return bin2block(transduce(block2bin(b))) 38 | 39 | def swap(b): 40 | l = BLOCK_SIZE // 2 41 | m = (1 << l) - 1 42 | return (b >> l) | ((b & m) << l) 43 | 44 | class Transducipher: 45 | def __init__(self, k): 46 | self.k = [k] 47 | for i in range(1, len(T)): 48 | k = swap(transduceblock(k)) 49 | self.k.append(k) 50 | 51 | def encrypt(self, b): 52 | for i in range(len(T)): 53 | b ^= self.k[i] 54 | b = transduceblock(b) 55 | b = swap(b) 56 | return b 57 | 58 | if __name__ == "__main__": 59 | flag = bytes.hex(os.urandom(BLOCK_SIZE // 8)) 60 | k = int(flag, 16) 61 | C = Transducipher(k) 62 | print("Your flag is PCTF{%s}" % flag) 63 | with open("data.txt", "w") as f: 64 | for i in range(16): 65 | pt = int(bytes.hex(os.urandom(BLOCK_SIZE // 8)), 16) 66 | ct = C.encrypt(pt) 67 | f.write(str((pt, ct)) + "\n") 68 | -------------------------------------------------------------------------------- /pctf-2018/macsh/macsh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | 6 | from fmac import fmac, keygen 7 | 8 | cwd = os.getcwd() 9 | 10 | k0, k1 = keygen() 11 | 12 | commands = [ 13 | "echo", 14 | "tag" 15 | ] 16 | 17 | privileged = { 18 | "pwd", 19 | "cd", 20 | "ls", 21 | "cat" 22 | } 23 | 24 | commands.extend(privileged) 25 | 26 | def echo(s): 27 | print(s) 28 | 29 | def encode(cmdline): 30 | return cmdline.encode('utf-8') 31 | 32 | def tag(cmd, *args): 33 | if cmd not in privileged: 34 | cmdline = encode(" ".join([cmd] + list(args))) 35 | print(bytes.hex(fmac(k0, k1, cmdline))) 36 | else: 37 | print("macsh: tag: Permission denied") 38 | 39 | def pwd(): 40 | print(cwd) 41 | 42 | def cd(newdir): 43 | global cwd 44 | if not os.path.exists(newdir) or not os.path.isdir(newdir): 45 | print("macsh: cd: {}: No such file or directory".format(newdir)) 46 | else: 47 | cwd = newdir 48 | os.chdir(newdir) 49 | 50 | def ls(path): 51 | if not os.path.exists(path): 52 | print("ls: cannot access '{}': no such file or directory".format(path)) 53 | return 54 | if os.path.isdir(path): 55 | for e in os.listdir(path): 56 | print(e) 57 | else: 58 | print(path) 59 | 60 | def cat(path): 61 | if not os.path.exists(path): 62 | print("cat: {}: No such file or directory".format(path)) 63 | else: 64 | sys.stdout.write(open(path).read()) 65 | 66 | while True: 67 | print("|$|> ", end='', flush=True) 68 | mac, cmdline = input().split('<|>') 69 | cmd, *args = cmdline.split() 70 | if cmd not in commands: 71 | print("macsh: {}: command not found".format(cmd)) 72 | continue 73 | if cmd == "tag" or bytes.hex(fmac(k0, k1, encode(cmdline))) == mac: 74 | eval(cmd)(*args) 75 | else: 76 | print("macsh: bad tag") 77 | -------------------------------------------------------------------------------- /seccon-2016/solve.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sage 2 | # coding=utf-8 3 | 4 | from sage.all import * 5 | 6 | n = 152892010443090161139450520363336518176742831599245145269153050396304564578907061795002905497998181142150084756273027299413611874514332068143865940235470562936379188762997683217102550513594953558853595307850654237744631156477403609463962491704648853366488908634011293294315042964988628571048954313358560384637 7 | 8 | c = (106401526983274935175554163521885709809458025472653542921421418077722955983292668441227764583037239343668045172131341517128947139240387701114722850059096442966228423310654842102708720586878987358201100671623722877133703007579985268013756391009593306931619413138182981344221190238429916930061095280892583295263, 54470798161956075480403090700211786713469572024746803641784226923977142081019650577257940680362357610394133057340134544650997598288856840818386679124943605079080275121081252172800511221049038683530736321128773529112806040362302220933880826210577342563310230742149978255782511061623867115574492187972433541543) 9 | 10 | PR. = PolynomialRing(Zmod(n)) 11 | gp = Gp(stacksize=1024*1024*512) 12 | 13 | def getflag(k): 14 | f = (x + k * y) ^ 4919 15 | coe = f.coefficients() 16 | ex = f.exponents() 17 | print "Get coe,exp" 18 | f1 = 0 19 | f2 = 0 20 | for i in xrange(len(ex)): 21 | re, im = ex[i] 22 | case = im % 4 23 | unit_f = coe[i] * x ^ re 24 | if case == 0: 25 | f1 += unit_f 26 | elif case == 1: 27 | f2 += unit_f 28 | elif case == 2: 29 | f1 -= unit_f 30 | elif case == 3: 31 | f2 -= unit_f 32 | if i % 100 == 0: 33 | print i 34 | f1 -= c[0] 35 | f2 -= c[1] 36 | gp.set('g','gcd(Mod({},{}),Mod({},{}))'.format(f1,n,f2,n)) 37 | print gp.get('g') 38 | res = gp('liftall(-Vec(g / Vec(g)[1])[2])') 39 | return res 40 | 41 | int_flag = getflag(1) 42 | hex_flag = hex(int(int_flag)).strip('L').split('00')[-1].lstrip('0') 43 | print hex_flag.decode('hex') 44 | -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/keygen.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sage 2 | # coding=utf-8 3 | 4 | proof.arithmetic(False) 5 | 6 | threshold = 21 << 1018 # just chosen arbitrarily:) 7 | 8 | def genKey(n, nd): 9 | ''' 10 | Designed with the awesome idea that generating two RSA key pairs 11 | that have the same public and private exponents to reduce the 12 | storage requirements! 13 | ''' 14 | 15 | assert n/2 > nd 16 | tmp = n/2 - nd 17 | 18 | while True: 19 | while True: 20 | x1 = randrange(2^(nd-1), 2^nd) 21 | x2 = randrange(2^(tmp-1), 2^tmp) 22 | p1 = x1*x2 + 1 23 | if p1.is_prime(): 24 | print '[+]bit length of p1:', int(p1).bit_length() 25 | break 26 | 27 | while True: 28 | y2 = randrange(2^(tmp-1), 2^tmp) 29 | p2 = x1*y2 + 1 30 | if p2.is_prime(): 31 | print '[+]bit length of p2:', int(p2).bit_length() 32 | break 33 | 34 | while True: 35 | y1 = randrange(2^(nd-1), 2^nd) 36 | q1 = y1*y2 + 1 37 | if q1.is_prime(): 38 | print '[+]bit length of q1:', int(q1).bit_length() 39 | break 40 | 41 | count = 0 42 | while True: 43 | d = randrange(2^(nd-1), 2^nd) 44 | if gcd(x1*x2*y1*y2, d) != 1: 45 | continue 46 | e = int(1/Mod(d, (p1-1)*(q1-1))) 47 | k1 = (e*d - 1) // ((p1-1)*(q1-1)) 48 | assert e*d == (p1-1)*(q1-1)*k1 + 1 49 | q2 = k1*x2 + 1 50 | if q2.is_prime(): 51 | print '[+]bit length of q2:', int(q2).bit_length() 52 | break 53 | n1 = p1 * q1 54 | n2 = p2 * q2 55 | n1, n2 = max([n1, n2]), min([n1, n2]) 56 | if n1 <= threshold: 57 | print '[+]N for encryptions is too small!' 58 | continue 59 | if n2 >= threshold: 60 | print '[+]N for signatures is too large!' 61 | continue 62 | break 63 | 64 | assert int(pow(pow(0xdeadbeef, e, n1), d)) == 0xdeadbeef 65 | assert int(pow(pow(0xdeadbeef, e, n2), d)) == 0xdeadbeef 66 | return (e, d, n1, n2) 67 | 68 | if __name__ == '__main__': 69 | print genKey(1024, 342) 70 | -------------------------------------------------------------------------------- /0ctf-2017-quals/oneTimePad2/oneTimePad2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | from os import urandom 5 | 6 | def process1(m, k): 7 | res = 0 8 | for i in bin(k)[2:]: 9 | res = res << 1; 10 | if (int(i)): 11 | res = res ^ m 12 | if (res >> 128): 13 | res = res ^ P 14 | return res 15 | 16 | def process2(a, b): 17 | res = [] 18 | res.append(process1(a[0], b[0]) ^ process1(a[1], b[2])) 19 | res.append(process1(a[0], b[1]) ^ process1(a[1], b[3])) 20 | res.append(process1(a[2], b[0]) ^ process1(a[3], b[2])) 21 | res.append(process1(a[2], b[1]) ^ process1(a[3], b[3])) 22 | return res 23 | 24 | def nextrand(rand): 25 | global N, A, B 26 | tmp1 = [1, 0, 0, 1] 27 | tmp2 = [A, B, 0, 1] 28 | s = N 29 | N = process1(N, N) 30 | while s: 31 | if s % 2: 32 | tmp1 = process2(tmp2, tmp1) 33 | tmp2 = process2(tmp2, tmp2) 34 | s = s / 2 35 | return process1(rand, tmp1[0]) ^ tmp1[1] 36 | 37 | 38 | def keygen(): 39 | key = str2num(urandom(16)) 40 | while True: 41 | yield key 42 | key = nextrand(key) 43 | 44 | def encrypt(message): 45 | length = len(message) 46 | pad = '\x00' + urandom(15 - (length % 16)) 47 | to_encrypt = message + pad 48 | res = '' 49 | generator = keygen() 50 | f = open('key.txt', 'w') # This is used to decrypt and of course you won't get it. 51 | for i, key in zip(range(0, length, 16), generator): 52 | f.write(hex(key)+'\n') 53 | res += num2str(str2num(to_encrypt[i:i+16]) ^ key) 54 | f.close() 55 | return res 56 | 57 | def decrypt(ciphertxt): 58 | # TODO 59 | pass 60 | 61 | def str2num(s): 62 | return int(s.encode('hex'), 16) 63 | 64 | def num2str(n, block=16): 65 | s = hex(n)[2:].strip('L') 66 | s = '0' * ((32-len(s)) % 32) + s 67 | return s.decode('hex') 68 | 69 | P = 0x100000000000000000000000000000087 70 | A = 0xc6a5777f4dc639d7d1a50d6521e79bfd 71 | B = 0x2e18716441db24baf79ff92393735345 72 | N = str2num(urandom(16)) 73 | assert N != 0 74 | 75 | if __name__ == '__main__': 76 | with open('top_secret') as f: 77 | top_secret = f.read().strip() 78 | assert len(top_secret) == 16 79 | plain = "One-Time Pad is used here. You won't know that the flag is flag{%s}." % top_secret 80 | 81 | with open('ciphertxt', 'w') as f: 82 | f.write(encrypt(plain).encode('hex')+'\n') 83 | -------------------------------------------------------------------------------- /twctf-2018/REVersiNG/README.md: -------------------------------------------------------------------------------- 1 | # REVersiNG 2 | After some simple reversing we can know that the binary is generated by the tool [rev.ng](https://rev.ng) (just as the chall name implies), which can "translate a static ARM, MIPS or x86-64 Linux binary to any of the architectures supported by LLVM". Strings the binary then you can find such string `int do_fork(struct CPUMIPSState *, unsigned int, abi_ulong, abi_ulong, target_ulong, abi_ulong)`. So our binary is translated from a mips binary. 3 | 4 | We try to analyse the binary more and find that the sections of original mips binary is still in the new binary. It makes things really easy.(I am not sure if it is expected by the designer) In its section table there are two strange sections `.o_rx_0x400000` and `.o_rw_0x412000`. Dump the data in the two sections and we see that it starts with 7f454c46. So it's exactly what we need. 5 | 6 | After getting the mips binary without obfuscation, we just try to find out what it does by reversing it(Sadly, we are unable to decompile it). Hours' work makes us know that the binary's behaviors can be described as follow: 7 | 8 | * it reads one byte `a` and one dword `b` as input 9 | * it generates a random nonce by reading /dev/urandom and get key(our flag) by reading ./key 10 | * it encrypts one 128-byte-long hardcoded string with the nonce and key twice and print two ciphertexts and the nonce(all hex-encoded) 11 | * the encryption algorithm is a block cipher in CTR mode and the block length is 64 bytes 12 | * In the second encryption, before it encrypts `block a`(for example, if a = 0, it's the first block), it will set the byte pointed by `b` to zero 13 | 14 | Now we know that the program is a simulation to **fault injection attack**. In encryption, 64-byte-long block is consist of constants(16 bytes), key(32 bytes), counter(4 bytes, starts at 1) and nonce(12 bytes). The process of one block's encryption can be showed as the expression: 15 | 16 | `ciphertext = plaintext ^ (Enc(block)+block)` 17 | 18 | In the addition, the blocks are regarded as int arrays and added. The fault injection happens after the block is constructed and before it is encrypted. Although the two `block` in `(Enc(block)+block)` should be same, in fact the second one is stored in .bss and the first one is a copy in stack. So if we set one byte of the block in .bss to zero, the result of encryption will be changed. With the difference of two ciphertexts, it is easy to calculate the original value of block, which contains the key. 19 | -------------------------------------------------------------------------------- /volgactf-quals-2017/transformer/solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | table1 = [2519479749, 882775218, 1423990682, 588921374, 1832875373, 2787014706, 1644446493, 4145957705, 4003550880, 1201359790, 52328806, 3815793521, 3746052287, 2776562778, 2165735275, 2970579843, 1125563752, 376534782, 2526561353, 918384088, 500007583, 3341944108, 2096269325, 1043419796, 3554651348, 3970926008, 2290989021, 48486030, 499483490, 3867123687, 2689685039, 858422008, 2864756522, 1986642315] 5 | 6 | table2 = [657800374, 909907066, 3699292052, 4095130001, 1424314379, 2589740212, 838473182, 2659734325, 2489071715, 2536617442, 726959802, 3382419106, 2547873521, 3083836440, 811431237, 1676056497, 2189369980, 543636498, 3306810483, 3679982497, 816452217, 823515817, 928870791, 1328426388, 410290954, 1225528300, 386220600, 13164700, 1340483833, 3423913261, 535908089, 423076688, 2072682706, 3395541267] 7 | 8 | def encrypt(t1, iv, tid): 9 | left = (t1[0] + iv) & 0xffffffff 10 | right = (t1[1] + tid) & 0xffffffff 11 | 12 | for i in range(1, 0x11): 13 | j = 2 * i 14 | tmp = left ^ right 15 | rol = right & 0x1f 16 | v11 = ((tmp << rol) | (tmp >> (32 - rol))) & 0xffffffff 17 | left = (t1[j] + v11) & 0xffffffff 18 | tmp = left ^ right 19 | rol = left & 0x1f 20 | v12 = ((tmp << rol) | (tmp >> (32 - rol))) & 0xffffffff 21 | right = (t1[j|1] + v12) & 0xffffffff 22 | 23 | return (right << 32) | left 24 | 25 | def decrypt(t, block): 26 | left, right = unpack('2I', block) 27 | for i in range(16, 0, -1): 28 | j = i << 1 29 | v12 = (right + (1 << 32) - t[j|1]) & 0xffffffff 30 | rol = left & 0x1f 31 | tmp = ((v12 >> rol) | (v12 << (32 - rol))) & 0xffffffff 32 | right = tmp ^ left 33 | v11 = (left + (1 << 32) - t[j]) & 0xffffffff 34 | rol = right & 0x1f 35 | tmp = ((v11 >> rol) | (v11 << (32 - rol))) & 0xffffffff 36 | left = tmp ^ right 37 | left = (left + (1 << 32) - t[0]) & 0xffffffff 38 | right = (right + (1 << 32) - t[1]) & 0xffffffff 39 | 40 | return (right << 32) | left 41 | 42 | from struct import unpack, pack 43 | 44 | def enc(name, iv): 45 | with open(name, 'rb') as f: 46 | plain = f.read() 47 | plain = plain + '\x80' 48 | plain = plain + (8 - len(plain) & 7) * '\x00' 49 | plen = len(plain) / 8 50 | res = '' 51 | for i in xrange(plen): 52 | if (i & 3) == 3: 53 | res += plain[i<<3:(i<<3)+8] 54 | continue 55 | key = encrypt(table1, iv, i) 56 | a, b = unpack('2I', plain[i<<3:(i<<3)+8]) 57 | tmp = encrypt(table2, a, b) 58 | # print hex(key), hex(tmp) 59 | res += pack('Q', key ^ tmp) 60 | return res 61 | 62 | def dec(name): 63 | with open(name, 'rb') as f: 64 | iv = unpack('I', f.read(4))[0] 65 | c = f.read() 66 | clen = len(c) / 8 67 | res = '' 68 | for i in range(clen): 69 | if (i & 3) == 3: 70 | res += c[i<<3:(i<<3)+8] 71 | continue 72 | key = encrypt(table1, iv, i) 73 | m = unpack('Q', c[i<<3:(i<<3)+8])[0] ^ key 74 | m = decrypt(table2, pack('Q', m)) 75 | res += pack('Q', m) 76 | return res.rstrip('\x00')[:-1] 77 | 78 | with open('./ciphertext.zip', 'wb+') as f: 79 | f.write(dec('ciphertext.zip.enc')) 80 | -------------------------------------------------------------------------------- /pctf-2018/lcg/lcg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import binascii 3 | import hashlib 4 | import os 5 | import signal 6 | import socketserver 7 | import string 8 | import sys 9 | 10 | from flag import FLAG 11 | 12 | HOST = "127.0.0.1" 13 | PORT = 6051 14 | 15 | N = 128 16 | assert N % 8 == 0 17 | OUTPUT = 32 18 | HIDDEN = N-OUTPUT 19 | TIME = 120 20 | 21 | def gcd(u, v): 22 | while v: 23 | u, v = v, u % v 24 | return abs(u) 25 | 26 | def nextstate(state, mult, inc, modulus): 27 | return (state*mult + inc) % modulus 28 | 29 | def gen_prefix(n): 30 | # can't use random module due to forking :( 31 | alphabet = string.digits+string.ascii_letters 32 | p = os.urandom(n) 33 | return ''.join(alphabet[i % len(alphabet)] for i in p) 34 | 35 | class lcgHandler(socketserver.BaseRequestHandler): 36 | def myrecv(self, n): 37 | x = self.request.recv(1) 38 | if n > 0 and x == b'': 39 | sys.exit(1) 40 | return x 41 | 42 | def recvline(self, limit): 43 | s = b"" 44 | while not s.endswith(b"\n") and len(s) <= limit: 45 | s += self.myrecv(1) 46 | return s 47 | 48 | def handle(self): 49 | # proof of work 50 | ''' 51 | prefix = gen_prefix(10) 52 | self.request.sendall("Give me a string starting with {} of length {} so its sha256sum ends in ffffff.\n".format(prefix, len(prefix)+6).encode('utf8')) 53 | l = self.recvline(len(prefix)+6+1).strip() 54 | if len(l) != len(prefix)+6 or not l.startswith(prefix.encode('utf8')) or hashlib.sha256(l).hexdigest()[-6:] != "ffffff": 55 | self.request.sendall(b"Nope.\n") 56 | return 57 | ''' 58 | 59 | # the good stuff 60 | self.request.sendall("Guess my numbers for the flag! You have {} seconds.\n".format(TIME).encode('utf8')) 61 | 62 | self.MODULUS = int(binascii.hexlify(os.urandom(N // 8)), 16) 63 | self.MULT = 0 64 | self.INC = 0 65 | self.STATE = 0 66 | 67 | while not (1 <= self.MULT < self.MODULUS and gcd(self.MULT, self.MODULUS) == 1): 68 | self.MULT = int(binascii.hexlify(os.urandom(N // 8)), 16) 69 | while not (1 <= self.INC < self.MODULUS and gcd(self.INC, self.MODULUS) == 1): 70 | self.INC = int(binascii.hexlify(os.urandom(N // 8)), 16) 71 | while not (1 <= self.STATE < self.MODULUS): 72 | self.STATE = int(binascii.hexlify(os.urandom(N // 8)), 16) 73 | 74 | # outputs 75 | s = b"" 76 | for i in range(40): 77 | output = self.STATE >> HIDDEN 78 | s += str(output).encode("utf8") + b" " 79 | self.STATE = nextstate(self.STATE, self.MULT, self.INC, self.MODULUS) 80 | self.request.sendall(b"Outputs: " + s + b"\n") 81 | 82 | signal.alarm(TIME) 83 | 84 | # predict 85 | failures = 0 86 | for i in range(200): 87 | l = int(self.recvline(30).strip()) 88 | output = self.STATE >> HIDDEN 89 | if output != l: 90 | self.request.sendall("Nope. (Expected {}.)\n".format(output).encode('utf8')) 91 | failures += 1 92 | if failures >= 5: 93 | self.request.sendall(b"Too many failures. Better luck next time!\n") 94 | return 95 | else: 96 | self.request.sendall(b"Good.\n") 97 | self.STATE = nextstate(self.STATE, self.MULT, self.INC, self.MODULUS) 98 | 99 | self.request.sendall("Congrats! {}\n".format(FLAG).encode('utf8')) 100 | 101 | if __name__ == '__main__': 102 | socketserver.ForkingTCPServer.allow_reuse_address = True 103 | server = socketserver.ForkingTCPServer((HOST, PORT), lcgHandler) 104 | server.serve_forever() 105 | -------------------------------------------------------------------------------- /pctf-2018/lcg/test.sage: -------------------------------------------------------------------------------- 1 | '''https://link.springer.com/chapter/10.1007/11506157_5''' 2 | def pgcd(f, g, n): 3 | gp = Gp(stacksize=1024*1024*512) 4 | gp.set('g','gcd(Mod({},{}),Mod({},{}))'.format(pols[0],n,pols[1],n)) 5 | print gp.get('g') 6 | res = gp('liftall(-Vec(g / Vec(g)[1])[2])') 7 | return int(res) 8 | 9 | from gen import init_test 10 | 11 | # mm, aa, bb, _, test = init_test() 12 | import pickle 13 | with open('lcg_stats') as f: 14 | test = pickle.load(f) 15 | 16 | 17 | cnt = len(test) 18 | x = [] 19 | y = [] 20 | for i in range(cnt-1): 21 | y.append(test[i+1]-test[i]) 22 | # x.append(state[i+1]-state[i]) 23 | # for i in range(cnt-2): 24 | # assert (x[i+1] - a * x[i]) % m == 0 25 | 26 | t = 6 27 | # n = ceil(8*sqrt(t)) 28 | n = 40 - t 29 | bb = float(32 + log(n, 2) + 1) * t / (n - t) 30 | 31 | ys = [] 32 | xs = [] 33 | ym = [] 34 | for i in range(n): 35 | tmp = [0] * n 36 | tmp[i] = 1 37 | ys.append(y[i:i+t]) 38 | # xs.append(x[i:i+t]) 39 | # ym.append([j*K for j in y[i:i+t]]+tmp) 40 | 41 | # xs = matrix(xs) 42 | ys = matrix(ys) 43 | lam = ys.left_kernel().matrix().LLL() 44 | kk = lam.nrows() 45 | # print n, kk, bb 46 | # print lam 47 | 48 | pols = [] 49 | P. = ZZ[] 50 | for sol in lam: 51 | pol = 0 52 | for i, k in enumerate(sol): 53 | pol += k * (z**(i)) 54 | # print pol 55 | pols.append(pol) 56 | # print sol * xs 57 | # print sol * ys 58 | # print '---------' 59 | 60 | rs = [] 61 | for i in range(12): 62 | rs.append(pols[i].resultant(pols[i+1])) 63 | m0 = gcd(rs) 64 | print 'm', m0 65 | # assert mm == m0 66 | m = m0 67 | 68 | # pols = map(lambda i: i.change_ring(Zmod(m0)), pols) 69 | f = pols[0] 70 | g = pols[1] 71 | ms = [] 72 | other_m = 1 73 | tmp = m 74 | while 1: 75 | flag = 1 76 | for i in f.coeffs(): 77 | i = abs(i) 78 | if i in (0, 1): 79 | continue 80 | gcd_res = gcd(i, tmp) 81 | # print 'i', i, gcd_res 82 | if gcd_res == i: 83 | print 'gg', i 84 | ms.append(gcd_res) 85 | other_m *= gcd_res 86 | tmp //= gcd_res 87 | flag = 0 88 | for i in g.coeffs(): 89 | i = abs(i) 90 | if i in (0, 1): 91 | continue 92 | gcd_res = gcd(i, tmp) 93 | # print 'i', i, gcd_res 94 | if gcd_res == i: 95 | print 'gg', i 96 | ms.append(gcd_res) 97 | other_m *= gcd_res 98 | tmp //= gcd_res 99 | flag = 0 100 | # print 'again', flag, tmp 101 | if flag: 102 | break 103 | ms.append(tmp) 104 | 105 | am = [] 106 | for i in ms: 107 | tmpf = f.change_ring(Zmod(i)) 108 | tmpg = g.change_ring(Zmod(i)) 109 | am.append(pgcd(f, g, i)) 110 | print ms 111 | print am 112 | a0 = CRT_list(am, ms) 113 | # assert a0 == aa 114 | print 'a', a0 115 | a = a0 116 | 117 | 118 | num = 39 119 | Y = [i * (2^96) for i in y] 120 | 121 | row = [m] + [0]*(num-1) 122 | mat=[row] 123 | for i in range(1,num): 124 | row = [(a^i)%m] + [0]*(num-1) 125 | row[i] = -1 126 | mat.append(row) 127 | 128 | print len(mat), len(mat[0]) 129 | L = matrix(mat) 130 | 131 | B = L.LLL() 132 | 133 | W1 = B * vector(Y) 134 | W2 = vector([ round(RR(w) / m) * m - w for w in W1 ]) 135 | 136 | Z_ = list(B.solve_right(W2)) 137 | print 'Y', Y[0] 138 | print 'Z', Z_[0] 139 | X_ = list([0]*num) 140 | for i in range(num): 141 | X_[i] = Y[i]+Z_[i] 142 | print 'X', X_[0] 143 | # print 'true', x[0] 144 | 145 | new_test = [i*(2^96) for i in test] 146 | 147 | l = new_test[39] 148 | h = new_test[39] + (1<<96) - 1 149 | for i in range(38, -1, -1): 150 | l -= X_[i] 151 | h -= X_[i] 152 | if l < new_test[i]: 153 | l = new_test[i] 154 | if h > new_test[i] + (1<<96) - 1: 155 | h = new_test[i] + (2^96) - 1 156 | print l, h 157 | for i in X_: 158 | l += i 159 | h += i 160 | s0 = (l + h) / 2 161 | with open('output', 'w') as f: 162 | pickle.dump((int(m), int(a), map(int, X_), int(s0)), f) 163 | -------------------------------------------------------------------------------- /Volga-CTF-Quals-2016/transformer/transformer.py: -------------------------------------------------------------------------------- 1 | set602268 = """c|w{\xf2ko\xc50\x01g+\xfe\xd7\xabv\xca\x82\xc9}\xfaYG\xf0\xad\xd4\xa2\xaf\x9c\xa4r\xc0\xb7\xfd\x93&6?\xf7\xcc4\xa5\xe5\xf1q\xd81\x15\x04\xc7#\xc3\x18\x96\x05\x9a\x07\x12\x80\xe2\xeb\'\xb2u\t\x83,\x1a\x1bnZ\xa0R;\xd6\xb3)\xe3/\x84S\xd1\x00\xed \xfc\xb1[j\xcb\xbe9JLX\xcf\xd0\xef\xaa\xfbCM3\x85E\xf9\x02\x7fP<\x9f\xa8Q\xa3@\x8f\x92\x9d8\xf5\xbc\xb6\xda!\x10\xff\xf3\xd2\xcd\x0c\x13\xec_\x97D\x17\xc4\xa7~=d]\x19s`\x81O\xdc"*\x90\x88F\xee\xb8\x14\xde^\x0b\xdb\xe02:\nI\x06$\\\xc2\xd3\xacb\x91\x95\xe4y\xe7\xc87m\x8d\xd5N\xa9lV\xf4\xeaez\xae\x08\xbax%.\x1c\xa6\xb4\xc6\xe8\xddt\x1fK\xbd\x8b\x8ap>\xb5fH\x03\xf6\x0ea5W\xb9\x86\xc1\x1d\x9e\xe1\xf8\x98\x11i\xd9\x8e\x94\x9b\x1e\x87\xe9\xceU(\xdf\x8c\xa1\x89\r\xbf\xe6BhA\x99-\x0f\xb0T\xbb\x16""" 2 | set602394 = '''\x00\x02\x04\x06\x08\n\x0c\x0e\x10\x12\x14\x16\x18\x1a\x1c\x1e "$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~\x80\x82\x84\x86\x88\x8a\x8c\x8e\x90\x92\x94\x96\x98\x9a\x9c\x9e\xa0\xa2\xa4\xa6\xa8\xaa\xac\xae\xb0\xb2\xb4\xb6\xb8\xba\xbc\xbe\xc0\xc2\xc4\xc6\xc8\xca\xcc\xce\xd0\xd2\xd4\xd6\xd8\xda\xdc\xde\xe0\xe2\xe4\xe6\xe8\xea\xec\xee\xf0\xf2\xf4\xf6\xf8\xfa\xfc\xfe\x1b\x19\x1f\x1d\x13\x11\x17\x15\x0b\t\x0f\r\x03\x01\x07\x05;9?=3175+)/-#!\'%[Y_]SQWUKIOMCAGE{y\x7f}sqwukiomcage\x9b\x99\x9f\x9d\x93\x91\x97\x95\x8b\x89\x8f\x8d\x83\x81\x87\x85\xbb\xb9\xbf\xbd\xb3\xb1\xb7\xb5\xab\xa9\xaf\xad\xa3\xa1\xa7\xa5\xdb\xd9\xdf\xdd\xd3\xd1\xd7\xd5\xcb\xc9\xcf\xcd\xc3\xc1\xc7\xc5\xfb\xf9\xff\xfd\xf3\xf1\xf7\xf5\xeb\xe9\xef\xed\xe3\xe1\xe7\xe5''' 3 | set602494 = '\x00\x03\x06\x05\x0c\x0f\n\t\x18\x1b\x1e\x1d\x14\x17\x12\x1103657412# %&/,)*\x0b\x08\r\x0e\x07\x04\x01\x02\x13\x10\x15\x16\x1f\x1c\x19\x1a' 4 | xor1 = ['= 10: break 60 | mes = f2(mes) 61 | mes = f3(mes) 62 | mes = f1(mes, k) 63 | print ''.join(reversed(mes)).encode('hex') 64 | -------------------------------------------------------------------------------- /0ctf-2017-final/crypto/solve.sage: -------------------------------------------------------------------------------- 1 | from sage.all import * 2 | 3 | ''' 4 | Reference: 5 | https://github.com/mimoo/RSA-and-LLL-attacks 6 | https://gist.github.com/elliptic-shiho/ea5047587ee4e6d4b256a0b10750a8b3 7 | https://gist.github.com/hellman/4b2897a857a5ec91d9ea965d87b795c8 8 | ''' 9 | 10 | def matrix_overview(BB, bound): 11 | for ii in range(BB.dimensions()[0]): 12 | a = ('%02d ' % ii) 13 | for jj in range(BB.dimensions()[1]): 14 | a += ' ' if BB[ii,jj] == 0 else 'X' 15 | if BB.dimensions()[0] < 60: 16 | a += ' ' 17 | if BB[ii, ii] >= bound: 18 | a += '~' 19 | print a 20 | 21 | with open('private.key') as f: 22 | e, d, p1, q1, p2, q2, k1, y1 = eval(f.read()) 23 | 24 | n1 = p1 * q1 25 | n2 = p2 * q2 26 | s1 = p1 + q1 - 1 27 | s2 = p2 + q2 - 1 28 | 29 | assert int(pow(pow(0xdeadbeef, e, n1), d)) == 0xdeadbeef 30 | assert int(pow(pow(0xdeadbeef, e, n2), d)) == 0xdeadbeef 31 | 32 | ne = e.bit_length() 33 | nd = d.bit_length() 34 | n = max(n1.bit_length(), n2.bit_length()) 35 | print '[+]bit length of n: %d\n[+]bit length of e: %d\n[+]bit length of d: %d' % (n, ne, nd) 36 | print '[+]e:', e 37 | print '[+]N1:', n1 38 | print '[+]N2:', n2 39 | # assert 0 40 | 41 | assert k1 < 2^nd and y1 < 2^nd 42 | 43 | a = 2^(n//2) 44 | l1 = matrix([[a, e], [0, n1]]) 45 | l1 = l1.LLL() 46 | print '[+]bit length of l:', map(lambda x: int(x).bit_length(), list(l1[0])+list(l1[1])), "(They should be around %d)" % floor(n*(3/4)) 47 | 48 | v = vector([a*d, 1-k1*s1]) 49 | v_a = l1.solve_left(v) 50 | print '[+]bit length of a:', map(lambda x: int(x).bit_length(), v_a), "(They should be no more than %d)" % ceil(nd-n/4) 51 | 52 | l11 = l1[0][0] 53 | l21 = l1[1][0] 54 | assert l11 % a == 0 and l21 % a == 0 55 | l11 //= a 56 | l21 //= a 57 | 58 | modulus = e * l21 59 | P. = PolynomialRing(ZZ) 60 | pol = x * (n2-y) - e*l11*z + 1 61 | 62 | # Here comes the important part! 63 | mm = 4 64 | tt = 1 65 | XX = 2^nd 66 | YY = 2^((n+1)//2+1) 67 | ZZ_ = 2^ceil(nd-n/4) 68 | assert y1 < XX 69 | assert s2 < YY 70 | assert v_a[0] < ZZ_ 71 | assert (pol(x=y1, y=s2, z=v_a[0])) % modulus == 0 72 | print '[+]roots:', (y1, s2, v_a[0]) 73 | print '[+]modulus:', modulus 74 | 75 | PR. = PolynomialRing(ZZ) 76 | Q = PR.quotient(x*y - 1 - u) 77 | polz = Q(pol).lift() 78 | print '[+]target poly:', polz 79 | 80 | UU = XX*YY - 1 81 | 82 | gg = [] 83 | for kk in range(mm+1): 84 | for ii in range(mm+1-kk): 85 | for jj in range(mm+1-kk-ii): 86 | poly = x^ii * z^jj * polz^kk * modulus^(mm-kk) 87 | gg.append(poly) 88 | 89 | hh = [] 90 | for jj in range(1, tt+1): 91 | for kk in range(floor(mm/tt)*jj, mm+1): 92 | for ll in range(kk+1): 93 | poly = y^jj * z^(kk-ll) * polz^ll * modulus^(mm-ll) 94 | poly = Q(poly).lift() 95 | hh.append(poly) 96 | 97 | monomials = [] 98 | polys = sorted(gg+hh) 99 | for poly in polys: 100 | monomials += poly.monomials() 101 | monomials = sorted(set(monomials)) 102 | print '[+]list of monomials:', monomials 103 | print len(monomials), len(polys) 104 | assert len(monomials) == len(polys) 105 | dim = len(polys) 106 | M = matrix(ZZ, dim) 107 | for ii in xrange(dim): 108 | M[ii, 0] = polys[ii](0, 0, 0, 0) 109 | for jj in xrange(dim): 110 | if monomials[jj] in polys[ii].monomials(): 111 | M[ii, jj] = polys[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU, XX, YY, ZZ_) 112 | matrix_overview(M, dim) 113 | print '' 114 | print '=' * 128 115 | print '' 116 | 117 | B = M.LLL() 118 | matrix_overview(B, dim) 119 | 120 | PS. = PolynomialRing(QQ) 121 | xs, ys, zs = PS.gens() 122 | hs = [] 123 | for ii in range(dim): 124 | pol = 0 125 | for jj in range(dim): 126 | pol += monomials[jj](xs*ys-1, xs, ys, zs) * B[ii, jj] / monomials[jj](UU, XX, YY, ZZ_) 127 | assert pol(xs=y1, ys=s2, zs=v_a[0]) % modulus == 0 128 | if pol(xs=y1, ys=s2, zs=v_a[0]) == 0: 129 | print "Got poly with good root over ZZ. (Vector %d)" % ii 130 | hs.append(pol) 131 | 132 | pset = PS.ideal(hs) 133 | assert pset.dimension() == 0 134 | print "[+]Well done! It's solvable!" 135 | proot = pset.variety()[0] 136 | print "[+]Got root:", proot 137 | print "[+]d should be:", d 138 | dd = (proot['xs'] * (n2 - proot['ys']) + 1) // e 139 | print "[+]what we compute is:", dd 140 | -------------------------------------------------------------------------------- /Volga-CTF-Quals-2016/transformer/solve.py: -------------------------------------------------------------------------------- 1 | set602268 = """c|w{\xf2ko\xc50\x01g+\xfe\xd7\xabv\xca\x82\xc9}\xfaYG\xf0\xad\xd4\xa2\xaf\x9c\xa4r\xc0\xb7\xfd\x93&6?\xf7\xcc4\xa5\xe5\xf1q\xd81\x15\x04\xc7#\xc3\x18\x96\x05\x9a\x07\x12\x80\xe2\xeb\'\xb2u\t\x83,\x1a\x1bnZ\xa0R;\xd6\xb3)\xe3/\x84S\xd1\x00\xed \xfc\xb1[j\xcb\xbe9JLX\xcf\xd0\xef\xaa\xfbCM3\x85E\xf9\x02\x7fP<\x9f\xa8Q\xa3@\x8f\x92\x9d8\xf5\xbc\xb6\xda!\x10\xff\xf3\xd2\xcd\x0c\x13\xec_\x97D\x17\xc4\xa7~=d]\x19s`\x81O\xdc"*\x90\x88F\xee\xb8\x14\xde^\x0b\xdb\xe02:\nI\x06$\\\xc2\xd3\xacb\x91\x95\xe4y\xe7\xc87m\x8d\xd5N\xa9lV\xf4\xeaez\xae\x08\xbax%.\x1c\xa6\xb4\xc6\xe8\xddt\x1fK\xbd\x8b\x8ap>\xb5fH\x03\xf6\x0ea5W\xb9\x86\xc1\x1d\x9e\xe1\xf8\x98\x11i\xd9\x8e\x94\x9b\x1e\x87\xe9\xceU(\xdf\x8c\xa1\x89\r\xbf\xe6BhA\x99-\x0f\xb0T\xbb\x16""" 2 | set602394 = '''\x00\x02\x04\x06\x08\n\x0c\x0e\x10\x12\x14\x16\x18\x1a\x1c\x1e "$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~\x80\x82\x84\x86\x88\x8a\x8c\x8e\x90\x92\x94\x96\x98\x9a\x9c\x9e\xa0\xa2\xa4\xa6\xa8\xaa\xac\xae\xb0\xb2\xb4\xb6\xb8\xba\xbc\xbe\xc0\xc2\xc4\xc6\xc8\xca\xcc\xce\xd0\xd2\xd4\xd6\xd8\xda\xdc\xde\xe0\xe2\xe4\xe6\xe8\xea\xec\xee\xf0\xf2\xf4\xf6\xf8\xfa\xfc\xfe\x1b\x19\x1f\x1d\x13\x11\x17\x15\x0b\t\x0f\r\x03\x01\x07\x05;9?=3175+)/-#!\'%[Y_]SQWUKIOMCAGE{y\x7f}sqwukiomcage\x9b\x99\x9f\x9d\x93\x91\x97\x95\x8b\x89\x8f\x8d\x83\x81\x87\x85\xbb\xb9\xbf\xbd\xb3\xb1\xb7\xb5\xab\xa9\xaf\xad\xa3\xa1\xa7\xa5\xdb\xd9\xdf\xdd\xd3\xd1\xd7\xd5\xcb\xc9\xcf\xcd\xc3\xc1\xc7\xc5\xfb\xf9\xff\xfd\xf3\xf1\xf7\xf5\xeb\xe9\xef\xed\xe3\xe1\xe7\xe5''' 3 | set602494 = '\x00\x03\x06\x05\x0c\x0f\n\t\x18\x1b\x1e\x1d\x14\x17\x12\x1103657412# %&/,)*\x0b\x08\r\x0e\x07\x04\x01\x02\x13\x10\x15\x16\x1f\x1c\x19\x1a' 4 | xor1 = ['