---
# System prepended metadata

title: Crypto-Freshman Writeup
tags: [NT219 - Mật mã học]

---

# Crypto - Freshman

## Phiphai
> Free Fire la tua game ban sung sinh ton nhieu nguoi choi so 1 vi en
Flag format: W1{A-Za-z0-9_}
Author: dvck13

Source chall:
```python3=
from Crypto.Util.number import *
flag = b'W1{?????????????}'
m = bytes_to_long(flag)
e = 0x10001
p = getPrime(1024)
q = getPrime(1024)
n = p*q
e = 65537
phi = (p-1)*(q-1)
d = pow(e, -1, phi)
hint = p+q
c = pow(m,e,n)
print(f"e={e}")
print(f"d={d}")
print(f"hint={hint}")
print(f"c={c}")
'''
e=65537
d=4504287984018183537713208161402766323065548618393723872837173606374276398491834181934336417310620387990925189536232872881499528612504958202701279049935780903977608853793957819684386053139789777966936156264230499424635837453895019683637553474699470241265384239892304309743522811693909773853204104744746499940669186347989219693819334120860342801601135658920550816397929837218587842050717426094705159184294217221659550021174121437354727563286401517383250923022292331155286641664114777714280910808217996581853423619501922201519238297960634332127751600929842715997073072544823353485994644594610107896462399877655553045761
hint=231925193905919836406214406898885408169720762556845482044575179755202576770665967750292209535638389585617923204488598005919071680696574306168950409350364369661185363429309191455686049593246205245617043129829360203967945465085196018291809693305049028207915207766096530755343783712735226590596701430255772594556
c=6217038084836470023310381029897048208087224587728895918727075557465841714766785434203795384404277685883194699549944699326316064489862857903738642081680285228167738881574533344177255570731527611503589831001734795490242158816621194509455025049486128406587545324515046616431849802141624745659660349892441242897503306780984369111460208907969417056103375189617092555003582813739896435112054576310776891033107119212517760203084951964632014280482552024983115272574743031704179104705817029355755554440364213319205880788661502753344785708858216051846295494426952842154398100557142240912181225765846610290283305931102820798460
'''
```

Ở bài này, là một bài mã hóa RSA cơ bản. Đầu tiên ta có công thức RSA như sau:

