## INTIGRITY_1337UP_2023 --- ![image](https://hackmd.io/_uploads/B1nDKVv4a.png) Đợt vừa rồi (17 ~ 18/12/2023) team mình có tham gia giải 1337UP mình thấy các crypto challs khá hay và không quá khó nên mình chia sẻ một vài write-ups. --- ### Really Secure Apparently Describtion: ```l! Apparently this encryption is "really secure" and I don't need to worry about sharing the ciphertext, or even these values.. n = 689061037339483636851744871564868379980061151991904073814057216873412583484720768694905841053416938972235588548525570270575285633894975913717130070544407480547826227398039831409929129742007101671851757453656032161443946817685708282221883187089692065998793742064551244403369599965441075497085384181772038720949 e = 98161001623245946455371459972270637048947096740867123960987426843075734419854169415217693040603943985614577854750928453684840929755254248201161248375350238628917413291201125030514500977409961838501076015838508082749034318410808298025858181711613372870289482890074072555265382600388541381732534018133370862587 ``` [Ciphertext](https://ctf.intigriti.io/files/e7e478273a8fa6853d87f71408401b9b/ciphertext?token=eyJ1c2VyX2lkIjoxMDA1LCJ0ZWFtX2lkIjo0MjksImZpbGVfaWQiOjIwfQ.ZVm7Gw.1vUuRfvJ-L4EbdIjZJiidqKCDt8) * Bài này dễ thấy là một RSA encryption cơ bản nhưng ta không thể phân tích $n=p*q$ vì $n$ là một safe prime. Sau một hồi suy nghĩ mình nhận thấy $e$ lớn ($\approx$ $n$) không như các bài khác $=>$ $d$ nhỏ. * Vì vậy mình dùng ~~tool~~ wiener attack trong [link này](https://github.com/orisano/owiener) Solve.py: ```python= from Crypto.Util.number import * from math import gcd import owiener f = open('ciphertexe', 'rb') file = f.readline() ct = file n = 689061037339483636851744871564868379980061151991904073814057216873412583484720768694905841053416938972235588548525570270575285633894975913717130070544407480547826227398039831409929129742007101671851757453656032161443946817685708282221883187089692065998793742064551244403369599965441075497085384181772038720949 e = 98161001623245946455371459972270637048947096740867123960987426843075734419854169415217693040603943985614577854750928453684840929755254248201161248375350238628917413291201125030514500977409961838501076015838508082749034318410808298025858181711613372870289482890074072555265382600388541381732534018133370862587 d = owiener.attack(e, n) #print(d) pt = long_to_bytes(pow(bytes_to_long(ct), d, n)) print(pt) ``` ![Screenshot 2023-11-19 144927](https://hackmd.io/_uploads/B1R7AVDV6.png) **Flag : INTIGRITI{0r_n07_50_53cur3_m4yb3}** ## Keyless > Describtion: > My friend made a new encryption algorithm. Apparently it's so advanced, you don't even need a key! > Chall.py: ```python= def encrypt(message): encrypted_message = "" for char in message: a = (ord(char) * 2) + 10 b = (a ^ 42) + 5 c = (b * 3) - 7 encrypted_char = c ^ 23 encrypted_message += chr(encrypted_char) return encrypted_message flag = "INTIGRITI{REDACTED}" encrypted_flag = encrypt(flag) with open("flag.txt.enc", "w") as file: file.write(encrypted_flag) ``` > Flag.txt: > ``ȽƻLJȽȉƃȽLJȽΑɥćʝʣāʹćʹɱāʝʹɩßʵɷ˧ʹʣāʹʣāééāɃʹć˫éāɃʹćɷɷ΅`` * Bài này thì mình chỉ việc làm ngược lại những gì đã encrypt =)) và kiểm tra xem kí tự ascii có nằm trong khoảng thoả mãn không. Solve.py: ```python= f = open("flag.txt.enc", 'r') import string flag = "" ct = f.readline() for i in ct: c = ord(i)^23 #print(c) b = (c+7)//3 #print(b) a = (b-5)^42 #print(a) d = (a-10)//2 #print(chr(d)) if chr(d) in string.printable: flag += chr(d) print(flag) ``` **Flag : INTIGRITI{m4yb3_4_k3y_w0uld_b3_b3773r_4f73r_4ll}** ## Not So Smooth: > Description: Can you find a and b? > Chall.py: ```python= from Crypto.Util.number import long_to_bytes from Crypto.Util.strxor import strxor from random import randint from flag import FLAG def f(x, n): return (pow(u,n,p)*x + v*(1-pow(u,n,p))*pow(1-u, -1, p)) % p p = 97201997431130462639713476119411091922677381239967611061717766639853376871260165905989218335681560177626304205941143288128749532327607316527719299945637260643711897738116821179208534292854942631428531228316344113303402450588666012800739695018334321748049518585617428717505851025279186520225325765864212731597 u = 14011530787746260724685809284106528245188320623672333581950055679051366424425259006994945665868546765648275822501035229606171697373122374288934559593175958252416643298136731105775907857798815936190074350794406666922357841091849449562922724459876362600203284195621546769313749721476449207319566681142955460891977927184371401451946649848065952527323468939007868874410618846898618148752279316070498097254384228565132693552949206926391461108714034141321700284318834819732949544823937032615318011463993204345644038210938407875147446570896826729265366024224612406740371824999201173579640264979086368843819069035017648357042 v = 16560637729264127314502582188855146263038095275553321912067588804088156431664370603746929023264744622682435376065011098909463163865218610904571775751705336266271206718700427773757241393847274601309127403955317959981271158685681135990095066557078560050980575698278958401980987514566688310172721963092100285717921465575782434632190913355536291988686994429739581469633462010143996998589435537178075521590880467628369030177392034117774853431604525531066071844562073814187461299329339694285509725214674761990940902460186665127466202741989052293452290042871514149972640901432877318075354158973805495004367245286709191395753 w = 30714296289538837760400431621661767909419746909959905820574067592409316977551664652203146506867115455464665524418603262821119202980897986798059489126166547078057148348119365709992892615014626003313040730934533283339617856938614948620116906770806796378275546490794161777851252745862081462799572448648587153412425374338967601487603800379070501278705056791472269999767679535887678042527423534392867454254712641029797659150392148648565421400107500607994226410206105774620083214215531253544274444448346065590895353139670885420838370607181375842930315910289979440845957719622069769102831263579510660283634808483329218819353 a = randint(0, 2**2048) b = randint(0, 2**2048) A = f(w, a) B = f(w, b) key = long_to_bytes(f(B, a))[:len(FLAG)] enc = strxor(FLAG, key) print(f"{A = }") print(f"{B = }") print(f"{enc = }") """ A = 7393401480034113709683683682039780458211722756040975666277858366986963864147091724359492764726999692812421940595309756560491142512219957986281425163574890752574157617546760386852366936945888357800966704941013951530688031419816817272581287237223765833452303447283089906937413964658335387593899889933721262202 B = 6919381992041136573008188094979879971060160509085428532054694712745921654244468113796582501225839242977870949915769181804595896718922228206397860738237256125972615830799470450058633231003927061049289907097099916321068776956652172887225970642896455423957706532253349472544176183473470843719479781727784095989 enc = b'\xcfW\x85\x8d\xedU\xdd\xd9`\x16f\xb8j(\xeb9-\x1b\xb8\x18 0av\xe5\xabK\xc6' """ ``` $$ f(x, n) = u^n*x + v*{\frac{1-u^n}{1-u}} \mod p $$ $$ A = f(w, a) = u^a*w + v*{\frac{1-u^a}{1-u}} \mod p $$ $$ B = f(w, b) = u^b*w + v*{\frac{1-u^b}{1-u}} \mod p $$ $$ key = f(B, a) = u^a*B + v*{\frac{1-u^a}{1-u}} \mod p $$ * Vì $A$ và $key$ có chung $u^{A}$ nên khi ta có thể biểu diễn $key$ theo $A$ cụ thể sau: $$ u^{a} = {\frac{A*(1-u)-v}{w*(1-u)-v}} = {\frac{key*(1-u)-v}{B*(1-u)-v}} $$ * Đến đây mình biểu diễn $key$ theo các tham số đã cho và tính toán $key$ là có flag. Solve.py: ```py= from sage.all import* from Crypto.Util.number import* from Crypto.Util.strxor import strxor A = 7393401480034113709683683682039780458211722756040975666277858366986963864147091724359492764726999692812421940595309756560491142512219957986281425163574890752574157617546760386852366936945888357800966704941013951530688031419816817272581287237223765833452303447283089906937413964658335387593899889933721262202 B = 6919381992041136573008188094979879971060160509085428532054694712745921654244468113796582501225839242977870949915769181804595896718922228206397860738237256125972615830799470450058633231003927061049289907097099916321068776956652172887225970642896455423957706532253349472544176183473470843719479781727784095989 enc = b'\xcfW\x85\x8d\xedU\xdd\xd9`\x16f\xb8j(\xeb9-\x1b\xb8\x18 0av\xe5\xabK\xc6' def f(x, n): return (pow(u,n,p)*x + v*(1-pow(u,n,p))*pow(1-u, -1, p)) % p p = 97201997431130462639713476119411091922677381239967611061717766639853376871260165905989218335681560177626304205941143288128749532327607316527719299945637260643711897738116821179208534292854942631428531228316344113303402450588666012800739695018334321748049518585617428717505851025279186520225325765864212731597 u = 14011530787746260724685809284106528245188320623672333581950055679051366424425259006994945665868546765648275822501035229606171697373122374288934559593175958252416643298136731105775907857798815936190074350794406666922357841091849449562922724459876362600203284195621546769313749721476449207319566681142955460891977927184371401451946649848065952527323468939007868874410618846898618148752279316070498097254384228565132693552949206926391461108714034141321700284318834819732949544823937032615318011463993204345644038210938407875147446570896826729265366024224612406740371824999201173579640264979086368843819069035017648357042 v = 16560637729264127314502582188855146263038095275553321912067588804088156431664370603746929023264744622682435376065011098909463163865218610904571775751705336266271206718700427773757241393847274601309127403955317959981271158685681135990095066557078560050980575698278958401980987514566688310172721963092100285717921465575782434632190913355536291988686994429739581469633462010143996998589435537178075521590880467628369030177392034117774853431604525531066071844562073814187461299329339694285509725214674761990940902460186665127466202741989052293452290042871514149972640901432877318075354158973805495004367245286709191395753 w = 30714296289538837760400431621661767909419746909959905820574067592409316977551664652203146506867115455464665524418603262821119202980897986798059489126166547078057148348119365709992892615014626003313040730934533283339617856938614948620116906770806796378275546490794161777851252745862081462799572448648587153412425374338967601487603800379070501278705056791472269999767679535887678042527423534392867454254712641029797659150392148648565421400107500607994226410206105774620083214215531253544274444448346065590895353139670885420838370607181375842930315910289979440845957719622069769102831263579510660283634808483329218819353 key = (((A*(1-u)-v)*(B*(1-u)-v)*inverse(w*(1-u)-v, p) % p) + v )*inverse(1-u, p) % p #print(long_to_bytes(key)) flag = strxor(enc, long_to_bytes(key)[:len(enc)]) print(flag) ``` **Flag : INTIGRITI{1e863724be1ea6d3e}** ## Share-it(part 1) > Description: > Check out my new cool platform for sharing your thoughts. I used my 1337 crypto skills to craft session tokens 🔐 > app.py: ```python= from flask import Flask, render_template, request, redirect, url_for, make_response from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import os import json import base64 from waitress import serve app = Flask(__name__) key = os.urandom(16) FLAG = os.getenv("FLAG") if not FLAG: FLAG = "FLAG{dummy}" def gen_encrypted_cookie(username): iv = os.urandom(16) cipher = AES.new(key, AES.MODE_CBC, iv=iv) user_dict = {'admin': False, 'username': username} c = cipher.encrypt(pad(json.dumps(user_dict).encode(), 16)) return base64.b64encode(json.dumps({'user_dict': base64.b64encode(c).decode(), 'iv': base64.b64encode(iv).decode()}).encode()).decode() def decrypt_cookie(cookie): cookie_dict = json.loads(base64.b64decode(cookie).decode()) iv = base64.b64decode(cookie_dict['iv'].encode()) cipher = AES.new(key, AES.MODE_CBC, iv=iv) return json.loads(unpad(cipher.decrypt(base64.b64decode(cookie_dict['user_dict'].encode())), 16)) @app.route("/") def index(): cookie = request.cookies.get("token") if cookie == None: return redirect(url_for('register')) else: try: user_dict = decrypt_cookie(cookie) except: return redirect(url_for('register')) return render_template('index.html', username=user_dict['username']) @app.route("/register", methods=['GET', 'POST']) def register(): if request.method == "GET": return render_template("register.html") elif request.method == "POST": username = request.form["username"] if username == None or username == "": return "username must be set", 400 cookie = gen_encrypted_cookie(username) res = make_response(redirect(url_for('index'))) res.set_cookie('token', cookie) return res @app.route("/admin-opinions") def admin(): cookie = request.cookies.get("token") if cookie == None: return redirect(url_for('register')) else: try: user_dict = decrypt_cookie(cookie) except: return redirect(url_for('register')) if not user_dict['admin'] == True: return "<p>Only admins are allowed to read these cool opionons</p>", 403 else: return render_template("admin.html", flag=FLAG) if __name__ == '__main__': print("Starting app...") serve(app, host='0.0.0.0', port='5000') ``` * Cách hoạt động của page này là đăng kí username, gắn **"admin = False"** và encode CBC và trả về cookies của page các giá trị ciphertext & iv * Ta cần phải truyền tham số trên vào cookies của /admin-opinions sao cho khi decrypt thì nhận được "admin = True" khi đó ta mới có flag. * Tuy nhiên, mình có thể chỉnh sửa iv và có thể gửi chung với ciphertext đồng thời có thể thấy rằng "admin = False" nằm ở block đầu của ciphertext $=>$ Đây chính là lổ hổng để ta khai thác CBC bitflipping attack. ![image](https://hackmd.io/_uploads/Sk6UBrP4a.png) * Vì vậy ta chỉ cần sửa sao cho iv_new[-7:-1] khi xor với pt' sẽ thành b'True' Solve.py: ```python= import requests import json from Crypto.Util.number import* from base64 import b64decode, b64encode import base64 from Crypto.Util.Padding import pad, unpad import json from Crypto.Cipher import AES from Crypto.Util.number import* import os key = os.urandom(16) def xor(a:bytes, b:bytes)->bytes: return bytes([i^j for i,j in zip(a,b)]) session = requests.Session() username = "adnDasdadsa" user_dict = {'admin': False, 'username': username} response = session.post("https://shareit.ctf.intigriti.io/register", data={"username": username}) token =json.loads(str((session.cookies.get_dict())).replace("'", '"'))['token'] token = json.loads(b64decode(token).decode()) user_dict = b64decode(token['user_dict']) iv = b64decode(token['iv']) iv_new = iv[:-7] + xor(xor(iv[-7:-1], b' true '), b' false') + iv[-1:] token = b64encode(json.dumps({'user_dict': b64encode(user_dict).decode(), 'iv': b64encode(iv_new).decode()}).encode()).decode() print(token) res = requests.get("https://shareit.ctf.intigriti.io/admin-opinions", cookies={"token":token}).text print(res) ``` **Flag : INTIGRITI{1v_1ike_t0_fl1p_bit5}** ## 1-10 > > Description: One equation, ten unknowns? > Note: flag format is INTIGRITI{[0-9a-f]} > Chall.py: ```python= from random import randint from re import search from flag import FLAG cs = [randint(0, 2**1000) for _ in range(10)] xs = [randint(0, 2**64) for _ in range(10)] xs = [ord(f) + i - (i%1000) for i, f in zip(xs, search("{(.*)}", FLAG).group(1))] print(f"{cs = }") print(f"s = {sum(c*x for c, x in zip(cs, xs))}") ``` * Các giá trị của xs ~ 64 bits $\ll$ 1000 bits ~ cs nên bài này mình dùng LLL latice reduction để tìm lại các hệ số xs. * Ngoài ra mình chú ý rằng $i - i\mod1000 = 1000k$ hay 3 chữ số cuối luôn bằng = 0 $=>$ 3 chữ số cuối của mỗi số chính là ord(f) Solve.py: ```python= from sage.all import * import numpy as np cs = [8508903290440008966939565321248693758153261635170177499193552423579929500027826696702216711413627480472568726828904707392607240309148374882044455682656477650413559779578913981575195542381602155806438946382809049847521263107908111429547314575039079118614485792613461747911710760754291582134293099750060, 10234293217173095983648586990138462404689872504690765936890158736280331352728086141006820545673419953576281340699793983414878095413526583845311613647542879798224462254801103246845064675391113534349390649562211376117941776588135441368773636568930887968431002105334751994385414474789708434897717472259757, 6001064586644974650131784742218587067958465984737568290249286706923485137083921908971767187010824715217158349948368322929900720010489749231105336650564421771867089333709608235963711368415685056362117910529113580811922176651335662802405504434103542105450330213217418470901029864459362153866361049469621, 5859510800336462649673113647904370677448984650623412649303149431740483580968255760095323745895405406649271411277663981671465673293279417168147656423009231087547991428322779036740050269460373254323377738756038706795196225547099530503996157675637620918729310987613041873955654973230573780794437230183289, 8212120161226957435594246142362544687871307206030517377713172267061914524817671684448986080347503212333314134144272096534190656954277299391948626024244379808998220515649968150824587976113971840005858079163744362874678111323034234960076591622752217194796532407435861854992608669653483268713825154541681, 4292538496747452556903766205458518557016170261915268175117554973221631407580344459540989898488936014316805799620957521118332103032738032797936315597220903773140347787977387271254963436603728977128756213671653297994336981775219965231686927050793105808729293803455246360077380768093287937551667515822737, 8583458084429417950887051233123781099671792568724013361916924355046040863544385972858215904752358387759143712618915109914726815547284050405347634520790328222420443989299783668017365846692013464579110450651166600940834254189911732107856656458621485902792541383514622551498513045029193930072821693821256, 927938350277846540058170699346614173130036388369329189433895716040551556863284640834396837739290832786836335265440745786025530973467859153202044442045287145528583412999497854136387626360287750242048999254798532603013016406637079389023297629455299864761196574249382738851682248453939600976884575974199, 4606866838328488359534883828872534448488908284003992208192170511899852596906485417934690617926601159129473558885893097400239110669875450476234618534668886892219546199419412794765402627731086862572263105282498567494065303352715044800789544479262215220148659740517187562922289802434925672447697743660640, 5696622808956926263797513675882969816326582766528835713485415099018508834817057303528828064039948371652175876967703746446602159940653502950606513683435185458750394450192106019388424601807240033502531431423705043713657847236861816929000927218441444067742560786753091009546483807078198791541719979069795] s = 605466527953516222016485516214431809590993588699320208021845670703468281059947406248463347211427615855012720451029976981068579151311047123161756448068506197424807516350675172131826275005312472029312861168498961728971558322943730466676859739724928104907194812943584226111451426124864722285484117269190235012612078303171378 #print(len(cs)) a = [[0 for i in range(11)] for i in range(11)] for i in range(1, 11): for j in range(1, 11): if i==j: a[i][j]=1 a[0] = [s] + cs a = Matrix(a) a = a.T L = a.LLL() ls = np.matrix(L[0]).tolist()[0][1:] flag = '' for i in ls: flag = flag + (chr(int(str(i)[-3:]))) flag = "INTIGRITI{" + flag + '}' print(flag) ``` **Flag = INTIGRITI{3a8a32c7f6}** ---