flag ="itf{REDACTED}"defobfuscate(flag): diction ={0:1,1:2,2:3,3:4,4:5} flag = flag[::-1] temp = [] temp.append(ord(flag[0]))for i inrange(1, len(flag)): temp.append(ord(flag[i]) ^ temp[-1]) res = []for i in temp: res.append(i + diction[i %5])return resprint(obfuscate(flag))
Karena kita tahu nilai akhir dari flag yaitu } jadi kita bisa manfaatkan hal tersebut untuk bruteforce per byte. Dengan algoritma yang sama kita bisa bruteforce dan bandingkan dengan hasil enkripsi. Berikut solver yang kami gunakan
import stringres = [126,39,126,32,118,47,33,124,41,77,37,128,30,113,93,58,17,121,28,120,45,87,35,66,119,14,113,30,119]diction ={0:1,1:2,2:3,3:4,4:5}known =ord("}")temp = [known]flag ="}"whilelen(temp)!=len(res):for i in string.printable[:-6]: tmp =ord(i)^temp[-1] tmp2 = tmp + diction[tmp %5]try:if(tmp2==res[len(temp)]): temp.append(tmp) flag += iexceptExceptionas e:breakprint(flag[::-1])
Flag : itf{3asy_obu5c4te_ha_h4_ha__}
encryptor (409 pts)
Description
-
Solution
Diberikan soal sebagai berikut
from pwn import xordefbanner():print("""=======================================welcome to message encryptor/decryptor=======================================choose one of the following options:\033[33m1.) encrypt2.) decrypt\033[37m=======================================""")defenc(flag): enc =b'' enc2 =b''for i inrange(len(flag)): enc +=xor(flag[i].encode(), i)for i inrange(int(len(flag)/2)): enc2 +=chr(enc[i]).encode()if i %5==5elsechr(enc[i] -1).encode() enc2 +=chr(enc[eval(f'-{i+1}')]).encode()open('enc_message.txt', 'wb').write(enc2)defdec(enc):print("Accidently delete the decryption function, can you help me to fix it?")defmain():banner()whileTrue:try: choice =int(input("choose method \033[33m>>>\033[39m "))ifint(choice)==1: msg =input("enter the message: ")iflen(msg)%2!=0:print("encrypted message should be even!")continueenc(msg)print("message encrypted successfully!")exit("=======================================")else: encrypted =open('enc_message.txt', 'rb').read()dec(encrypted)exit("=======================================")exceptValueError:print("invalid input, please input number above")continueexceptKeyboardInterrupt:print("\nbye")exit("=======================================")if__name__=="__main__":main()
Kita bisa mendapatkan nilai flag dengan mengembalikan index flag kembali seperti awal (index setelah di encrypt adalah index 0 , index -1, dst ) . Kemudian tinggal +1 xor dengan index untuk nilai pada index 0 - len(flag)//2 dan xor dengan index saja untuk len(flag)//2 - len(flag). Berikut solver yang kami gunakan
enc ="hXtVcFwK6QcPt~}vVBiha~i}_F`vP#9u~JMaj|"pref =""suff =""for i inrange(0,len(enc),2): pref += enc[i] suff += enc[i+1]dec = pref + suff[::-1]flag =""for i inrange(len(dec)//2): flag +=chr((ord(dec[i])+1)^i)for i inrange(len(dec)//2,len(dec)): flag +=chr((ord(dec[i]))^i)print(flag)
Flag : itf{3asy_chall_5o_you_c4n_get_happier}
valorand (490 pts)
Description
-
Solution
Diberikan soal sebagai berikut
#!/usr/bin/python3from Crypto.Util.number import*import random, os, base64from libnum import grey_codefrom valo import agents, maps, flagLEN =32SECRET = os.urandom(LEN//2)defnext_prime(x): y = x |1whilenotisPrime(y)or y == x: y +=2return ydefthey_are_so_dead(x): a,b,c = x[0],x[1],x[2]for i inrange((LEN <<11)+1): a,b,c =list(map(grey_code, [a,b,c]))return [a,b,c]definvitation_code(x): z = random.getrandbits(x *8)# print(z) rand = z.to_bytes(x, 'little')return rand.hex()classRANDOM:def__init__(self,seed,m): self.seed = seed self.m =next_prime(m) self.a = random.randint(1, m-1) self.c = random.randint(1, m-1)defnext(self): self.seed = (self.seed * self.a + self.c) % self.mreturn self.seeddefencrypt(secret,mod): seed,mod =bytes_to_long(secret),int(mod[:LEN],16) prng =RANDOM(seed, mod) l_rand =they_are_so_dead([prng.next() for _ inrange(3)])return base64.b64encode(b' >//< '.join([long_to_bytes(i) for i in l_rand])).decode()defbanner():print("\n"+"="*15+" Hallo Pemain Satu "+"="*15)print("\n1) Get Invitation Code")print("2) Encrypted Secret")print("3) Guessing for Flag")print("4) I Don't Care\n")whileTrue:try:banner() choose =int(input("> "))if choose ==1:print("Hey mike, Let's play Valorand\n")print(f"Here's my Invitation Code: {invitation_code(LEN)} ")elif choose ==2:print(encrypt(SECRET, invitation_code(LEN)))elif choose ==3:print(SECRET) awikwok =bytes_to_long(SECRET)print(awikwok) idx = awikwok %len(agents)print("\nAs a friend, I'll test you to guess my favourite Agent & Map. Would ya?") ga =input("Your guess (agent): ")if (ga == agents[idx]): idx = (awikwok//(idx+1)) %len(maps) gm =input("Your guess (map): ")if (gm == maps[idx]):print("No way, I bet you can't leaked my Secret haha") gs =input("Secret (in hex): ").strip()if (bytes.fromhex(gs)== SECRET):print(f"Well, I think you deserve this {flag}")exit()else:print("Ohhh damnn so close")exit()else:print("Wrong!")exit()else:print("Wrong!, pffftt ur not my friend")exit()elif choose ==4:print("Understandable, Have a Great Day")exit()else:print("You choose violence huh?!\n")except:break
Untuk nilai getrandbits kita bisa predict, kita hanya perlu mendapatkan 624*32 bits number untuk dapat memprediksi nilai selanjutnya. Untuk grey_code bisa di reverse dengan function dari libnum yaitu rev_grey_code. Untuk class RANDOM merupakan lcg, jadi bisa dicrack untuk nilai nilai multiplier dan incrementnya dengan minimal 3 states yang diketahui. Selanjutnya kita perlu mendapatkan state awal, bisa dengan melakukan modular inverse terhadap nilai multiplier lalu dikalikan dengan state dan disubtract dengan nilai increment (https://stackoverflow.com/questions/2911432/reversible-pseudo-random-sequence-generator) . Setelah dapat nilai secret tinggal lakukan hal yang sama seperti pada soal dan dapat flag. Berikut solver yang kami gunakan
from pwn import*import base64from Crypto.Util.number import*from randcrack import RandCrackfrom libnum import rev_grey_codefrom valo import agents, maps, flagLEN =32defint_from_bytes(xbytes:bytes) ->int:returnint.from_bytes(xbytes, 'little')defdecrypt(ct,mod): seed,mod =bytes_to_long(secret),int(mod[:LEN],16) prng =RANDOM(seed, mod) l_rand =they_are_so_dead([prng.next() for _ inrange(3)])return base64.b64encode(b' >//< '.join([long_to_bytes(i) for i in l_rand])).decode()defrev_they_are_so_dead(x): a,b,c = x[0],x[1],x[2]for i inrange((LEN <<11)+1): a,b,c =list(map(rev_grey_code, [a,b,c]))return [a,b,c]defgcdExtended(a,b): if a ==0:return b,0,1 gcd,x1,y1 =gcdExtended(b%a, a) x = y1 - (b//a) * x1 y = x1 return gcd,x,ydefmodinv(b,n): g, x, _ =gcdExtended(b, n)if g ==1:return x % ndefcrack_unknown_increment(states,modulus,multiplier): increment = (states[1]- states[0]*multiplier) % modulusreturn modulus, multiplier, incrementdefcrack_unknown_multiplier(states,modulus): multiplier = (states[2]- states[1]) *modinv(states[1] - states[0], modulus)% modulusreturncrack_unknown_increment(states, modulus, multiplier)defnext_prime(x): y = x |1whilenotisPrime(y)or y == x: y +=2return yclassRnd:def__init__(self,state,mod,inc,mul): self.x = state self.M = mod self.A = mul self.C = incdefprev(self): ainverse =gcdExtended(self.A, self.M)[1] self.x = (ainverse * ((self.x) - self.C)) % self.Mreturn self.x;rc =RandCrack()# r = process("./chall.py")r =remote("15.235.143.42",24480)r.recvuntil(b"> ")for i inrange(78): r.sendline(b"1") r.recvuntil(b"Code: ") tmp =int_from_bytes(bytes.fromhex(r.recvline().strip().decode()))while tmp >0: rc.submit(tmp % (1<<32)) tmp = tmp >>32r.recvuntil(b"> ")r.sendline(b"2")tmp = base64.b64decode(r.recvline().strip().decode()).split(b' >//< ')l_rand = [bytes_to_long(i)for i in tmp]list_prng =rev_they_are_so_dead(l_rand)z = rc.predict_randrange(0, 115792089237316195423570985008687907853269984665640564039457584007913129639935)rand = z.to_bytes(LEN, 'little')mod = rand.hex()mod =next_prime(int(mod[:LEN],16))mod, mul, inc =crack_unknown_multiplier(list_prng,mod)rnd =Rnd(list_prng[0],mod,inc,mul)SECRET = rnd.prev()awikwok = SECRETidx = awikwok %len(agents)r.recvuntil(b"> ")r.sendline(b"3")r.recvuntil(b"(agent): ")r.sendline(agents[idx].encode())idx = (awikwok//(idx+1)) %len(maps)r.recvuntil(b"(map): ")r.sendline(maps[idx].encode())r.recvuntil(b"(in hex): ")r.sendline(long_to_bytes(SECRET).hex().encode())r.interactive()
Flag : itf{s00000_M4nYyy_Vu1n3r4b1LyTYY_iN_r44nnD00mNe5555}
Regulus (490 pts)
Description
-
Solution
Diberikan soal sebagai berikut
#!/usr/bin/env python3from Crypto.Util.number import*FLAG =open('flag.txt', 'rb').read()defgen_key(e):whileTrue: p =getPrime(1024) q =getPrime(1024)ifGCD(e, p -1)!=1: n = p * q x = (p | q) & (~p |~q)return x, ne =17x, n =gen_key(e)m =bytes_to_long(FLAG)c =pow(m, e, n)print(f"e = {e}")print(f"x = {x}")print(f"n = {n}")print(f"c = {c}")
x adalah p^q , jadi kami menggunakan solver berikut untuk mendapatkan p dan q https://github.com/sliedes/xor_factor/blob/master/xor_factor.py . Selanjutnya karena gcd(e,p-1) != 1 maka seharusnya public exponent menjadi invalid (tidak bisa langsung didapatkan plaintext dengan rsa biasa). Selanjutnya kami cek apakah q-1 relatif prima dengan e atau tidak ternyata iya. Kami coba asumsikan bahwa nilai plaintext < q , jika iya maka cukup menggunakan q saja kita bisa mendapatkan plaintext dan ternyata bisa. Berikut solver yang kami gunakan
#!/usr/bin/env python3import mathimport sysfrom Crypto.Util.number import*defcheck_cong(k,p,q,n,xored=None): kmask = (1<< k) -1 p &= kmask q &= kmask n &= kmask pqm = (p*q) & kmaskreturn pqm == n and (xored isNoneor (p^q) == (xored & kmask))defextend(k,a): kbit =1<< (k-1)assert a < kbityield ayield a | kbitdeffactor(n,p_xor_q): tracked =set([(p, q) for p in [0, 1] for q in [0, 1]ifcheck_cong(1, p, q, n, p_xor_q)]) PRIME_BITS =int(math.ceil(math.log(n, 2)/2)) maxtracked =len(tracked)for k inrange(2, PRIME_BITS+1): newset =set()for tp, tq in tracked:for newp_ inextend(k, tp):for newq_ inextend(k, tq):# Remove symmetry newp, newq =sorted([newp_, newq_])ifcheck_cong(k, newp, newq, n, p_xor_q): newset.add((newp, newq)) tracked = newsetiflen(tracked)> maxtracked: maxtracked =len(tracked)print('Tracked set size: {} (max={})'.format(len(tracked), maxtracked))# go through the tracked set and pick the correct (p, q)for p, q in tracked:if p !=1and p*q == n:return p, qassertFalse,'factors were not in tracked set. Is your p^q correct?'defmain(): n = 22451551366816023348447360202706900510830228629535815632658578221314261064933474109636193729071628012788940344452133851852017366927912454304020151569077485428297287005092834399390331099292171142378091606316748297786818433520789846641672149800540227266293454818259245555037809687786408161265527128130286378132948469437045923528803839460472658089176281722635258117945691238035953639144567185393378025198781483772862757035177291776200594778755058897094464206604922106079336841950344777388210700915854307396511199737299628895177354590685847912303822981430221023684494499862378536004374159141470325183538271583329616455757
p_xor_q =13325746550403466212714844471707212937581458917071528889507316337472192514813105181935336789043645998333195565571097932091147031399645852915634658166184147103093354018188111637363471637779171476786034005445587323443827018127885697909742606323087732854102560044520839819469235327883849488746246247697743171692 e =17 p, q =factor(n, p_xor_q) phi_q = q-1assert(math.gcd(e,q-1)==1)assert(p*q == n) d =inverse(e,phi_q) c = 9047109186695716774493044743719567175241644184089507442584534823490756021179430936117703186628297798259962946105389678055937492529139624918819050121145820040744493946685696954852665988130200490572330390736017156342489807822905818339681033123588313594877193383455078089960731734527174011784218941887134291367527052665464983565114074040366884625418398659288026406454520940740270300118969354963533194264073904597417067604434831121704761033826371763757844708719978440319590584091409656789067656896398639616192828948187752275446654682648902660578332094386655437184555798059618096082012599980495812821602065652614873657083
print("pt < q == ",pow(c,d,q)<q)print(long_to_bytes(pow(c,d,q)))if__name__=='__main__':main()