![image](https://hackmd.io/_uploads/HkPUvP1Ceg.png)

Với bài trên đã cho $e$, $d$, $c$ và $hint$ với $hint$ = $p$ + $q$

Đầu tiên ta cần tìm được $n$

Ta có:
$phi$ = $(p - 1)$$(q - 1)$ = $pq$ - $(p + q)$ + $1$ = $n$ - $hint$ + $1$

$d = pow(e, -1, phi)$ => $e*d$ = $1 + k*phi$ => $e*d -1$ = $k*phi$
=> $e*d$ = $k * (n - hint + 1)$

Sau đó ta sẽ brute force $k$ và giải mã RSA để tìm flag.

Sau đây là sol script:

```python3=
from Crypto.Util.number import long_to_bytes

e=65537
d=4504287984018183537713208161402766323065548618393723872837173606374276398491834181934336417310620387990925189536232872881499528612504958202701279049935780903977608853793957819684386053139789777966936156264230499424635837453895019683637553474699470241265384239892304309743522811693909773853204104744746499940669186347989219693819334120860342801601135658920550816397929837218587842050717426094705159184294217221659550021174121437354727563286401517383250923022292331155286641664114777714280910808217996581853423619501922201519238297960634332127751600929842715997073072544823353485994644594610107896462399877655553045761
hint=231925193905919836406214406898885408169720762556845482044575179755202576770665967750292209535638389585617923204488598005919071680696574306168950409350364369661185363429309191455686049593246205245617043129829360203967945465085196018291809693305049028207915207766096530755343783712735226590596701430255772594556
c=6217038084836470023310381029897048208087224587728895918727075557465841714766785434203795384404277685883194699549944699326316064489862857903738642081680285228167738881574533344177255570731527611503589831001734795490242158816621194509455025049486128406587545324515046616431849802141624745659660349892441242897503306780984369111460208907969417056103375189617092555003582813739896435112054576310776891033107119212517760203084951964632014280482552024983115272574743031704179104705817029355755554440364213319205880788661502753344785708858216051846295494426952842154398100557142240912181225765846610290283305931102820798460


tmp = d * e - 1
for i in (range(1,100000)):
    if tmp % i == 0:
        phi = tmp // i
        n   = phi + hint - 1 
        m = pow(c,d,n)
        flag = long_to_bytes(m)

        if b'W1{' in flag:
            print(flag)
```

**Flag: W1{phi_phai_la_game_rac_so_1_vn}**

## phiphai2
> Just kidding, I play this game too
Flag Format: W1{A-Za-z0-9_}
Author: dvck13

Source chall:
```python3=
from Crypto.Util.number import *

flag = b'W1{???????????}'
p = getPrime(1024)
q = getPrime(1024)
e = 65537
n = p*q
leak = (p**2+q**2) % n 
ct = pow(bytes_to_long(flag),e, n)
print(f'{n = }')
print(f'{leak = }')
print(f'{ct = }')
'''
n = 20842938351896783351765564497257406689875073939168847270109018452331595953195137925905407574790509131975169442262183423216630782056006817670026102637100795102868553295795605909294220001159170312214938967565708237131119660898946450453038715919305770854433454485282482531591669338374784896696254086081923985254456532726474557269047987653955703675146699130077388795028830171715932232259532178061195603162554212575207799198670246556909810593997402979919324116015029695269687378794139114073155816838415492318483626370434226417328166879349978988600491401399315534138391936796615782306743416152563145103425347897571269559877
leak = 1246889223294307854370712989427585884021285335323141671816486223380713311286629425480810174036551750931478373626071781038942054037291709281118654737087599035092443005799430352628570933778452108536502272580400092528062848455445985692614774855796791907610933670663580901476953467808284328166657791568856558571935788405193538986947393116928493787198798661826785549975721130971676199856446097879499458065034678153636052702160287204920680541565366139294026010089009061274372587986143754097126566624340639998228509117420424679732985956823117206903025894886029533740978018513157416105341714161360196840042575896512731742096
ct = 3088291167300681828911890341254838261507896143994085977627215978594078495952883007565773809797879150841185401282724413230256089706081482055304607098189837372445021022139016449305819308800001848241222118389290692225549475347019810385147707744883436586629808823247373108273012523932858309484832402796522454251129915341722714855738383668651266661352021406899104266596812402238487015961091455318371807234925900608259741913811110018686747303985152505270333578971573169716269092799613880511496142576903738948348527279101539196915559331086705114365249818982213416798535758240324625059044600889754519687795415852504666992830
'''
```

Tiếp tục là một bài RSA, với bài trên đã cho $n$, $ct$ với $ct$ là ciphertext và $leak$ với $leak$ = $p^2$ + $q^2$ $mod\ n$

Ta có cách giải bài này như sau:
```
Đặt tmp = p + q

Ta có:
leak = (p^2 + q^2) mod n 
= ((p + q) ^ 2 - 2*p*q) mod n
= ((p + q) ^ 2 - 2 * n) mod n
= ((p + q) ^ 2) mod n
=> (p + q) ^ 2 = leak + k * n
=> tmp ^ 2 = leak + k * n

phi = (p - 1) * (q - 1) = p * q - (p + q) + 1
=> phi = n - tmp + 1

n = p * q
ct = (flag ^ e) mod n
d = e ^ -1 mod phi
flag = ct ^ d mod n
```

Sau đây là solve script:

```python3=
from Crypto.Util.number import *
from math import isqrt

n = 20842938351896783351765564497257406689875073939168847270109018452331595953195137925905407574790509131975169442262183423216630782056006817670026102637100795102868553295795605909294220001159170312214938967565708237131119660898946450453038715919305770854433454485282482531591669338374784896696254086081923985254456532726474557269047987653955703675146699130077388795028830171715932232259532178061195603162554212575207799198670246556909810593997402979919324116015029695269687378794139114073155816838415492318483626370434226417328166879349978988600491401399315534138391936796615782306743416152563145103425347897571269559877
leak = 1246889223294307854370712989427585884021285335323141671816486223380713311286629425480810174036551750931478373626071781038942054037291709281118654737087599035092443005799430352628570933778452108536502272580400092528062848455445985692614774855796791907610933670663580901476953467808284328166657791568856558571935788405193538986947393116928493787198798661826785549975721130971676199856446097879499458065034678153636052702160287204920680541565366139294026010089009061274372587986143754097126566624340639998228509117420424679732985956823117206903025894886029533740978018513157416105341714161360196840042575896512731742096
ct = 3088291167300681828911890341254838261507896143994085977627215978594078495952883007565773809797879150841185401282724413230256089706081482055304607098189837372445021022139016449305819308800001848241222118389290692225549475347019810385147707744883436586629808823247373108273012523932858309484832402796522454251129915341722714855738383668651266661352021406899104266596812402238487015961091455318371807234925900608259741913811110018686747303985152505270333578971573169716269092799613880511496142576903738948348527279101539196915559331086705114365249818982213416798535758240324625059044600889754519687795415852504666992830
e = 65537

for i in range(1,100000):
    tmp = int(isqrt(leak + i * n))
    phi = n - tmp + 1
    d = pow(e,-1,phi)
    flag = long_to_bytes(pow(ct,d,n))

    if b'W1{' in flag:
        print(flag)
        break
```

**FLag: W1{i_hope_you_like_this_one}**

## Vi-et
> Vi-et is easy to cook!
Author: Nhan_laptop

Source chall:
```python3=
import sympy as sp
import random 
from Crypto.Util.number import * 
a = getPrime(128)
b = getPrime(128)
c = getPrime(128)
x,y,z = sp.symbols('x y z')

print(f'a * b * c = {a*b*c}')
print(f'a + b + c = {a+b+c}')
print(f'a*b + b*c + c*a = {a*b + b*c + c*a}')

flag = f'W1{{{123*a  + 456*b + 789*c}}}'
"""
a * b * c = 15864378984956659850534060107405422568891641699308509134070157505662198692417476378386001170963905568690006431674713
a + b + c = 779122598205443694565344617967399722167
a*b + b*c + c*a = 196487786916397904192643381759626074607590751745631772329891131596526673844879
"""
```

Ta cần tìm a,b,c khi đã biết $a+b+c$, $a*b*c$, $a*b + b*c + c*a$

Với bài trên, ta áp dụng định lý Vi-et ngược để giải, ta có định lý đó như sau:
![image](https://hackmd.io/_uploads/Sk33cDyRle.png)

Sử dụng thư viện `sympy` có sẵn trên python để giải hệ phương trình và tìm nghiệm.

Sau đây là solve script:
```python3=
from sympy import symbols, Eq, solve

a, b, c = symbols('a b c')

plus = Eq(a + b + c, 779122598205443694565344617967399722167)
plus_mul = Eq(a*b + b*c + c*a, 196487786916397904192643381759626074607590751745631772329891131596526673844879)
mul = Eq(a*b*c, 15864378984956659850534060107405422568891641699308509134070157505662198692417476378386001170963905568690006431674713)

ans = solve((plus, plus_mul, mul))

print(ans)
```

Code trên in ra như sau:
```
[{a: 173765774214092292255311904274089510307, b: 284881463704823367455830769292310355251, c: 320475360286528034854201944400999856609}, {a: 173765774214092292255311904274089510307, b: 320475360286528034854201944400999856609, c: 284881463704823367455830769292310355251}, {a: 284881463704823367455830769292310355251, b: 173765774214092292255311904274089510307, c: 320475360286528034854201944400999856609}, {a: 284881463704823367455830769292310355251, b: 320475360286528034854201944400999856609, c: 173765774214092292255311904274089510307}, {a: 320475360286528034854201944400999856609, b: 173765774214092292255311904274089510307, c: 284881463704823367455830769292310355251}, {a: 320475360286528034854201944400999856609, b: 284881463704823367455830769292310355251, c: 173765774214092292255311904274089510307}]
```

Vậy ta tìm được 3 số:
```
173765774214092292255311904274089510307
284881463704823367455830769292310355251
320475360286528034854201944400999856609
```

Thử 6 hoán vị để ghép vào a, b, c và có flag.

**Flag: W1{318278380181268876680024363742066731941800}**

## Baby Crypto
> Since I was a child, I have always been curious about three strange things:
> 
> 1. The number 13 is a prime number but there is a meaning behind it that I do not know...
> 2. Why can a mysterious string of characters lead me to a secret video?
> 3. Why does a world exist where the myth: 1+1=0 happens?
That journey of discovery turned into an adventure, opening the door between mathematics and virtual reality.
Oh yeah, I forgot to give you the mysterious string of characters:
XmoUNb2=|CcXxL#d2e-ebz)^MV{dIQcVTp6Xg_v6WKnlCcR5#QSYuH
Author: R1muru

Source chall:
```python3=
#!/usr/bin/env python3
import os

message = '???'
FLAG = open("flag.txt").read().encode()
assert FLAG in message


def cauhoi1(text: bytes) -> bytes:
    return ???

def cauhoi2(text: bytes) -> bytes:
    return ???

def cauhoi3(a: bytes, b: bytes) -> bytes:
    return ???

    
enc = cauhoi1(message.encode())
weird = cauhoi2(enc)
key1, key2, key3 = [os.urandom(len(weird)) for _ in range(3)]

ct1 = cauhoi3(weird, key1)
ct2 = cauhoi3(key1, key2)
ct3 = cauhoi3(key2, key3)


with open("output.txt", "w") as o:
    o.write(f'ct1: {ct1.hex()}\nct2: {ct2.hex()}\nct3: {ct3.hex()}\n')
    # I will give you a chance with my last key :D
    o.write(f'key3: {key3.hex()}')

#ct1: 944073d9c2fdec4334375867fcd9b0c4545d20152151f6d008259a14ea339e4e0a38167ea99fd4817b4e22565772b28c5b6781c67bf16c0c4f4e0efdeaf21f0a5a7e96bff3e8a39008788fd8256c2b522c6d9b446a29e456dee859f536ba1241e5df09a25ea1abf820ab0358c554afaadf371e02b2dc6f949da28f539b4d9845d962a9899280c2301b8be293c69a241d8e39059e9fbf3fe3772b0500505867df29e4afacd12578114bbb48d17ebf9779d784d05e2479dfccc072c814a1b4d6d8286da2d553b1726a5f2590a9d80604fc7038bb6f2f3999f23d4e37626760d4035fb8cc10bdc66ea4b0a8b9a82283c1a1680f0ca91c226ee2a1af6e8dbd03b5d47c88d6e90f5505f02f7e4e5c03c3cd2ba4e66e2049ec32b4032aae025a9065dec4744aef76926beefe5f7a560a3d82e0c603348081889bcf4ec751be9b899cb23a0c117d8c15b0c9e7e217f92f024d8ed2c028e36eb5bbdc332f04981bf05226ab15dda261e569e8869b97228021c84f454d18570a6120dc40d30679154997b91d1398ef2dd166fa64ee1169c550f506013a327c34889eb0b172878f356ec042d3a22c52a3ed99536fbd6f6f1c2058f25c2314adf4190782e542644af809fd80728c7bfd9a53016565615f1cbe323ea5057679ffd8cdaaa29ea41cb3df37aecbb669e0339bbc52ab3885bbb7eef8273f5dbfeeca6d96efda197004473fe41ba54b1a898f0f30f3ec0b253b8d3555ae0a7948d74b2f083c3cf26035f9b97819124dd930c2747950bf0d6d35e7d82a7f8d3f0a7c8ef012b6926efea881d877e9acbf16a883a98d292193fcbf332cc8a5b6b732abc3cbff2e9e19531053759cae090eaf90b7b8357c9351aeacb13c4c03b1fbf8eea7a35ce1ee793f530eae06e55fe536d0ec0c5a4e70a4f6735a240ac0e38713d14ffa32c88927908b3f273febc81e268fe4a6473f8f0e3fca74c436e08e1f1b3690d0b41b29a519bdf7ba78e6fd0dc915dc78609eaf16c4cedc3a71c406b2bbfb0bfe6d86e9e2e00d6f7a1dc8be264751cf3e84bf58cd266b3f33e0948df9d5fcee3b1405192c5401d0bd3b97839260165935e254d64cbf4a2ea318bfe17fcf241f082e8b0ec78dc68369b02d1e1d9900184fe3b62bf56cc4ed66c0dccd433beb8585295cd478d3216eea43f258da09e7011549d9235e4763c57f46e985b6f2e9561157688e266e67b35e1ee8180c00d26b14cea81417b6244175d48d2381364d4fee04df5ea1aadacc07653f1e4857550648644dd62924caa4bf6d9df4cf2fb66e4b4287de8bcbb4fa45d06c1f54256e34639b2ec6cb8e9c9bbb0ad655b6e65c4372688ccf44e65f263f2b677f800e5b4a9464c611e51c1ad31637b7933313bd73e037e0a738ef0d782427a0b56c255dc9e1febf42ed6cbefc27f138aaf00336992a2e970d597bd037f05ff6cc92477a3528c5daaf6bd3c8d47c67ed6f91a4348ea43125352f34842843bb467220097384291a43b098a6c41611041fbfa9900a7733129710436da9c991a08c50eba4ebb7b22165a111cadbb0c86f6448f574857b561fa0813528ae886ad0e80192b53c21c831a317e7f2fea1521f8b3e237b79e40245feac47ae9a8d99fd1ee8f11aaaf8cc6fd7b1a066ae9299b210c55b7651b2052a4be88fd1eb3a85f515adb388d504507236464ef0c83151001e0035b6e55de0bd5091305cca1002de0d4b0fe920ddad16232d0cf82e0c7588399bad23a3bfdbcdda2fdaa532c2f421bc25480e395f5db0d724748b3751156c29348494c88d4fbc75b6a9997dd714a66228f1099f2d36ecab036d77728183c704beae2cfb594dd8484c0d2b299626e1413a584fef756c73945200f16cf05b79568dc94b56dab9569adcdd000d55aa04b35115ec11ba53bd8a05e576d5956b4df9170b6e65c9849a6204fb62c98ef2b8d3d138f95d0335180831ebee7f5583e737c4782895f082defaae68775825a2ab34403347261a6fd497ee7a9eadf050e9954a01b173aaf5e9a21a03d66f
#ct2: 770178bcb4c79bb17a3e9d3fae37aff128817b9528af0fd6ba9b35638095318ca7c640c7b5f4ca9dd5621472887287fc07d9bdeea79c6c68d059cc3e497c036e8fbf6b9ed480d3b4be6069dd834c6a9a162ba2a879cdf7286697670c9d299086e79844760caff21366ebf507d59fe40a0a59fca4df49fb306937faeb4d3b6ad266c2def5b5d78ef5cb6fd66a2e4cbe251d54e71478f539a82683d7f403e583bddcd0db7bf992c6dc1d50de5066c209bf14995e92b0383437719e3f93ccbc9eda83674d770d7d29b182e7fe3f1b791de8231645dfd3c258ae65fec2e1f1e9693c4f138b3b3c714385285fe25c7ab1a7c77c64c974e003c2d0ca4c144f7a6ebeba7d556aefe0929658b96b9252e7c3682a611915583da9c20ca84d3ef1b551f41c5f2adfb76970f8653342064587693dba7318d8118dd1f31ef27f22caad90c1f9145d71074fed2d81928c29d077ad92b679fe8d79ded8c62ca8bf53218df5439b1a81d6f21df99e0432c67f6002a0155b82f0f6953b6c5a5324df90333fe1c731f792e3f27fdc09047b13de99fcc1763cd1fe7a0587becbbf2ce09b9897c6325258450055c49bcf3506db1a2b055f7a029e99f1343888d8d8fa4a84be11ca1f5b85ffbf00b96dc61d05db4b446eba1a53aae9bdbac981d7046ca3158e67cf7e3f9c357fea73718d61da1e0fe42a4e4f10490495deee5174f02326b591b7dbf8d0e52841faf4da6b469d250f65ed794f08c438307752ab5368db551da6aba167bbf3ddb34e54f4ce725512721343714338901492fa298db176449277011ae92d252a7a9c5aac970dfd004329fdb2b0ca7a6d543ee133ed5a3d31e0a1b15a07cb366a25d5569eb124d74237604688fabc5bdec532ef76825d8592e910f6e59b843e8487605e0d823af50b0dea4bd199a9e52818fd90de3194fc0c9e3d30de743301a154cf08e40068234acdc8b4e5b39ca8f0053439db32b029ecc44b74998635d433eaf174b5946715e5ffdb21e3315f3a412c7e2b6ff53832befd256164ef47697dece91de9e7bc2d0095bde64422ef708223d6c0e59f0e0762197d59846b0c9f3060edc4cabc79e01acc72c8580af50b959b2436dde3753fa316cfd9a789facb770c3afdf04a183e897ff5b5b8366f8c3092b1d1ab0975c0f83b0a1da0a1e105cc067339bdee25f82d9a5e02d8ce593691e370e1ca297849e9e932d0773590a61a4ff645b468ad0d9fc0d1899e2ff5aa168d61fda073792e33c50f4a566385b87566afc14449b4fb9ac662a0f9267a872565f6e3458c24999c3972524c7015ad02ed24d93268d362b32ea6f6ea00ebabbae9968cab114f8f835a03802850951f5c16c5446d5f2910b1e72618e453b21e132b2275608471915271e019efc6324a88af1ec0a2c0840f676c64636ac7e8801f67befe418557956f9fb8274031392cb121b5f73434f30436a486f13cb36e39a9ee3bef53a1acbb90340755c2a06a6f1c21fb9f9ac3e520e20a90b952378d2759ae789ab26acbed14fab5d2d5c40e420a356c7ff0050d7368efd10cea07d9a1d7eeecc91ce13a066c93690a513d3cc7b1bbd468575aeb7b3563d60b82613b9ae50c5df8f26ae5bfe84677cc54898d504644e5b423ba47b507b30d495dbaa2e5f87f780be3b9562c1bfe1a1f79d828c4867274d2b5b31ef750f965d4a84dbadef33871e435d61425578fec1f1f6651d615fde35697e31162658239110e4b0ccf1d05e50ac275a82ddc8f7920dda8021f7c14e36692eeba0f2421151f3496566e2e176c6a4d89058d19479b89e043e1e4bb63f892c9134a5100a3b574afa9f7e6c6688e71ad3038c37587a6efb417e0473e06e14ad083b825c7f1caf0e9e61003da38fe526e421e1abad336ffe81fa166d7ff8714bb1972547f08e0cbb80355387f87ffcea8219f96a108f71e1474b68fd46dfda7bcfe899b9e752f7dbc68cf252f31a68435165de7748460b86341f6e3b10d6f5c3f7e6e813fa5ef538380914e127f21f728e0eb3370597c
#ct3: 9a1019a263bf5c2b7473e7afe4c447db8b621e1b68ff78306e2a9f179b0cd3cacc544c3dbf8051f4d4e8bd9f921d07a6a757016bacfcf5075e895f7076303f845a2e7b6971184040cd98d6ceb90ce321afc89374230910051da77a080f544bf0f2c59dade7cb76d055763a9759ef7063d603012e2e525a7801d7928cdf68346883580415447e297107822d298b21522c472a9828b19667dd83cd3250a656f0976a320c35af7660b40900a6b714d6d531a63ea20c1c1982a959d87fe5fc502a0932a688c4530ebb9abb5d696fb8f29eaefdbdd5683d44c3438418c3c8469345fbdb2de1c230c5d36a0aba17fb671dd5b952903e314cdbf467263feedfa1c470879a91b2008600af5f7b69004a34ac6274e4484ea383caf910be86dfa19c43a38518254a04699a54c5718363e9c2a16e56d91bb4e2373069fd9934bfef2b853a79554f57ea4a7c8f199853122df8e556c0b4cb51894c0f5a232555242d2e48ec554bbdadaf5b4baa2cb6cbefe4463422fad383723f9757ad71fd594dbc984a54939b37c19634e62cf10f859e2a712ec603c15bff5526ab6248be1f118c5afa84181d067e4e9f1c0176a2753880634c148518c169a3aa695f12b68d54c4a9f8f976d3a6b0420ac0a39d51638c71199d87b5f185fdc4298247dced58026e3f9ab79424ebda18e8053d5e508f66137fa632b9a5dcd4a25e4d9c5bda508ea9d1a2afb01511387e3b5d3f985e6ac97c7cb8614b316d3a3838acdd808c23d25c19cfd2116cecbda92cae83deb555c8ae8cc983aac571c9e4365a0c0d077a401df2bb8596f7d457f093367b0e49a1a11e79c7723d20a9e4b54d535a945e958323c4d39b648fd314dbb4afafad01c5504cc860f891f89d60a4d87dd90e53b89192bacc0a935c3253dc5f8454f776305d418734b3d5e4c71b6dabcc3230141f2e92129f415ccab55e1d81f07ea8709b008026001d994dad50cb1583a3b141e0a9fa5a2fb20b82558f04090f889b7f9bec4a5055a5f3ef60b278f5fc2c6ed8c51f826b9cc5be88cf667d8f7394342a7735b65001c766ec62f0a94970d90cf94d4d53f6ad8d273f2c6163390321578b2835e396072b6cbf7876e46e24c14a821b85a5be90b34147f0d8e553e361709c7871dda118dac4e1a11b254fe6eaeec628289e6a6fad2d1382c6602dd92b5026a123b1a6d972d9c4000c480574ce1c2c45e33c5437d469857a427964e05ec79ade151943ab01c33bc6e4eff64d81515851f08b3ba64854683217595397161173a47e5de056b290dc47324c68fa47ce7a53c19048d72b549bfa70f2d9f8e06e3d27214be154f9668b02bfcf69576c15ce42e6736e4dff74a21f3754ff7e4ad396132435f19ae605dbdbffba84f99898ca7fb51055af2093658eab899a06318a0e30b01c3b731df1f22751bbce2db6f2a1bd695b386b42203327fb51fddfc616c838f046e6aa6af7149335b43460d6e578eac6c0d3950c3577957ada59d1a68bf12b652a4bdde7cc7dbe304f3e608dd0581439394c3f3e73bb79ef288bdda8d7bc6d2f4b1d31997e320005a92426ea75264fce6fcfd256a17290cac2a62c29dfbfe7e9b0c31ce48643612a949277ac98b6403cd94a99a5c187067562f63377bf7819fa3f0a626dd9d3d53238e60b2603d5cf9ec83ef5c028841799fa11e213c43a549aa1916ad48b27bbd894a7a4825ad2cbf25cec2dacb1da3a22b916a5f2988c17c624f7100d8c9fe6331c3c04f81653798935dfb231ff2802cd8d01700f17e77fbb794dffd6bec64fb8158202f2b989d8a6df2d5970b83f75c9ea6d4b372069254d4bbb926db3cc2758c5a95e573a9af016ace085db954561900a867490a99df789435589bc471936e159521daea5e4a5a90fc37f657cb5c694ff39fa35ae59f45dad5088e923319caa5afd9c46d974a498d339c6b05cd06d07cdda7648d60c6153b452c734e4935cbb3bcf22b3433a8dcca328bc147e697cadd0bd2ff0d0f4c93bf17af2df0ff4a36808f9cc2f6f838518
#key3: 2b753a867adf4ee6123c63a3da5960a6d6f272bf0322e747bff70403bfd43d522ae42ce795840ebc3ba5e28a7b5c689dd6b87c2251ad9d01e5d3b5d08fdb46a7bc8ec51c753568284ffe7d995e5cd998f4dbcfbd6e8c250e989714b99588a176a8d8e50bec8d41485261bca97f7461a53332a6c91abfebe2a3289e66487fb0d7158f122a0f5726eeb25a79eb399f8b409a0620ce369236c9964ea3e1ded237b0fe230191c696814c10a9716c60820ab63f611bf9ea7b096f8075d229bc153a48c8fb20276c85a00731c032ba37ccd1ca8ae648a086cf4348b4f201018745bcef88c38dd0c245a675e565796c601c9b9527debed789987b3c688df53b07e336bff1354b3d3e8756bba71fe8279bf2901a18826bb9c7cd48fa7497656527e3560cea33892d0721f72d89fe3e9818858b4552410231122f600969b0aec134f641732d6f43c0b8dc7e69a2466d5dd86fbdbf249b9b63aa2854b982a750a3c378bcbfdc43d1a76b63308d43f726c893f49dab576dff84c372b3a6d304a58dd0c1626b4dd79ffb0bd202575852248c19c80d1072ab8a51c1d25c6655f943d69274046ba3c03e00b90b1f6191707bbc29665427b931b57b07c0cf11f1c9e37b116351d859e2108d019b01a46b92d66ca856ce2f13786be209f75e2f26304a0beb57301e6f9107ff519f8dad84508410c72364cefd30e4e787a04152a8434f3d69cd09aaf507a6538b9ad9518932aff7e4f5f663e74c9c5e0e22e395c47fd1606943ebd382ae0103294f7c71a440c0145ad0eb4f27300dbb959537bc7963d9f37c0c327e3a915f77c40877939b5851a5bef25ca780a84ccef204654e20547d92b51f992ec8600610ec65ceb15e68f1c61fe36a2f8fc1e98b4aec24328b4db20b877807b35ce79524321d7820baf3930e238f939211871ae3ce955c2a7746d8afade9cfe61fb127a69cf3583c753f45737de444fcf48c04136d7d29f05074360718a74816992e0fdcff8a307be089b8f6e82d6e9b46917e2c5125f394fdbd55bb3044770886039df83c23de68ad85b9116681e4f7d2f0ebd1e68f842ef65a7af782a5556be66acd8e91033a37ac673a7937705dfd1174359d80af5e0dccb1de9b259e27fe4c13c841a11de51bd25817eb129736d2cd4c3049209c88d717815bb77eaedf5540fa6300c11291d2032e2e173433e10ab545c2bfec4de29a82efe30b2b6ddd8fad574531b5170daf39c2dbb398693e37e548eb05f0636e72b36d477e4fc2a2a57f7da6ca08909262871cb365dd2c37d3745413960978a7db2cf72c553c20789ba26d6078be4754ab07b82c6fe833edcdd3694741c163ce7175a6f0b43b686d421f64ef084904ffe0f0ab7ccd4a8cb1c99a8a518a451371d0e1807d32c906d65fea33a5e3ed0a6c89e00323f12012e0902b1bbdefcdec190bb37d317ad26dbea94a006dbadf19b9ede96b8001f41da3986d8e57bfba946d43bd8d12972fa468492ff69b95ab527d69c8c66bce25a9227ef3b575c3995abb6659d1775130399f072ba53f8fb79cf166f03a4096692a4ee126f959691689268636b851bba66cc3061ce267a6661d4bf54e3e846a51520467ea582ade3a139af556f09bc9f985575c4035036f41aecdce899d2eace709ebc40d8854ea21ee4f890c8a49c995a8a73682890a6d8579621d05110b250c6b4402b7443d753dae85a2805a950a89b0c47c874bdd474f0ff3e4ba3ba571e198798f10f24ae84491cc5b1211f58ea07ec9a3314b76e1a945075de2b3d9012d5fe2c93d8d46b9ce72e3c1536e23d8b19dbf48147bdb73d8f58c3940b0dcccd8d1a9bcc3165da911fa13c5a038aa9f101e3bb01a6db3564afe83943ba24901d3749b9e7e2f13b7c4391922d93dbfe8d92726793f8f676c87099ab1f0ce5190f98c7c6a1f12762b8571e9195df6c460b97b9e5854baf40a04e0f24f28ad6de50d0faf31f623c61552ac5249472b921fd9178c96c667a5cfc4fb48e9c3c10e66f1f69e43b43a542c44820572c26c69
```


Ở câu hỏi 3, 1+1 = 0 có vẻ đó là phép xor.

Ta biết được ct1, ct2, ct3 và key3.

Mà 
ct1 = cauhoi3(weird, key1)
ct2 = cauhoi3(key1, key2)
ct3 = cauhoi3(key2, key3)

Nếu `cauhoi3` thật sự là phép xor => $weird = key3\ xor\ ct1\ xor\ ct2\ xor\ ct3$
Ở câu hỏi 2, khi ném đoạn secret đấy lên cyberchef thì nó đã phát hiện ra là base85 và nó decode ra được 1 đường link
Ở câu hỏi 1, số 13 đó có vẻ là ROT13.

Sau khi thử thì ta tìm ra được flag.
![image](https://hackmd.io/_uploads/r1Y1HOyAle.png)

**Flag: W1{D1d_y0U_GeT_r1Ck_r0lL3d?}**

## Sor Sor Sor
> Let's begin with an easy XOR challenge.
Format flag: W1{A-Za-z0-9_}
Author: L1ttl3

Source chall:
```python3=
import random

with open('flag.txt', 'rb') as f:
    flag = f.read().strip()

assert len(flag) % 3 == 0

def xor(a, b):
    return bytes(x ^ y for x, y in zip(a, b))

blocks = [flag[i:i+3] for i in range(0, len(flag), 3)]
ori_blocks = [flag[i:i+3] for i in range(0, len(flag), 3)]

random.shuffle(blocks)

assert all(ori_blocks[i] != blocks[i] for i in range(len(blocks)))

print(xor(b''.join(blocks), flag).hex())
# 2f01090a6f042b4447101f0047460d6e0e5d001100422d156443022c4a3e074a392b033e531d1b47401b44423c411e08
```

Bài này chia flag thành các block, mỗi block dài 3 bytes sau đó xáo trộn rồi xor lại với flag ban đầu. Để khôi phục lại, đầu tiên ta biết được format flag là `W1{` dựa trên nó, ta sẽ bruteforce ngược lại lần lượt các block bằng thuật toán backtrack.

Solve script:

```python3=
import re
from itertools import product

h = "2f01090a6f042b4447101f0047460d6e0e5d001100422d156443022c4a3e074a392b033e531d1b47401b44423c411e08"
ct = bytes.fromhex(h)
A  = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_"
X  = lambda a,b: bytes(i^j for i,j in zip(a,b))

C = [ct[i:i+3] for i in range(0,len(ct),3)]
m = len(C)

T = [None]*m                # plaintext blocks
P = [-1]*m                  # pi
R = [-1]*m                  # inverse
T[0] = b"W1{"

BRE = re.compile(br'^[0-9A-Za-z{}_]{3}$')
FRE = re.compile(br'^W1\{[0-9A-Za-z_]*\}$')

def ok(b,i):
    if not BRE.fullmatch(b): return False
    if b.find(b'{')!=-1 and i!=0:    return False
    if b.find(b'}')!=-1 and i!=m-1:  return False
    return True

sol = []

def dfs():
    # expand edges i->t where T[i] known but P[i] unknown
    for i in range(m):
        if T[i] is not None and P[i]==-1:
            v = X(T[i], C[i])
            for t in range(m):
                if t==i or (R[t] not in (-1,i)):    continue
                if T[t] is not None and T[t]!=v:    continue
                if not ok(v,t):                     continue
                old = (T[t], P[i], R[t])
                T[t]; P[i]; R[t]
                T[t], P[i], R[t] = v, t, i
                dfs()
                T[t], P[i], R[t] = old
            return

    # place a fresh plaintext block if any None
    if None in T:
        j = T.index(None)
        last = [ord('}')] if j==m-1 else list(A)
        for a,b,d in product(A, A, last):
            blk = bytes((a,b,d))
            if not ok(blk,j):            continue
            v = X(blk, C[j])
            if not BRE.fullmatch(v) or b'{' in v:  continue
            T[j] = blk
            dfs()
            T[j] = None
        return

    # all filled: final checks
    if not FRE.fullmatch(b"".join(T)): return
    for i in range(m):
        if P[i] in (-1,i) or X(T[P[i]], T[i])!=C[i]: return
    sol.append(b"".join(T))

dfs()
print(len(sol))
for s in sol: print(s)
```

![image](https://hackmd.io/_uploads/SktGz6wRxl.png)
**Flag: W1{x0r_p3rmut4t1on_a3r_v3ry_3asy_t0_brut3f0rc3s}**

## System of Equations
> Chắc hẳn bạn đã từng một lần đối mặt với một hệ phương trình trong quá khứ, đúng không? Nếu đã quen với những thử thách ấy, thì con đường dẫn tới lời giải cho thử thách này thực ra đang ở ngay trong tầm tay bạn. Điều quan trọng chỉ là sự kiên trì: dám mò mẫm từng ngõ ngách, thử nghiệm từng bước đi, và không ngần ngại bước vào những lối rẽ tưởng chừng bế tắc.
Tôi đã rất dễ dãi khi chỉ đưa ra cho bạn vỏn vẹn ba phương trình. Còn lại, tất cả phụ thuộc vào khả năng và sự bền bỉ của bạn.
Author: r1muru

Source chall:
```python=
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib
import os

FLAG = b'W1{???}'

x = int(input("Nhap x nguyen: "))
y = int(input("Nhap y nguyen: "))
z = int(input("Nhap z nguyen: "))

assert x**2 + 2*x*y - 8 == 4*z**2 + 4*y - 8*z
assert x**5 + y**3 == 10823714993004958804353333960725385073542379465721 - z**4 
assert 8864612849141*x**2 + 8864612849141*y + 17729225698282*z == 205022233466935232483321764396

mode = str(input("Nhap phuong thuc (encrypt hoac decrypt): "))

secret = (str(x**10) + str(y**10) + str(z**10)).encode()
key = hashlib.sha256(secret).digest()

if mode == "encrypt":
    iv = os.urandom(16)
    c = AES.new(key, AES.MODE_CBC, iv).encrypt(pad(FLAG, 16))

    print(f'iv = {iv}')
    print(f'ciphertext = {c}')
    
elif mode == "decrypt":
    iv = b'\x8d\r\x19\xbc\xfd\x84\x13N,\xf85\xdb\xd3\x92i\x93'
    ciphertext = b'\xe9\xa2\x8c\x8b\xc3\xb4\x88\xe2\xbb\x96\xc6\xac`\x1c}\xd1\xca\xc1ZB\xf1@\x01\x92\xca\xc4Z[\x96o\xdeFv\xdf\r\x13u+\x89\xac3\xa3\xc9X\xfb\x07u\x1bO\x9c\xb0\xbdN\xa4\xb6\xca&T\xabmx\xdb\xae\xc2'
    print(key)
    FLAG = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ciphertext), 16)
    print(FLAG.decode())
    
else:
    exit(1)
```

Ở code trên nó thực hiện mã hóa flag bằng AES mode CBC với padding là PKCS#7.

IV và ciphertext đã được cho, còn key được thực hiện tạo bởi 3 số x,y,z bằng các lấy hash sha256 của `(str(x**10) + str(y**10) + str(z**10)).encode()`

Ta còn biết:
```
assert x**2 + 2*x*y - 8 == 4*z**2 + 4*y - 8*z
assert x**5 + y**3 == 10823714993004958804353333960725385073542379465721 - z**4 
assert 8864612849141*x**2 + 8864612849141*y + 17729225698282*z == 205022233466935232483321764396
```

Vậy nên việc của ta đơn giản là thực hiện giải hệ phương trình 3 ẩn trên là xong.

Solve script:

```python3=
from sympy import symbols, Eq, solve
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib

x, y, z = symbols('x y z')

pt1 = Eq(x**2 + 2*x*y - 4*z**2 - 4*y + 8*z, 8)
pt2 = Eq(x**5 + y**3 + z**4 , 10823714993004958804353333960725385073542379465721)
pt3 = Eq(8864612849141*x**2 + 8864612849141*y + 17729225698282*z  , 205022233466935232483321764396)

ans = solve((pt1, pt2, pt3))

x_val = int(ans[0][x])
y_val = int(ans[0][y])
z_val = int(ans[0][z])

iv = b'\x8d\r\x19\xbc\xfd\x84\x13N,\xf85\xdb\xd3\x92i\x93'
ciphertext = b'\xe9\xa2\x8c\x8b\xc3\xb4\x88\xe2\xbb\x96\xc6\xac`\x1c}\xd1\xca\xc1ZB\xf1@\x01\x92\xca\xc4Z[\x96o\xdeFv\xdf\r\x13u+\x89\xac3\xa3\xc9X\xfb\x07u\x1bO\x9c\xb0\xbdN\xa4\xb6\xca&T\xabmx\xdb\xae\xc2'

secret = (str(x_val**10) + str(y_val**10) + str(z_val**10)).encode()
key = hashlib.sha256(secret).digest()

FLAG = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ciphertext), 16)
print(FLAG.decode())
```

**Flag: W1{y0u_must_b3_th3_m4st3r_0f_3quat1ons_817e31a7ccdbe8fd}**

## Learning with BRUTEFORCE
> Have you ever heard of "BRUTEFORCE," the GOAT of algorithms forever????
Author: Nhan_laptop

Source chall:

```python3=
from Crypto.Util.number import *
from sage.all import * 
import numpy as np
flag = b"W1{????????????????????????????????}"

e = [2506,2006]

def rebase(n,b):
    if n <= b:
        return [n]
    
    return [n%b] + rebase(n//b,b)


s = rebase(bytes_to_long(flag),3671)

n = len(s)
A = np.random.randint(1,3671-1,(n,n)).tolist()
s = vector(GF(3671),s)
e = np.random.choice(e,size=n)
A = matrix (GF(3671),A)
e = vector(GF(3671),e.tolist())

print(f'b = {A * s + e}')
print(f'A = {list(A)}')

#b = (3142, 2772, 805, 2779, 2853, 1921, 535, 210, 1161, 989, 2484, 2104, 1594, 1048, 452, 3586, 56, 1370, 436, 1601, 512, 274)
#A = [(2413, 2531, 3411, 2884, 2264, 377, 3514, 78, 1702, 3182, 3167, 20, 1054, 3422, 3177, 1535, 680, 3425, 3297, 535, 3390, 3619), (3236, 181, 2133, 1731, 844, 3201, 2176, 1268, 1285, 1692, 2874, 705, 1025, 2161, 1800, 992, 774, 625, 1897, 1823, 112, 2314), (1036, 1649, 317, 2345, 1900, 2149, 2964, 1518, 2909, 176, 3454, 2808, 465, 2940, 155, 2209, 3019, 1986, 1407, 2536, 3003, 155), (725, 237, 85, 2270, 1539, 1946, 1357, 1526, 759, 2183, 725, 1639, 2478, 2453, 2591, 520, 3060, 2483, 104, 1788, 1358, 1690), (2084, 1986, 1503, 560, 3033, 1451, 2721, 2749, 3537, 2408, 843, 1955, 498, 1849, 878, 2538, 2717, 3655, 3304, 2856, 926, 2658), (2431, 950, 953, 3046, 2543, 2422, 3552, 3656, 2063, 3585, 825, 2811, 497, 3635, 3445, 2579, 1882, 2003, 778, 2285, 866, 1288), (2859, 2257, 1451, 2988, 2568, 150, 2901, 3657, 1736, 2551, 3084, 3146, 2300, 3205, 3246, 909, 1574, 1345, 2087, 147, 584, 321), (3651, 1560, 3243, 1860, 1523, 1374, 1273, 1296, 1043, 1392, 3063, 2144, 21, 323, 3458, 2766, 2390, 2582, 2815, 211, 9, 1781), (2269, 2189, 1832, 1302, 2167, 2126, 863, 1101, 1177, 1689, 3631, 1722, 1933, 2429, 798, 912, 1360, 1811, 1740, 1759, 1981, 1266), (1788, 2524, 910, 448, 3558, 2913, 2309, 328, 404, 1995, 1633, 2605, 2421, 3488, 2860, 1259, 364, 1196, 1504, 1732, 2630, 587), (1975, 82, 3369, 129, 2504, 854, 1538, 3598, 953, 1324, 1469, 2984, 164, 2565, 744, 2792, 1196, 1383, 2922, 2544, 3609, 2630), (3120, 453, 248, 2510, 2464, 3098, 2459, 1219, 1179, 840, 1374, 2641, 1582, 304, 263, 186, 3191, 478, 988, 568, 3300, 929), (3401, 2877, 2106, 1352, 3664, 3069, 845, 1219, 1780, 3135, 2801, 251, 3617, 1195, 764, 2232, 2919, 693, 46, 3113, 2144, 874), (854, 2101, 3361, 2135, 1797, 3133, 2872, 3494, 2534, 1978, 1066, 1138, 439, 1503, 962, 1509, 2360, 1924, 1574, 483, 2641, 545), (2163, 3377, 253, 2530, 1968, 2470, 2662, 2807, 1264, 2924, 2528, 468, 729, 1707, 2692, 1960, 387, 3591, 800, 1428, 655, 2190), (1569, 3225, 3456, 1244, 157, 2438, 3248, 3443, 547, 967, 1107, 2571, 3068, 3578, 1799, 98, 452, 2108, 3462, 40, 2302, 41), (672, 2649, 1436, 2391, 2011, 2920, 2460, 1672, 3594, 2587, 1647, 1366, 3006, 1449, 2945, 2767, 3023, 991, 82, 1432, 1493, 1498), (1763, 3130, 948, 2461, 2695, 1362, 1558, 3344, 2710, 3397, 1845, 1735, 3493, 450, 407, 2907, 1564, 1203, 1497, 1656, 3651, 2348), (506, 1747, 50, 967, 1100, 2688, 283, 160, 3599, 2210, 3548, 3191, 252, 3519, 591, 3393, 3482, 1364, 1420, 425, 318, 2133), (2136, 625, 2454, 2764, 3635, 3514, 559, 1526, 1301, 2311, 837, 111, 3431, 1363, 3365, 2946, 1116, 1215, 1555, 3594, 973, 3622), (2464, 914, 3225, 706, 1804, 137, 2957, 1278, 766, 3570, 2155, 3634, 1960, 3482, 394, 2665, 896, 529, 1510, 1142, 656, 2868), (1080, 2030, 878, 945, 658, 1134, 2591, 1512, 313, 3348, 1329, 1571, 1108, 3279, 3185, 1188, 1330, 2315, 2885, 3190, 2141, 1307)]
```

### Bài toán
Cho hệ b = A·s + e (mod 3671). Vector s là “chữ số” của N = bytes_to_long(flag) trong cơ số 3671.
Mỗi e_i thuộc {2006, 2506}. Biết flag ASCII, bắt đầu `W1{` và kết thúc `}`.

### Ý tưởng
Viết e = 2006·1 + 500·z với z ∈ {0,1}^n. Đặt M = A^{-1}, y = M·b, c = M·1.
Suy ra s = y − 2006·c − 500·M·z (mod 3671) ⇒ s là ánh xạ affine theo z.

### Khai thác
- Chia 22 bit của z thành 11|11 và meet-in-the-middle trên các tổng con của −500·M[:, j].
- Lọc nhanh theo byte cuối: tính N mod 256 từ s (sau khi gộp mod 3671) và giữ ứng viên có 0x7D (‘}’).
- Dựng N, đổi ra bytes, kiểm tra ASCII + định dạng `W1{...}`.

### Solve script

```python3=
p = 3671
# --- nhập A, b từ đề (22x22 và 22 phần tử) ---
b = (3142, 2772, 805, 2779, 2853, 1921, 535, 210, 1161, 989, 2484, 2104, 1594, 1048, 452, 3586, 56, 1370, 436, 1601, 512, 274)
A = [(2413, 2531, 3411, 2884, 2264, 377, 3514, 78, 1702, 3182, 3167, 20, 1054, 3422, 3177, 1535, 680, 3425, 3297, 535, 3390, 3619), (3236, 181, 2133, 1731, 844, 3201, 2176, 1268, 1285, 1692, 2874, 705, 1025, 2161, 1800, 992, 774, 625, 1897, 1823, 112, 2314), (1036, 1649, 317, 2345, 1900, 2149, 2964, 1518, 2909, 176, 3454, 2808, 465, 2940, 155, 2209, 3019, 1986, 1407, 2536, 3003, 155), (725, 237, 85, 2270, 1539, 1946, 1357, 1526, 759, 2183, 725, 1639, 2478, 2453, 2591, 520, 3060, 2483, 104, 1788, 1358, 1690), (2084, 1986, 1503, 560, 3033, 1451, 2721, 2749, 3537, 2408, 843, 1955, 498, 1849, 878, 2538, 2717, 3655, 3304, 2856, 926, 2658), (2431, 950, 953, 3046, 2543, 2422, 3552, 3656, 2063, 3585, 825, 2811, 497, 3635, 3445, 2579, 1882, 2003, 778, 2285, 866, 1288), (2859, 2257, 1451, 2988, 2568, 150, 2901, 3657, 1736, 2551, 3084, 3146, 2300, 3205, 3246, 909, 1574, 1345, 2087, 147, 584, 321), (3651, 1560, 3243, 1860, 1523, 1374, 1273, 1296, 1043, 1392, 3063, 2144, 21, 323, 3458, 2766, 2390, 2582, 2815, 211, 9, 1781), (2269, 2189, 1832, 1302, 2167, 2126, 863, 1101, 1177, 1689, 3631, 1722, 1933, 2429, 798, 912, 1360, 1811, 1740, 1759, 1981, 1266), (1788, 2524, 910, 448, 3558, 2913, 2309, 328, 404, 1995, 1633, 2605, 2421, 3488, 2860, 1259, 364, 1196, 1504, 1732, 2630, 587), (1975, 82, 3369, 129, 2504, 854, 1538, 3598, 953, 1324, 1469, 2984, 164, 2565, 744, 2792, 1196, 1383, 2922, 2544, 3609, 2630), (3120, 453, 248, 2510, 2464, 3098, 2459, 1219, 1179, 840, 1374, 2641, 1582, 304, 263, 186, 3191, 478, 988, 568, 3300, 929), (3401, 2877, 2106, 1352, 3664, 3069, 845, 1219, 1780, 3135, 2801, 251, 3617, 1195, 764, 2232, 2919, 693, 46, 3113, 2144, 874), (854, 2101, 3361, 2135, 1797, 3133, 2872, 3494, 2534, 1978, 1066, 1138, 439, 1503, 962, 1509, 2360, 1924, 1574, 483, 2641, 545), (2163, 3377, 253, 2530, 1968, 2470, 2662, 2807, 1264, 2924, 2528, 468, 729, 1707, 2692, 1960, 387, 3591, 800, 1428, 655, 2190), (1569, 3225, 3456, 1244, 157, 2438, 3248, 3443, 547, 967, 1107, 2571, 3068, 3578, 1799, 98, 452, 2108, 3462, 40, 2302, 41), (672, 2649, 1436, 2391, 2011, 2920, 2460, 1672, 3594, 2587, 1647, 1366, 3006, 1449, 2945, 2767, 3023, 991, 82, 1432, 1493, 1498), (1763, 3130, 948, 2461, 2695, 1362, 1558, 3344, 2710, 3397, 1845, 1735, 3493, 450, 407, 2907, 1564, 1203, 1497, 1656, 3651, 2348), (506, 1747, 50, 967, 1100, 2688, 283, 160, 3599, 2210, 3548, 3191, 252, 3519, 591, 3393, 3482, 1364, 1420, 425, 318, 2133), (2136, 625, 2454, 2764, 3635, 3514, 559, 1526, 1301, 2311, 837, 111, 3431, 1363, 3365, 2946, 1116, 1215, 1555, 3594, 973, 3622), (2464, 914, 3225, 706, 1804, 137, 2957, 1278, 766, 3570, 2155, 3634, 1960, 3482, 394, 2665, 896, 529, 1510, 1142, 656, 2868), (1080, 2030, 878, 945, 658, 1134, 2591, 1512, 313, 3348, 1329, 1571, 1108, 3279, 3185, 1188, 1330, 2315, 2885, 3190, 2141, 1307)]

# nghịch đảo modulo p (Gauss-Jordan)
def inv_mod(a,p):
    t, newt, r, newr = 0, 1, p, a % p
    while newr:
        q = r//newr
        t, newt = newt, t-q*newt
        r, newr = newr, r-q*newr
    return t%p

def mat_inv_mod(A,p):
    n = len(A)
    M = [[A[i][j]%p for j in range(n)] + [1 if i==j else 0 for j in range(n)] for i in range(n)]
    row = 0
    for col in range(n):
        pivot = next((r for r in range(row,n) if M[r][col]%p), None)
        M[row], M[pivot] = M[pivot], M[row]
        inv = inv_mod(M[row][col], p)
        M[row] = [(x*inv)%p for x in M[row]]
        for r in range(n):
            if r!=row and M[r][col]%p:
                f = M[r][col]%p
                M[r] = [(M[r][c]-f*M[row][c])%p for c in range(2*n)]
        row += 1
    return [r[n:] for r in M]

def mat_vec(M,v,p): return [sum((M[i][j]*v[j])%p for j in range(len(v)))%p for i in range(len(M))]

invA = mat_inv_mod(A,p)
one = [1]*len(b)
y = mat_vec(invA, b, p)
c = mat_vec(invA, one, p)
t = [(y[i]-2006*c[i])%p for i in range(len(b))]

# cột của invA và delta
cols = [[invA[r][c] for r in range(len(b))] for c in range(len(b))]
dcols = [[(-500*x)%p for x in col] for col in cols]

# chia 11|11 và dựng mọi tổng con
H1, H2 = list(range(11)), list(range(11,22))
def all_subset_sums(idxs):
    S = [[0]*len(b)]
    for j in idxs:
        add = dcols[j]
        S += [[(S[i][k]+add[k])%p for k in range(len(b))] for i in range(len(S))]
    return S

S1 = all_subset_sums(H1)  # 2048
S2 = all_subset_sums(H2)  # 2048

# chuẩn bị modulo 256 cho lọc nhanh
r256 = []
pw = 1%256
for _ in range(len(b)):
    r256.append(pw); pw = (pw * (3671%256)) % 256

def last_byte(s):
    return sum((s[i]%256)*r256[i] for i in range(len(b))) % 256

# quét ứng viên, chọn byte cuối '}' = 0x7D
cands = []
for v2 in S2:
    for v1 in S1:
        s = [(t[i] + v1[i] + v2[i]) % p for i in range(len(b))]
        if last_byte(s) == 0x7D:
            cands.append(s)

# dựng số lớn và kiểm tra định dạng
powB = [1]
for _ in range(len(b)): powB.append(powB[-1]*3671)

def s_to_int(s):
    return sum(int(s[i]) * powB[i] for i in range(len(s)))

def int_to_bytes(N):
    if N==0: return b"\x00"
    L = (N.bit_length()+7)//8
    return N.to_bytes(L, 'big')

for s in cands:
    N = s_to_int(s)
    bs = int_to_bytes(N)
    if bs.startswith(b'W1{') and bs.endswith(b'}') and all(32<=c<=126 for c in bs):
        print(bs.decode())  # flag
        break
```

**Flag: W1{M3ss1_1s_t43_90AT!!!!!!!!!!!}**

## Bo tu sieu dang
> You can't beat these 4 guards, or ...?
Format flag: W1{A-Za-z0-9_}
Author: L1ttl3

Source chall:

```python3=
from Crypto.Util.number import *

with open("flag.txt ", 'rb') as f:
    flag = f.read().strip()

assert flag.startswith(b'W1{') and flag.endswith(b'}')

m = bytes_to_long(flag)

e = 0x10001
m1 = 2**1024 - 3
m2 = 2**1022 - 2
m3 = 2**1020 - 1
m4 = 2**1018

c = pow(m, e, m1) % m2 % m3 % m4

print(c)
#c = 2027792127378145444099302510462900300257442068928010403052259994880511317607407514908720534902489134379904618947792557805368190009359079320337075768626232418980864987406619809977532904702783433112202254001367719098893178820312980355187703995660867067442830169498602243151057835147454968516377852012013934653
```

**Bài toán.** Cho m = bytes_to_long(flag), e = 65537 và
c = (m^e mod (2^1024 - 3)) mod (2^1022 - 2) mod (2^1020 - 1) mod 2^1018.
Flag định dạng `W1{A-Za-z0-9_}` ⇒ m là số lẻ.

**Ý chính**
- Gọi r1 = m^e mod (2^1024 - 3).
  Từ chuỗi phép `%` suy ra:
  r1 ≡ c + t2·(2^1022 − 2) + t3·(2^1020 − 1) (mod 2^1018),
  với t2, t3 ∈ {0,1,2,3}.
- Trên mô-đun 2^1018 (nhóm đơn vị có bậc 2^1017), ánh xạ x ↦ x^e là song ánh.
  Lấy d ≡ e^(-1) (mod 2^1017) ⇒ m ≡ r1^d (mod 2^1018).
- Duyệt 16 khả năng, tính m (mod 2^1018), đổi ra bytes, giữ chuỗi khớp regex `^W1\{[A-Za-z0-9_]*\}$`. Kết quả duy nhất là flag.

Solve script:

```python3=
from sage.all import Integer, crt, inverse_mod, power_mod
from itertools import product
import re

# --- tham số mô-đun ---
mod1 = 2**1024 - 3
mod2 = 2**1022 - 2
mod3 = 2**1020 - 1
mod4 = 2**1018

C = Integer(2027792127378145444099302510462900300257442068928010403052259994880511317607407514908720534902489134379904618947792557805368190009359079320337075768626232418980864987406619809977532904702783433112202254001367719098893178820312980355187703995660867067442830169498602243151057835147454968516377852012013934653)
E = Integer(65537)

# các thừa số nguyên tố của mod1
PRIMES = list(map(Integer, [
    13, 107, 87671, 3870037838243,
    279462107025143615623321823017,
    1325706410421371952032007611396267
]))

# nghịch đảo mũ e modulo p-1 cho từng p
inv_exps = [inverse_mod(E, p - 1) for p in PRIMES]

# gom ứng viên flag hợp lệ (tuỳ chọn)
rx_flag = re.compile(rb'^W1\{[A-Za-z0-9_]*\}$')
seen = set()

for t2, t3, t4 in product(range(4), repeat=3):
    # r1 ≡ C + t2*mod2 + t3*mod3 + t4*mod4 (theo mô tả phép chia dư xâu chuỗi)
    r1 = C + t2 * mod2 + t3 * mod3 + t4 * mod4

    # m ≡ r1^{d_i} (mod p_i) cho từng p_i
    residues = [power_mod(r1, d, p) for d, p in zip(inv_exps, PRIMES)]

    # ghép bằng CRT để thu m (mod ∏p_i)
    m_rec = crt(residues, PRIMES)

    # đổi ra bytes (big-endian)
    blen = (int(m_rec).bit_length() + 7) // 8 or 1
    fb = int(m_rec).to_bytes(blen, 'big')

    if fb not in seen:
        seen.add(fb)
        print(fb)
        # nếu muốn chỉ in flag hợp lệ, bỏ comment dòng dưới:
        # if rx_flag.fullmatch(fb): print(fb.decode())
```

**Flag: W1{RSA_w1th_0v3rl4pp1ng_m0dulo}**