0%

NKCTF2023·Crypto WP

NKCTF2023

笔者以星盟安全团队成员的身份参与了本次比赛,在队内师傅们的共同努力下队伍取得了不错的成绩

队伍排名:4

文章仅就密码方向进行分享。

Crypto

完成度:12/13

一血数:6

baby_RSA

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import *
nbit = 512
flag='****************************'

p=getPrime(nbit)
q=getPrime(nbit)
e=65537
n=p*q
m= bytes_to_long(bytes(flag.encode()))
P = pow(m,p,n)
Q = pow(m,q,n)
N=P*Q
phi_N=(P-1)*(Q-1)
d=inverse(e,phi_N)
dP=d%(P-1)
print('n = ',n)
print('N = ',N)
print('dP = ',dP)


n = 114101396033690088275999670914803472451228154227614098210572767821433470213124900655723605426526569384342101959232900145334500170690603208327913698128445002527020347955300595384752458477749198178791196660625870659540794807018881780680683388008090434114437818447523471527878292741702348454486217652394664664641
N = 1159977299277711167607914893426674454199208605107323826176606074354449015203832606569051328721360397610665453513201486235549374869954501563523028914285006850687275382822302821825953121223999268058107278346499657597050468069712686559045712946025472616754027552629008516489090871415609098178522863027127254404804829735621706042266140637592206366042515190385496909533329383212542170504864473944657824502882014292528444918055958758310544435120502872883857209880723535754528096143707324179005292445100655695427777453144657819474805882956064292780031599790769618615908501966912635232746588639924772530057835864082951499028
dP = 33967356791272818610254738927769774016289590226681637441101504040121743937150259930712897925893431093938385216227201268238374281750681609796883676743311872905933219290266120756315613501614208779063819499785817502677885240656957036398336462000771885589364702443157120609506628895933862241269347200444629283263

题解

  1. dp泄漏分解P、Q

  2. coppersmith解m

    $P = m^p \mod n = m \mod p = m+k_1p$

    $Q = m^q \mod n = m \mod q = m+k_2q$

    $P \cdot Q=m^2+m(k_1p+k_2q)+k_1k_2n=m^2+m(P-m+Q-m) \mod n$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import gmpy2 as gp
from Crypto.Util.number import *

e = 65537
N = 1159977299277711167607914893426674454199208605107323826176606074354449015203832606569051328721360397610665453513201486235549374869954501563523028914285006850687275382822302821825953121223999268058107278346499657597050468069712686559045712946025472616754027552629008516489090871415609098178522863027127254404804829735621706042266140637592206366042515190385496909533329383212542170504864473944657824502882014292528444918055958758310544435120502872883857209880723535754528096143707324179005292445100655695427777453144657819474805882956064292780031599790769618615908501966912635232746588639924772530057835864082951499028
dp = 33967356791272818610254738927769774016289590226681637441101504040121743937150259930712897925893431093938385216227201268238374281750681609796883676743311872905933219290266120756315613501614208779063819499785817502677885240656957036398336462000771885589364702443157120609506628895933862241269347200444629283263
n = 114101396033690088275999670914803472451228154227614098210572767821433470213124900655723605426526569384342101959232900145334500170690603208327913698128445002527020347955300595384752458477749198178791196660625870659540794807018881780680683388008090434114437818447523471527878292741702348454486217652394664664641


for a in range(1, e+1):
if (dp*e-1) % a == 0:
if N % ((dp*e-1) // a + 1) == 0: # ! 关键,易漏.要求n被p整除
P = (dp*e-1) // a + 1
Q = N // P
print('P =', P)
print('Q =', Q)
break
else:
a += 1


PR.<m> = PolynomialRing(Zmod(n))
f = P*Q-m^2-m*(P-m+Q-m)
f = f.monic()
m = f.small_roots(X=2^400, beta=0.4)
print(m)
flag1 = long_to_bytes(int(m[0]))
print(flag1)
# NKCTF{Th1S_a_babyRSA_y0u_are_tql!!!}

ez_math

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from Crypto.Util.number import getPrime, bytes_to_long
from secret import BITS, hints, flag

p = getPrime(BITS)
q = getPrime(BITS)
n = p * q
print(f'n = {n}')

e = 0x10001
c = pow(bytes_to_long(flag), e, n)
print(f'c = {c}')

print('Give you some boring pows:')
for i in range(len(hints)):
print(hints[i])

"""
n = 369520637995317866367336688225182965061898803879373674073832046072914710171302486913303917853881549637806426191970292829598855375370563396182543413674021955181862907847280705741114636854238746612618069619482248639049407507041667720977392421249242597197448360531895206645794505182208390084734779667749657408715621
c = 324131338592233305486487416176106472248153652884280898177125443926549710357763331715045582842045967830200123100144721322509500306940560917086108978796500145618443920020112366546853892387011738997522207752873944151628204886591075864677988865335625452099668804529484866900390927644093597772065285222172136374562043
Give you some boring pows:
pow(6, 42762902032363446334121451790132830028099011269558028556333775251728898854654431095595000922138958455510196735338223430882428451914478079186797153527810555787441234842366353864053114538165236037883914332840687123514412294276743506313011532002136735343280737244020115917460801848337792582496228600926958548903290, n) = 4
pow(6, 141997416965295486849546892322458652502850390670128808480582247784728456230996812361056958004801816363393016360646922983916999235770803618904474553309200419301820603229504955218189709387942156848904968053547462302189568831762401075340100029630332409419313772378068180267756675141584884876543484516408660699471038, n) = 9
pow(6, 163378867981477210016607618217525067516899896304907822758749135410592905658324027908854458465871295591148114728316034699358213461728042658497873130073105697195541220650688132150216266657024774867846925219967805863946774978900772828496605795631400777090954141000078238226487076065753781167791598816872139973922682, n) = 3
pow(5, 101651508435846472131121026992982127175369332865677196032272241712711171024515826370577416844824734811581351106736224929238579734879671732717639124571916168742336862493284572465162318403582113621582374924091725060981390318743531229548188092491836655143124663368239422819562367919547196053790207486164506763679128, n) = 4
pow(8, 7202269322818255506843028035725052687541091567764933235328308385449791332345247877549905289072216053144576876979686287212194040101112899704499548530779540409356827298148385589812450437990490353926475147376495772639210184768544932563432306664067058309318707174880146258394471096033723193568453520897758319446472, n) = 3
pow(6, 64144353048545169501182177685199245042148516904337042834500662877593348281981646643392501383208437683265295103007335146323642677871717118780195730291715833681161852263549530796079671807247854056825871499261030685271618441415115259469517298003205103014921105866030173876191202772506688873744342901390437823354935, n) = 8
pow(6, 21381451016181723167060725895066415014049505634779014278166887625864449427327215547797500461069479227755098367669111715441214225957239039593398576763905277893720617421183176932026557269082618018941957166420343561757206147138371753156505766001068367671640368622010057958730400924168896291248114300463479274451645, n) = 2
pow(4, 21606807968454766520529084107175158062623274703294799705984925156349373997035743632649715867216648159433730630939058861636582120303338699113498645592338621228070481894445156769437351313971471061779425442129487317917630554305634797690296919992201174927956121524640438775183413288101169580705360562693274958339416, n) = 9
pow(2, 21606807968454766520529084107175158062623274703294799705984925156349373997035743632649715867216648159433730630939058861636582120303338699113498645592338621228070481894445156769437351313971471061779425442129487317917630554305634797690296919992201174927956121524640438775183413288101169580705360562693274958339417, n) = 6
pow(4, 10803403984227383260264542053587579031311637351647399852992462578174686998517871816324857933608324079716865315469529430818291060151669349556749322796169310614035240947222578384718675656985735530889712721064743658958815277152817398845148459996100587463978060762320219387591706644050584790352680281346637479169708, n) = 3
pow(9, 3293982057350410278459882519024200329089724149803879577174733206141551016681048848343176690789446255513117465644006032807116613436995145441651711865811812905401261777042165657533800465011922458688696664211216129846590488003282750224539553623014598025837108471148806368738631086225250952573439068109703953523338, n) = 4
pow(2, 43213615936909533041058168214350316125246549406589599411969850312698747994071487265299431734433296318867461261878117723273164240606677398226997291184677242456140963788890313538874702627942942123558850884258974635835261108611269595380593839984402349855912243049280877550366826576202339161410721125386549916678832, n) = 9
pow(7, 156359509651684605051402965560382969488421316701585527115005130492947292379802933549188085059602557600903593831240316597311439285149968787780538126741092612405335349622445040578126369183536683733294143156965518222696624206221060030916594302284630706642066420353822195108928341123726471513256217857861184609387726, n) = 9
pow(7, 170559914324671769117535654836487226009685359320636182075960576764702323732727088502920021993271666209903403463612731506055433486417625242935904916789051793747298593847158174830184596554822038310041512771676833824200302666130102306284852931958549925702330464987955245647072909056824574486147965487598401928881026, n) = 3
pow(8, 123173545998439288789112229408394321687299601293124558024610682024304903390434162304434639284627183212602142063990097609866285125123521132060847804558007316726174558714580872721495215950738261924525921590925432950469320750692763054435407707754979429841729673081392197456811651326615118306026475411557079498916218, n) = 4
pow(2, 21606807968454766520529084107175158062623274703294799705984925156349373997035743632649715867216648159433730630939058861636582120303338699113498645592338621228070481894445156769437351313971471061779425442129487317917630554305634797690296919992201174927956121524640438775183413288101169580705360562693274958339416, n) = 3
pow(3, 6587964114700820556919765038048400658179448299607759154349466412283102033362097696686353381578892511026234931288012065614233226873990290883303423731623625810802523554084331315067600930023844917377393328422432259693180976006565500449079107246029196051674216942297612737477262172450501905146878136219407907046676, n) = 4
pow(7, 146900004342901005519726059203387905743111231159623333298786259340649199259667124880775175860427705602975071010583553281005991812801779033020769274211420710213704563866848310994325033574484679477677016014418321661821714582236428708141287327064859146436371562752616380650770729341741997594308364878898526065859626, n) = 4
pow(5, 172192380036714150788905270808196199818277334366508682218739812159577144024191963252552116624193235000074634457087111471641800814071769221933018962135503876997163938949365614056098717522475180216291316295788774044033481065993544994610614082708563841846852650913646728169671510827052772868386414581035580266356334, n) = 3
pow(8, 68789042322037899901399142739922213531190892214327212247633649397602243027562329029767224931385807659445647908974735092145336602662873465734923450809783198772444106655438821950560058413359621316189435942839212247873870560114926459781136160541556773230183543715576244986800296759341282346581691226676298068904581, n) = 6
pow(5, 159624441075769368394142197503800917105605266793330527400563601282696932962732683048452274321445695181246055818189076528484173940458256745774766217433996778905066039826859919029954611118842967545793750205189398662362981005947945407568116603784658538931110792205205160154125544664182868277733116044735541284338342, n) = 9
pow(8, 14404538645636511013686056071450105375082183135529866470656616770899582664690495755099810578144432106289153753959372574424388080202225799408999097061559080818713654596296771179624900875980980707852950294752991545278420369537089865126864613328134116618637414349760292516788942192067446387136907041795516638892944, n) = 9
"""

题解

  • 找到合适数据求出Kphi

    $6^{2B}≡6^A \mod n, 2B!=A$,则$2B ≡ A \mod phi, 2B-A=kphi $

  • Kphi当phi解出明文m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import gmpy2
import libnum

e = 0x10001
n = 369520637995317866367336688225182965061898803879373674073832046072914710171302486913303917853881549637806426191970292829598855375370563396182543413674021955181862907847280705741114636854238746612618069619482248639049407507041667720977392421249242597197448360531895206645794505182208390084734779667749657408715621
c = 324131338592233305486487416176106472248153652884280898177125443926549710357763331715045582842045967830200123100144721322509500306940560917086108978796500145618443920020112366546853892387011738997522207752873944151628204886591075864677988865335625452099668804529484866900390927644093597772065285222172136374562043

A = 141997416965295486849546892322458652502850390670128808480582247784728456230996812361056958004801816363393016360646922983916999235770803618904474553309200419301820603229504955218189709387942156848904968053547462302189568831762401075340100029630332409419313772378068180267756675141584884876543484516408660699471038
B = 163378867981477210016607618217525067516899896304907822758749135410592905658324027908854458465871295591148114728316034699358213461728042658497873130073105697195541220650688132150216266657024774867846925219967805863946774978900772828496605795631400777090954141000078238226487076065753781167791598816872139973922682

assert pow(6, 2*B, n) == pow(6, A, n)
assert 2*B != A

Kphi = 2*B-A
d = gmpy2.invert(e, Kphi)
m = int(pow(c,d,n))
print(libnum.n2s(m))
# NKCTF{d15cr373_L0g_15_R3DuC710n_f0R_f4C70r1nG}

ezRSA

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from Crypto.Util.number import *
from secret import flag

m1 = bytes_to_long(flag[:len(flag)//3])
m2 = bytes_to_long(flag[len(flag)//3:])

def gen():
prime_list = []
for i in range(4):
prime_list.append(getPrime(512))
return sorted(prime_list)

prime_list = gen()
p,q,r,t = prime_list[0],prime_list[3],prime_list[1],prime_list[2]
e = 65537
n = p*q*r*t
phi = (p-1)*(q-1)*(r-1)*(t-1)
c1 = pow(m1,e,p*q)
p1 = getPrime(512)
q1 = getPrime(512)
N = p1*q1
c2 = pow(m2,p1,N)
c3 = pow(m2,q1,N)
print(f'n = {n}')
print(f'phi = {phi}')
print(f'c1 = {c1}')
print(f'N = {N}')
print(f'c2 = {c2}')
print(f'c3 = {c3}')

'''
n = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505626165666334675100147790578546682128517668100858766784733351894480181877144793496927464058323582165412552970999921215333509253052644024478417393146000490808639363681195799826541558906527985336104761974023394438549055804234997654701266967731137282297623426318212701157416397999108259257077847307874122736921265599854976855949680133804464839768470200425669609996841568545945133611190979810786943246285103031363790663362165522662820344917056587244701635831061853354597
phi = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505622503351461565956106005118029537938273153581675065762015952483687057805462728186901563990429998916382820576211887477098611684072561849314986341226981300596338314989867731725668312057134075244816223120038573374383949718714549930261073576391501671722900294331289082826058292599838631513746370889828026039555245672195833927609280773258978856664434349221972568651378808050580665443131001632395175205804045958846124475183825589672204752895252723130454951830966138888560
c1 = 78327207863361017953496121356221173288422862370301396867341957979087627011991738176024643637029313969241151622985226595093079857523487726626882109114134910056673489916408854152274726721451884257677533593174371742411008169082367666168983943358876017521749198218529804830864940274185360506199116451280975188409
N = 157202814866563156513184271957553223260772141845129283711146204376449001653397810781717934720804041916333174673656579086498762693983380365527400604554663873045166444369504886603233275868192688995284322277504050322927511160583280269073338415758019142878016084536129741435221345599028001581385308324407324725353
c2 = 63355788175487221030596314921407476078592001060627033831694843409637965350474955727383434406640075122932939559532216639739294413008164038257338675094324172634789610307227365830016457714456293397466445820352804725466971828172010276387616894829328491068298742711984800900411277550023220538443014162710037992032
c3 = 9266334096866207047544089419994475379619964393206968260875878305040712629590906330073542575719856965053269812924808810766674072615270535207284077081944428011398767330973702305174973148018082513467080087706443512285098600431136743009829009567065760786940706627087366702015319792328141978938111501345426931078
'''

题解

  1. 已知phi分解n,常规rsa求解flag1
  2. 通过m1确定m2比特位,最后用baby_RSA的coppersmith解法再解一次m2

已知phi分解n

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from math import gcd
from math import isqrt
from random import randrange
from gmpy2 import is_prime
# from sage.all import is_prime


def factorize(N, phi):
"""
Recovers the prime factors from a modulus if Euler's totient is known.
This method only works for a modulus consisting of 2 primes!
:param N: the modulus
:param phi: Euler's totient, the order of the multiplicative group modulo N
:return: a tuple containing the prime factors, or None if the factors were not found
"""
s = N + 1 - phi
d = s ** 2 - 4 * N
p = int(s - isqrt(d)) // 2
q = int(s + isqrt(d)) // 2
return p, q


def factorize_multi_prime(N, phi):
"""
Recovers the prime factors from a modulus if Euler's totient is known.
This method works for a modulus consisting of any number of primes, but is considerably be slower than factorize.
More information: Hinek M. J., Low M. K., Teske E., "On Some Attacks on Multi-prime RSA" (Section 3)
:param N: the modulus
:param phi: Euler's totient, the order of the multiplicative group modulo N
:return: a tuple containing the prime factors
"""
prime_factors = set()
factors = [N]
while len(factors) > 0:
# Element to factorize.
N = factors[0]

w = randrange(2, N - 1)
i = 1
while phi % (2 ** i) == 0:
sqrt_1 = pow(w, phi // (2 ** i), N)
if sqrt_1 > 1 and sqrt_1 != N - 1:
# We can remove the element to factorize now, because we have a factorization.
factors = factors[1:]

p = gcd(N, sqrt_1 + 1)
q = N // p

if is_prime(p):
prime_factors.add(p)
elif p > 1:
factors.append(p)

if is_prime(q):
prime_factors.add(q)
elif q > 1:
factors.append(q)

# Continue in the outer loop
break

i += 1

return tuple(prime_factors)
if __name__ =='__main__':
n = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505626165666334675100147790578546682128517668100858766784733351894480181877144793496927464058323582165412552970999921215333509253052644024478417393146000490808639363681195799826541558906527985336104761974023394438549055804234997654701266967731137282297623426318212701157416397999108259257077847307874122736921265599854976855949680133804464839768470200425669609996841568545945133611190979810786943246285103031363790663362165522662820344917056587244701635831061853354597
phi = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505622503351461565956106005118029537938273153581675065762015952483687057805462728186901563990429998916382820576211887477098611684072561849314986341226981300596338314989867731725668312057134075244816223120038573374383949718714549930261073576391501671722900294331289082826058292599838631513746370889828026039555245672195833927609280773258978856664434349221972568651378808050580665443131001632395175205804045958846124475183825589672204752895252723130454951830966138888560
fac = factorize_multi_prime(n, phi)
print(fac)

coppersmith解法再解一次m2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import gmpy2
import libnum


n = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505626165666334675100147790578546682128517668100858766784733351894480181877144793496927464058323582165412552970999921215333509253052644024478417393146000490808639363681195799826541558906527985336104761974023394438549055804234997654701266967731137282297623426318212701157416397999108259257077847307874122736921265599854976855949680133804464839768470200425669609996841568545945133611190979810786943246285103031363790663362165522662820344917056587244701635831061853354597
phi = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505622503351461565956106005118029537938273153581675065762015952483687057805462728186901563990429998916382820576211887477098611684072561849314986341226981300596338314989867731725668312057134075244816223120038573374383949718714549930261073576391501671722900294331289082826058292599838631513746370889828026039555245672195833927609280773258978856664434349221972568651378808050580665443131001632395175205804045958846124475183825589672204752895252723130454951830966138888560
e = 65537
c1 = 78327207863361017953496121356221173288422862370301396867341957979087627011991738176024643637029313969241151622985226595093079857523487726626882109114134910056673489916408854152274726721451884257677533593174371742411008169082367666168983943358876017521749198218529804830864940274185360506199116451280975188409

prime_list = [10278918289612367146046409135513725291319742611325451529622387426552790672650542777172769017399682768083823848127693717878822223823002122605741847534168871, 8420341711111386139826589531912136886697864041156239432418101990860951057225344962981814097328105109563572968937589482777359728076364540186966659710593563, 9422949623669587592195284918343137628924288670457557164230168847803264549856927866278221296107887154859174132983372562130946621134855520373823156469022523, 10834231423967940002221004300639472879422266804796466209639481015717927053785699849888626682293072249949761634253205413288361321778947376683555990557548843]
prime_list = sorted(prime_list)
p,q,r,t = prime_list[0],prime_list[3],prime_list[1],prime_list[2]
d1 = gmpy2.invert(e, phi)
m1 = int(pow(c1, d1, p*q))
flag1 = libnum.n2s(m1)

# part 2
N = 157202814866563156513184271957553223260772141845129283711146204376449001653397810781717934720804041916333174673656579086498762693983380365527400604554663873045166444369504886603233275868192688995284322277504050322927511160583280269073338415758019142878016084536129741435221345599028001581385308324407324725353
c2 = 63355788175487221030596314921407476078592001060627033831694843409637965350474955727383434406640075122932939559532216639739294413008164038257338675094324172634789610307227365830016457714456293397466445820352804725466971828172010276387616894829328491068298742711984800900411277550023220538443014162710037992032
c3 = 9266334096866207047544089419994475379619964393206968260875878305040712629590906330073542575719856965053269812924808810766674072615270535207284077081944428011398767330973702305174973148018082513467080087706443512285098600431136743009829009567065760786940706627087366702015319792328141978938111501345426931078
n = N
P = c2
Q = c3

PR.<m> = PolynomialRing(Zmod(n))
f = P*Q-m^2-m*(P-m+Q-m)
f = f.monic()
m = f.small_roots(X=2^(len(flag1)*2*8), beta=0.7)

flag2 = libnum.n2s(int(m[0]))
print(flag1+flag2)
# b'NKCTF{it_i5_e45y_th4t_Kn0wn_phi_4nd_N_dec0mp0ses_N_w1th_th3_s4m3_c0mm0n_n_but_pq}'

real_MT

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import random
import signal

def guess_number_1():
randoms = []
for _ in range(208):
randoms.append(random.getrandbits(96))

print("randoms = "+str(randoms))
number = str(random.getrandbits(96))
guess = str(input("Guess after number:"))
if guess != number:
print("Wrong Number! Guess again.")
exit(0)

def guess_number_2():
number = str(random.getrandbits(96))
randoms = []
for _ in range(627):
randoms.append(random.getrandbits(32))

print("randoms = "+str(randoms))
guess = str(input("Guess pre number:"))
if guess != number:
print("Wrong Number! Guess again.")
exit(0)

def guess_number_3():

def _int32(x):
return int(0xFFFFFFFF & x)
def init(seed):
mt = [0] * 624
mt[0] = seed
for i in range(1, 624):
mt[i] = _int32(1812433253 * (mt[i - 1] ^ mt[i - 1] >> 30) + i)
return mt[-1]
number = random.getrandbits(32)
print("last number = "+ str(init(number)))
guess = int(str(input("Guess seed number:")))
if guess != number:
print("Wrong Number! Guess again.")
exit(0)

def guess_number_4():
def extract_number(y):
y = y ^ y >> 11
y = y ^ y << 7 & 2636928640
y = y ^ y << 15 & 4022730752
y = y ^ y >> 18
return y&0xffffffff

number = random.getrandbits(32)
print("extract number = "+ str(extract_number(number)))
guess = int(str(input("Guess be extracted number:")))
if guess != number:
print("Wrong Number! Guess again.")
exit(0)


print("Welcome to the Mersenne Twister basic challenge. Please try to solve 20 challenges in 60 seconds.")
signal.alarm(60)

for i in range(20):
print("Round: "+str(i+1))
random.choice([guess_number_1,guess_number_2,guess_number_3,guess_number_4])()
print("Good job!")

flag = open('/flag').read()
print("Congratulations on passing the challenge. This is your flag: " + str(flag))

题解

MT19937相关的经典内容大杂烩,参考badmonkey师傅博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import gmpy2
from pwn import *
from extend_mt19937_predictor import ExtendMT19937Predictor

context.log_level = 'debug'


# right shift inverse
def inverse_right(res, shift, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp >> shift
return tmp


# left shift with mask inverse
def inverse_left_mask(res, shift, mask, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp << shift & mask
return tmp


def recover(y):
y = inverse_right(y, 18)
y = inverse_left_mask(y, 15, 4022730752)
y = inverse_left_mask(y, 7, 2636928640)
y = inverse_right(y, 11)
return y & 0xffffffff


def attack1(list1):
predictor = ExtendMT19937Predictor()
for i in range(208):
predictor.setrandbits(list1[i], 96)
return predictor.predict_getrandbits(96)


def attack2(list1):
predictor = ExtendMT19937Predictor()
for i in range(627):
predictor.setrandbits(list1[i], 32)
for i in range(627):
predictor.backtrack_getrandbits(32)
x = predictor.backtrack_getrandbits(96)
return x


def attack3(last):
n = 1 << 32
inv = gmpy2.invert(1812433253, n)
for i in range(623, 0, -1):
last = ((last - i) * inv) % n
last = inverse_right(last, 30)
return last


def attack4(y):
return recover(y)


# :
sh = remote('node.yuzhian.com.cn', 38574)
sh.recvuntil(b'Press Enter to start...')
sh.sendline()
for i in range(20):
sh.recvline_contains(b'Round:')
data = sh.recvuntil(b':')
if b'Guess after number:' in data:
data.replace(b'Guess after number:', b'')
data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
ans = attack1(data)
elif b'Guess pre number:' in data:
data.replace(b'Guess pre number:', b'')
data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
ans = attack2(data)
elif b'Guess seed number:' in data:
data.replace(b'Guess seed number:', b'')
data = eval(data.split(b'last number = ')[-1].split(b'\n')[0])
ans = attack3(data)
else:
data.replace(b'Guess be extracted number:', b'')
data = eval(data.split(b'extract number = ')[-1].split(b'\n')[0])
ans = attack4(data)
sh.sendline(str(ans).encode())
sh.recvline() # Good job!
sh.interactive()
# NKCTF{73e1d7d9-29f5-4a9c-a4a8-0350faf4cb76}

fake_MT

题目

基本如上,差别是用的py2

题解

出题人预期的非预期解是利用py2的input能当eval用。

如下是非预期的预期解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import gmpy2
from pwn import *
from extend_mt19937_predictor import ExtendMT19937Predictor

context.log_level = 'debug'


# right shift inverse
def inverse_right(res, shift, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp >> shift
return tmp


# left shift with mask inverse
def inverse_left_mask(res, shift, mask, bits=32):
tmp = res
for i in range(bits // shift):
tmp = res ^ tmp << shift & mask
return tmp


def recover(y):
y = inverse_right(y, 18)
y = inverse_left_mask(y, 15, 4022730752)
y = inverse_left_mask(y, 7, 2636928640)
y = inverse_right(y, 11)
return y & 0xffffffff


def attack1(list1):
predictor = ExtendMT19937Predictor()
for i in range(208):
predictor.setrandbits(list1[i], 96)
return predictor.predict_getrandbits(96)


def attack2(list1):
predictor = ExtendMT19937Predictor()
for i in range(627):
predictor.setrandbits(list1[i], 32)
for i in range(627):
predictor.backtrack_getrandbits(32)
x = predictor.backtrack_getrandbits(96)
return x


def attack3(last):
n = 1 << 32
inv = gmpy2.invert(1812433253, n)
for i in range(623, 0, -1):
last = ((last - i) * inv) % n
last = inverse_right(last, 30)
return last


def attack4(y):
return recover(y)

sh = remote('node.yuzhian.com.cn', 35467)

for i in range(20):
sh.recvline_contains(b'Round:')
data = sh.recvuntil(b':')
if b'Guess after number:' in data:
data = data.replace(b'L', b'')
data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
print(data)
ans = attack1(data)

elif b'Guess pre number:' in data:
data = data.replace(b'L', b'')
data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
print(data)
ans = attack2(data)
elif b'Guess seed number:' in data:
data = data.replace(b'L', b'')
data = eval(data.split(b'last number = ')[-1].split(b'\n')[0])
print(data)
ans = attack3(data)
else:
data = data.replace(b'L', b'')
data = eval(data.split(b'extract number = ')[-1].split(b'\n')[0])
print(data)
ans = attack4(data)
sh.sendline(str(ans).encode())
sh.recvline() # Good job!
sh.interactive()
# NKCTF{55d825f1-8bc1-421d-850f-2af971731b5d}

ez_polynomial

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#sage
from Crypto.Util.number import *
flag = list(bytearray(''))
p = getPrime(16)
R.<y> = PolynomialRing(GF(p))
while True:
P1 = R.random_element(degree=(ZZ.random_element(len(flag), 2*len(flag))))
Q1 = R.random_element(degree=(ZZ.random_element(len(flag), 2*len(flag))))
if P1.is_irreducible() and Q1.is_irreducible():
P = P1
Q = Q1
break
e = 65537
N = P*Q
S.<x> = R.quotient(N)
c = S(flag) ^ e
print("P:" + str(p) + "\n")
print("N:" + str(N) + "\n")
print("C:" + str(c))

#P:40031
#N:24096*y^93 + 38785*y^92 + 17489*y^91 + 9067*y^90 + 1034*y^89 + 6534*y^88 + 35818*y^87 + 22046*y^86 + 12887*y^85 + 445*y^84 + 26322*y^83 + 37045*y^82 + 4486*y^81 + 3503*y^80 + 1184*y^79 + 38471*y^78 + 8012*y^77 + 36561*y^76 + 19429*y^75 + 35227*y^74 + 10813*y^73 + 26341*y^72 + 29474*y^71 + 2059*y^70 + 16068*y^69 + 31597*y^68 + 14685*y^67 + 9266*y^66 + 31019*y^65 + 6171*y^64 + 385*y^63 + 28986*y^62 + 9912*y^61 + 10632*y^60 + 33741*y^59 + 12634*y^58 + 21179*y^57 + 35548*y^56 + 17894*y^55 + 7152*y^54 + 9440*y^53 + 4004*y^52 + 2600*y^51 + 12281*y^50 + 22*y^49 + 17314*y^48 + 32694*y^47 + 7693*y^46 + 6567*y^45 + 19897*y^44 + 27329*y^43 + 8799*y^42 + 36348*y^41 + 33963*y^40 + 23730*y^39 + 27685*y^38 + 29037*y^37 + 14622*y^36 + 29608*y^35 + 39588*y^34 + 23294*y^33 + 757*y^32 + 20140*y^31 + 19511*y^30 + 1469*y^29 + 3898*y^28 + 6630*y^27 + 19610*y^26 + 11631*y^25 + 7188*y^24 + 11683*y^23 + 35611*y^22 + 37286*y^21 + 32139*y^20 + 20296*y^19 + 36426*y^18 + 25340*y^17 + 36204*y^16 + 37787*y^15 + 31256*y^14 + 505*y^13 + 27508*y^12 + 20885*y^11 + 32037*y^10 + 31236*y^9 + 7929*y^8 + 27195*y^7 + 28980*y^6 + 11863*y^5 + 16025*y^4 + 16389*y^3 + 570*y^2 + 36547*y + 10451
#C:3552*x^92 + 6082*x^91 + 25295*x^90 + 35988*x^89 + 26052*x^88 + 16987*x^87 + 12854*x^86 + 25117*x^85 + 25800*x^84 + 30297*x^83 + 5589*x^82 + 23233*x^81 + 14449*x^80 + 4712*x^79 + 35719*x^78 + 1696*x^77 + 35653*x^76 + 13995*x^75 + 13715*x^74 + 4578*x^73 + 37366*x^72 + 25260*x^71 + 28865*x^70 + 36120*x^69 + 7047*x^68 + 10497*x^67 + 19160*x^66 + 17939*x^65 + 14850*x^64 + 6705*x^63 + 17805*x^62 + 30083*x^61 + 2400*x^60 + 10685*x^59 + 15272*x^58 + 2225*x^57 + 13194*x^56 + 14251*x^55 + 31016*x^54 + 10189*x^53 + 35040*x^52 + 7042*x^51 + 29206*x^50 + 39363*x^49 + 32608*x^48 + 38614*x^47 + 5528*x^46 + 20119*x^45 + 13439*x^44 + 25468*x^43 + 30056*x^42 + 19720*x^41 + 21808*x^40 + 3712*x^39 + 25243*x^38 + 10606*x^37 + 16247*x^36 + 36106*x^35 + 17287*x^34 + 36276*x^33 + 1407*x^32 + 28839*x^31 + 8459*x^30 + 38863*x^29 + 435*x^28 + 913*x^27 + 36619*x^26 + 15572*x^25 + 9363*x^24 + 36837*x^23 + 17925*x^22 + 38567*x^21 + 38709*x^20 + 13582*x^19 + 35038*x^18 + 31121*x^17 + 8933*x^16 + 1666*x^15 + 21940*x^14 + 25585*x^13 + 840*x^12 + 21938*x^11 + 20143*x^10 + 28507*x^9 + 5947*x^8 + 20289*x^7 + 32196*x^6 + 924*x^5 + 370*x^4 + 14849*x^3 + 10780*x^2 + 14035*x + 15327

题解

常规的多项式rsa。

没了解过的话,可以去lazzaro师傅博客里翻一翻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import gmpy2, libnum
p = 40031
S.<x> = PolynomialRing(GF(p))
y = x
N=24096*y^93 + 38785*y^92 + 17489*y^91 + 9067*y^90 + 1034*y^89 + 6534*y^88 + 35818*y^87 + 22046*y^86 + 12887*y^85 + 445*y^84 + 26322*y^83 + 37045*y^82 + 4486*y^81 + 3503*y^80 + 1184*y^79 + 38471*y^78 + 8012*y^77 + 36561*y^76 + 19429*y^75 + 35227*y^74 + 10813*y^73 + 26341*y^72 + 29474*y^71 + 2059*y^70 + 16068*y^69 + 31597*y^68 + 14685*y^67 + 9266*y^66 + 31019*y^65 + 6171*y^64 + 385*y^63 + 28986*y^62 + 9912*y^61 + 10632*y^60 + 33741*y^59 + 12634*y^58 + 21179*y^57 + 35548*y^56 + 17894*y^55 + 7152*y^54 + 9440*y^53 + 4004*y^52 + 2600*y^51 + 12281*y^50 + 22*y^49 + 17314*y^48 + 32694*y^47 + 7693*y^46 + 6567*y^45 + 19897*y^44 + 27329*y^43 + 8799*y^42 + 36348*y^41 + 33963*y^40 + 23730*y^39 + 27685*y^38 + 29037*y^37 + 14622*y^36 + 29608*y^35 + 39588*y^34 + 23294*y^33 + 757*y^32 + 20140*y^31 + 19511*y^30 + 1469*y^29 + 3898*y^28 + 6630*y^27 + 19610*y^26 + 11631*y^25 + 7188*y^24 + 11683*y^23 + 35611*y^22 + 37286*y^21 + 32139*y^20 + 20296*y^19 + 36426*y^18 + 25340*y^17 + 36204*y^16 + 37787*y^15 + 31256*y^14 + 505*y^13 + 27508*y^12 + 20885*y^11 + 32037*y^10 + 31236*y^9 + 7929*y^8 + 27195*y^7 + 28980*y^6 + 11863*y^5 + 16025*y^4 + 16389*y^3 + 570*y^2 + 36547*y + 10451
C=3552*x^92 + 6082*x^91 + 25295*x^90 + 35988*x^89 + 26052*x^88 + 16987*x^87 + 12854*x^86 + 25117*x^85 + 25800*x^84 + 30297*x^83 + 5589*x^82 + 23233*x^81 + 14449*x^80 + 4712*x^79 + 35719*x^78 + 1696*x^77 + 35653*x^76 + 13995*x^75 + 13715*x^74 + 4578*x^73 + 37366*x^72 + 25260*x^71 + 28865*x^70 + 36120*x^69 + 7047*x^68 + 10497*x^67 + 19160*x^66 + 17939*x^65 + 14850*x^64 + 6705*x^63 + 17805*x^62 + 30083*x^61 + 2400*x^60 + 10685*x^59 + 15272*x^58 + 2225*x^57 + 13194*x^56 + 14251*x^55 + 31016*x^54 + 10189*x^53 + 35040*x^52 + 7042*x^51 + 29206*x^50 + 39363*x^49 + 32608*x^48 + 38614*x^47 + 5528*x^46 + 20119*x^45 + 13439*x^44 + 25468*x^43 + 30056*x^42 + 19720*x^41 + 21808*x^40 + 3712*x^39 + 25243*x^38 + 10606*x^37 + 16247*x^36 + 36106*x^35 + 17287*x^34 + 36276*x^33 + 1407*x^32 + 28839*x^31 + 8459*x^30 + 38863*x^29 + 435*x^28 + 913*x^27 + 36619*x^26 + 15572*x^25 + 9363*x^24 + 36837*x^23 + 17925*x^22 + 38567*x^21 + 38709*x^20 + 13582*x^19 + 35038*x^18 + 31121*x^17 + 8933*x^16 + 1666*x^15 + 21940*x^14 + 25585*x^13 + 840*x^12 + 21938*x^11 + 20143*x^10 + 28507*x^9 + 5947*x^8 + 20289*x^7 + 32196*x^6 + 924*x^5 + 370*x^4 + 14849*x^3 + 10780*x^2 + 14035*x + 15327
e = 65537
roots = factor(N)
P = roots[0][0]
Q = roots[1][0]
PHI = (p^P.degree()-1)*(p^Q.degree()-1)
D = int(gmpy2.invert(e, PHI))
M = pow(C,D,N)
print(M)
hint = ''.join([chr(i) for i in M])
print(hint)
# NKCTF{We_HaV3_n0th1ng_But_dr3amS}

eZ_Bl⊕ck

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from Crypto.Util.strxor import strxor as xor
import os
from secret import flag


def round(s, k):
l, r = s[:16], s[16:]
l_, r_ = xor(xor(r, k), l), l
return l_ + r_


def encode(s, k):
t = s
for i in range(8):
t = round(t, k[i])
return t


r = os.urandom(32)
print(r)

key = [os.urandom(16) for _ in range(8)]

print(encode(r, key))
m = flag.strip(b'NKCTF{').strip(b'}').replace(b'-', b'')
print(encode(m, key))

# b"t\xf7\xaa\xac\x9d\x88\xa4\x8b\x1f+pA\x84\xacHg'\x07{\xcc\x06\xc4i\xdd)\xda\xc9\xad\xa9\xe8\x1fi"
# b"'{<z}\x91\xda\xc5\xd5S\x8b\xfa\x9f~]J\x0f\xf4\x9a\x1e\xe0\xef\x129N\xe7a\x928+\xe0\xee"
# b'8\x1f"\x83B4\x86)\xce\xebq3\x06\xa0w\x16U\x04M/w\xa1\x8f;)M\xdd~\x11:\xe3\xb3'

题解

手动浅推一下,会发现r加密和flag加密后的“格式”是一致的,所以两者对应分段异或能消去key

在不具体推理其余变量的情况下,可以直接尝试异或所有可能分段,即解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from Crypto.Util.strxor import strxor as xor

r = b"t\xf7\xaa\xac\x9d\x88\xa4\x8b\x1f+pA\x84\xacHg'\x07{\xcc\x06\xc4i\xdd)\xda\xc9\xad\xa9\xe8\x1fi"
enc1 = b"'{<z}\x91\xda\xc5\xd5S\x8b\xfa\x9f~]J\x0f\xf4\x9a\x1e\xe0\xef\x129N\xe7a\x928+\xe0\xee"
enc2 = b'8\x1f"\x83B4\x86)\xce\xebq3\x06\xa0w\x16U\x04M/w\xa1\x8f;)M\xdd~\x11:\xe3\xb3'
t1 = xor(enc2[:16], enc1[:16])
t2 = xor(enc2[16:], enc1[16:])
r1 = r[:16]
r2 = r[16:]
# print(xor(t1, r1))
# print(xor(t2, r1))

print(xor(t1, r2)) # this
flag1 = xor(t1, r2)
# print(xor(t2, r2))

# print(xor(xor(t1, r1), r2))
# print(xor(xor(t2, r1), r2))

# print(xor(t2, r1))
# print(xor(t2, r2))
# print(xor(xor(t2, r1), r2))
tt = xor(t2, flag1)
# print(xor(tt, r1))
# print(xor(tt, r2))
print(xor(xor(tt, r1), r2)) # this
flag2 = xor(xor(tt, r1), r2)
print(flag2+flag1) # 改为UUID格式
# NKCTF{1ccd5cee-c96d-4caf-8ce5-9a512b3d0655}

easy_high

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Util.number import *
flag = ''

p, q = getPrime(1024), getPrime(1024)
N = p * q
p0 = p ^ (bytes_to_long(flag)<<444)
m = bytes_to_long(flag)
c = pow(m, 65537, N)
print('c=',c)
print('N=',N)
print('p0=',p0)

#c= 4881545863615247924697512170011400857004555681758106351259776881249360423774694437921554056529064037535796844084045263140567168171628832384672612945806728465127954937293787045302307135365408938448006548465000663247116917564500525499976139556325841597810084111303039525833367199565266613007333465332710833102978756654324956219855687611590278570749890543277201538208370370097424105751568285050703167350889953331829275262932104042040526209179357770495596739361176548337593674366015027648541293309465113202672923556991818236011769228078267484362980348613669012975963468592763463397575879215173972436831753615524193609612
#N= 17192509201635459965397076685948071839556595198733884616568925970608227408244870123644193452116734188924766414178232653941867668088060274364830452998991993756231372252367134508712447410029668020439498980619263308413952840568602285764163331028384281840387206878673090608323292785024372223569438874557728414737773416206032540038861064700108597448191546413236875600906013508022023794395360001242071569785940215873854748631691555516626235191098174739613181230094797844414203694879874212340812119576042962565179579136753839946922829803044355134086779223242080575811804564731938746051591474236147749401914216734714709281349
#p0= 149263925308155304734002881595820602641174737629551638146384199378753884153459661375931646716325020758837194837271581361322079811468970876532640273110966545339040194118880506352109559900553776706613338890047890747811129988585025948270181264314668772556874718178868209009192010129918138140332707080927643141811

题解

通过p0能得到p高位以及p低444位数据,设p中间位,coppersmith求解后即可rsa解密得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import libnum, gmpy2

e = 65537
c= 4881545863615247924697512170011400857004555681758106351259776881249360423774694437921554056529064037535796844084045263140567168171628832384672612945806728465127954937293787045302307135365408938448006548465000663247116917564500525499976139556325841597810084111303039525833367199565266613007333465332710833102978756654324956219855687611590278570749890543277201538208370370097424105751568285050703167350889953331829275262932104042040526209179357770495596739361176548337593674366015027648541293309465113202672923556991818236011769228078267484362980348613669012975963468592763463397575879215173972436831753615524193609612
N= 17192509201635459965397076685948071839556595198733884616568925970608227408244870123644193452116734188924766414178232653941867668088060274364830452998991993756231372252367134508712447410029668020439498980619263308413952840568602285764163331028384281840387206878673090608323292785024372223569438874557728414737773416206032540038861064700108597448191546413236875600906013508022023794395360001242071569785940215873854748631691555516626235191098174739613181230094797844414203694879874212340812119576042962565179579136753839946922829803044355134086779223242080575811804564731938746051591474236147749401914216734714709281349
p0= 149263925308155304734002881595820602641174737629551638146384199378753884153459661375931646716325020758837194837271581361322079811468970876532640273110966545339040194118880506352109559900553776706613338890047890747811129988585025948270181264314668772556874718178868209009192010129918138140332707080927643141811
flag_len = 400
p_high =(p0>>(flag_len+444))<<400+444

p_low = p0%(2^444)
PR.<x> = PolynomialRing(Zmod(N))
f = p_high+x*2^444+p_low
f = f.monic()
x = f.small_roots(X=2^flag_len, beta=0.4)
print(x)
p = int(p_high+x[0]*2^444+p_low)
q = N//p
print(p)
print(q)

d = int(gmpy2.invert(e, (p-1)*(q-1)))
m = int(pow(c, d, N))
print(libnum.n2s(m))
# NKCTF{F10wrs_hVe_r3strDay}

eZ_LargeCG

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from gmpy2 import next_prime
from Crypto.Util.number import getPrime, isPrime, bytes_to_long
import random
from secret import flag

def init():
primes = []
p = 1
while len(primes) < 100:
p = next_prime(p)
primes.append(int(p))
return primes

def genMyPrimeA(bits):
while True:
g = 2
while g < 2 ** bits:
g *= random.choice(primes)
g += 1
if isPrime(g):
return g

def genMyPrimeB(bits):
while True:
g = 2
while g < 2 ** bits:
g *= random.choice(primes)
g -= 1
if isPrime(g):
return g

def gen(st, n, a, b, c, d):
A = [st + 2023, st + 2024, st + 2025]
for i in range(6**666):
A.append((a * A[-3] + b * A[-2] + c * A[-1] + d) % n)
return A

primes = init()
p1 = getPrime(256)
print(p1)
q1 = 1
while p1 > q1:
q1 = genMyPrimeA(256)
print(q1)
p2 = getPrime(256)
q2 = 1
while p2 > q2:
q2 = genMyPrimeB(256)
n1 = p1 * q1
n2 = p2 * q2
print(f'n1 = {n1}')
print(f'n2 = {n2}')

r = getPrime(512)
print(f'r = {r}')

A = gen(bytes_to_long(flag), r, p1, q1, p2, q2)
print(f'A[-3] = {A[-3]}')
print(f'A[-2] = {A[-2]}')
print(f'A[-1] = {A[-1]}')


# n1 = 39755206609675677517559022219519767646524455449142889144073217274247893104711318356648198334858966762944109142752432641040037415587397244438634301062818169
# n2 = 30725253491966558227957591684441310073288683324213439179377278006583428660031769862224980605664642101191616868994066039054762100886678504154619135365646221
# r = 7948275435515074902473978567170931671982245044864706132834233483354166398627204583162848756424199888842910697874390403881343013872330344844971750121043493
# A[-3] = 6085327340671394838391386566774092636784105046872311226269065664501131836034666722102264842236327898770287752026397099940098916322051606027565395747098434
# A[-2] = 1385551782355619987198268805270109182589006873371541520953112424858566073422289235930944613836387546298080386848159955053303343649615385527645536504580787
# A[-1] = 2529291156468264643335767070801583140819639532551726975314270127875306069067016825677707064451364791677536138503947465612206191051563106705150921639560469

题解

原题,参考https://blog.csdn.net/m0_51507437/article/details/124205732

  1. p-1/p+1光滑分解n
  2. 矩阵快速幂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import libnum
"""
from gmpy2 import *
from primefac import *
n1 = 39755206609675677517559022219519767646524455449142889144073217274247893104711318356648198334858966762944109142752432641040037415587397244438634301062818169
n2 = 30725253491966558227957591684441310073288683324213439179377278006583428660031769862224980605664642101191616868994066039054762100886678504154619135365646221


N = n1
a = 2
n = 2
while True:
a = powmod(a, n, N)
res = gcd(a-1, N)
if res != 1 and res != N:
q1 = N // res
p1 = res
print(p1)
print(q1)
break
n += 1

def mlucas(v, a, n):
""" Helper function for williams_pp1(). Multiplies along a Lucas sequence modulo n. """
v1, v2 = v, (v**2 - 2) % n
for bit in bin(a)[3:]: v1, v2 = ((v1**2 - 2) % n, (v1*v2 - v) % n) if bit == "0" else ((v1*v2 - v) % n, (v2**2 - 2) % n)
return v1
n = n2
for v in count(1):
for p in primegen():
e = ilog(isqrt(n), p)
if e == 0: break
for _ in range(e): v = mlucas(v, p, n)
g = gcd(v-2, n)
if 1 < g < n:
p2 = g
q2 = n2//p2
print(p2)
print(q2)
exit(0)
if g == n: break
"""


x = 6085327340671394838391386566774092636784105046872311226269065664501131836034666722102264842236327898770287752026397099940098916322051606027565395747098434
y = 1385551782355619987198268805270109182589006873371541520953112424858566073422289235930944613836387546298080386848159955053303343649615385527645536504580787
z = 2529291156468264643335767070801583140819639532551726975314270127875306069067016825677707064451364791677536138503947465612206191051563106705150921639560469

# def gen(st, n, a, b, c, d):
# A = gen(bytes_to_long(flag), r, p1, q1, p2, q2)
n1 = 39755206609675677517559022219519767646524455449142889144073217274247893104711318356648198334858966762944109142752432641040037415587397244438634301062818169
n2 = 30725253491966558227957591684441310073288683324213439179377278006583428660031769862224980605664642101191616868994066039054762100886678504154619135365646221
p1 = 427721675251610827084310512123962488210068003845592404231631542730839819224381
q1 = 92946439027877993602295703905130336736159270745389239059083263513478865293549
p2 = 288551157776490110472645044398395422160196115791981535735903775378294599329633
q2 = n2//p2
r = 7948275435515074902473978567170931671982245044864706132834233483354166398627204583162848756424199888842910697874390403881343013872330344844971750121043493

if p1 > q1:
p1, q1 = q1, p1

if p2 > q2:
p2, q2 = q2, p2
a = p1
b = q1
c = p2
d =q2
mt=matrix(Zmod(r),4,4)
mt[0]=[c,b,a,d]
mt[1]=[1,0,0,0]
mt[2]=[0,1,0,0]
mt[3]=[0,0,0,1]

mn=matrix(Zmod(r),4,1,[z,y,x,1])
# 6**666
X=(mt^(pow(6,666))).solve_right(mn)
flag = X[2][0]-2023
print(libnum.n2s(int(flag)))
# NKCTF{y0u_kN0w_r5A_&_LCg_&_Ma7r1X_s0_w3ll!!!}

complex_matrix

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import *
import gmpy2 as gy
flag = ''


k = 400
p, q = getPrime(741), getPrime(741)
N = p * q
phi = (p-1) * (q-1)
_flag = bytes_to_long(flag)
p, q = getPrime(1024), getPrime(1024)
d_array = [getPrime(k) for _ in range(4)]
e_array = [inverse(i, phi) for i in d_array]
c = pow(_flag, 65537, N)
print('N:',N)
print('e:',e_array)
print('c:',c)

#N: 71841248095369087024928175623295380241516644434969868335504061065977014103487197287619667598363486210886674500469383623511906399909335989202774281795855975972913438448899231650449810696539722877903606541112937729384851506921675290984316325565141178015123381439392534417225128922398194700511937668809140024838070124095703585627058463137549632965723304713166804084673075651182998654091113119667582720831809458721072371364839503563819080226784026253
#e: [65128799196671634905309494529154568614228788035735808211836905142007976099865571126946706559109393187772126407982007858423859147772762638898854472065889939549916077695303157760259717113616428849798058080633047516455513870697383339784816006154279428812359241282979297285283850338964993773227397528608557211742425548651971558377656644211835094019462699301650412862894391885325969143805924684662849869947172175608502179438901337558870349697233790535, 58756559706647121529575085912021603170286163639572075337348109911506627489265537716060463072086480156516641723700802217411122982693536541892986623158818442274840863016647800896033363360822503445344748132842451806511693779600370832206455202293028402486647422212959763287987847280322100701242139127654031151565924132562837893975505159702015125483479126108892709063135006366792197127007229210558758401679638300464111782814561428899998471531067163715, 34828685390969672139784723764579499920301439564705391196519314224159563070870933754477650614819514127121146216049444888554338415587165719098661141454627820126445291802801256297252654045398330613075575527685542980264993711077876535643646746742646371967302159565887123638001580042027272379341650995728849759541960087953160211696369079708787543303742132161742979856720539914370868829868891655221361545648778590685232034703220732697083024449894197969, 26717968456600556973167180286909817773394160817933525240720067057464671317174201540556176814203780603153696663101158205367554829261808020426363683474848952397963507069306452835776851274959389849223566030857588019845781623271395012194869024566879791449466064832273531795430185178486425688475688634844530106740480643866537205900809400383304665727460014210405339697947582657505028211149470787536144302545259243549176816653560626044921521516818788487]
#c: 39297018404565022956251803918747154798377576057123078716166221329195959669756819453426741569480551313085435037629493881038383709458043802420338889323233368852331387845200216275712388921820794980987541224782392553528127093154957890356084331463340193478391679540506421250562554424770350351514435220782124981277580072039637811543914983033300225131364246910828188727043248991987332274929827173923543187017105236008487756190002204169623313222748976369

题解

西湖论剑2021原题,参考https://www.ctfer.vip/note/set/51

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import gmpy2
import libnum
isdigit = lambda x: ord('0') <= ord(x) <= ord('9')

def my_permutations(g, n):
sub = []
res = []
def dfs(s, prev):
if len(s) == n:
res.append(s[::])
for i in g:
if i in s or i < prev:
continue
s.append(i)
dfs(s, max(prev, i))
s.remove(i)
dfs(sub, 0)
return res

class X3NNY(object):
def __init__(self, exp1, exp2):
self.exp1 = exp1
self.exp2 = exp2

def __mul__(self, b):
return X3NNY(self.exp1 * b.exp1, self.exp2 * b.exp2)

def __repr__(self):
return '%s = %s' % (self.exp1.expand().collect_common_factors(), self.exp2)

class X_Complex(object):
def __init__(self, exp):
i = 0
s = '%s' % exp
while i < len(s):
if isdigit(s[i]):
num = 0
while i < len(s) and isdigit(s[i]):
num = num*10 + int(s[i])
i += 1
if i >= len(s):
self.b = num
elif s[i] == '*':
self.a = num
i += 2
elif s[i] == '/':
i += 1
r = 0
while i < len(s) and isdigit(s[i]):
r = r*10 + int(s[i])
i += 1
self.b = num/r
else:
i += 1
if not hasattr(self, 'a'):
self.a = 1
if not hasattr(self, 'b'):
self.b = 0

def WW(e, d, k, g, N, s):
return X3NNY(e*d*g-k*N, g+k*s)
def GG(e1, e2, d1, d2, k1, k2):
return X3NNY(e1*d1*k2- e2*d2*k1, k2 - k1)

def W(i):
e = eval("e%d" % i)
d = eval("d%d" % i)
k = eval("k%d" % i)
return WW(e, d, k, g, N, s)

def G(i, j):
e1 = eval("e%d" % i)
d1 = eval("d%d" % i)
k1 = eval("k%d" % i)

e2 = eval("e%d" % j)
d2 = eval("d%d" % j)
k2 = eval("k%d" % j)

return GG(e1, e2, d1, d2, k1, k2)

def R(e, sn): # min u max v
ret = X3NNY(1, 1)
n = max(e)
nn = len(e)
l = set(i for i in range(1, n+1))
debug = ''
u, v = 0, 0
for i in e:
if i == 1:
ret *= W(1)
debug += 'W(%d)' % i
nn -= 1
l.remove(1)
u += 1
elif i > min(l) and len(l) >= 2*nn:
ret *= G(min(l), i)
nn -= 1
debug += 'G(%d, %d)' % (min(l), i)
l.remove(min(l))
l.remove(i)
v += 1
else:
ret *= W(i)
l.remove(i)
debug += 'W(%d)' % i
nn -= 1
u += 1
# print(debug, end = ' ')
return ret, u/2 + (sn - v) * a

def H(n):
if n == 0:
return [0]
if n == 2:
return [(), (1,), (2,), (1, 2)]
ret = []
for i in range(3, n+1):
ret.append((i,))
for j in range(1, i):
for k in my_permutations(range(1, i), j):
ret.append(tuple(k + [i]))
return H(2) + ret

def CC(exp, n):
cols = [0 for i in range(1<<n)]

# split exp
texps = ('%s' % exp.exp1.expand()).strip().split(' - ')
ops = []
exps = []
for i in range(len(texps)):
if texps[i].find(' + ') != -1:
tmp = texps[i].split(' + ')
ops.append(0)
exps.append(tmp[0])
for i in range(1, len(tmp)):
ops.append(1)
exps.append(tmp[i])
else:
ops.append(0)
exps.append(texps[i])
if exps[0][0] == '-':
for i in range(len(exps)):
ops[i] = 1-ops[i]
exps[0] = exps[0][1:]
else:
ops[0] = 1
# find e and N
l = []
for i in range(len(exps)):
tmp = 1 if ops[i] else -1
en = []
j = 0
while j < len(exps[i]):
if exps[i][j] == 'e':
num = 0
j += 1
while isdigit(exps[i][j]):
num = num*10 + int(exps[i][j])
j += 1
tmp *= eval('e%d' % num)
en.append(num)
elif exps[i][j] == 'N':
j += 1
num = 0
if exps[i][j] == '^':
j += 1
while isdigit(exps[i][j]):
num = num*10 + int(exps[i][j])
j += 1
if num == 0:
num = 1
tmp *= eval('N**%d' % num)
else:
j += 1
if tmp == 1 or tmp == -1:
l.append((0, ()))
else:
l.append((tmp, tuple(sorted(en))))

# construct h
mp = H(n)
for val, en in l:
cols[mp.index(en)] = val
# print(cols)
return cols

def EWA(n, elist, NN, alpha):
mp = H(n)
var('a')
S = [X_Complex(n*a)]
cols = [[1 if i == 0 else 0 for i in range(2^n)]]
for i in mp[1:]:
eL, s = R(i, n)
cols.append(CC(eL, n))
S.append(X_Complex(s))

alphaA,alphaB = 0, 0
for i in S:
alphaA = max(i.a, alphaA)
alphaB = max(i.b, alphaB)
# print(alphaA, alphaB)
D = []
for i in range(len(S)):
# print((alphaA-S[i].a), (alphaB - S[i].b))
D.append(
int(NN^((alphaA-S[i].a)*alpha + (alphaB - S[i].b)))
)
kw = {'N': NN}
for i in range(len(elist)):
kw['e%d' % (i+1)] = elist[i]

B = Matrix(ZZ, Matrix(cols).T(**kw)) * diagonal_matrix(ZZ, D)
L = B.LLL(0.5)
v = Matrix(ZZ, L[0])
x = v * B**(-1)
phi = int(x[0,1]/x[0,0]*elist[0])
return phi

def attack(NN, elist, alpha):
phi = EWA(len(elist), elist, NN, alpha)
print(phi)
return phi


NN = 71841248095369087024928175623295380241516644434969868335504061065977014103487197287619667598363486210886674500469383623511906399909335989202774281795855975972913438448899231650449810696539722877903606541112937729384851506921675290984316325565141178015123381439392534417225128922398194700511937668809140024838070124095703585627058463137549632965723304713166804084673075651182998654091113119667582720831809458721072371364839503563819080226784026253
elist = [65128799196671634905309494529154568614228788035735808211836905142007976099865571126946706559109393187772126407982007858423859147772762638898854472065889939549916077695303157760259717113616428849798058080633047516455513870697383339784816006154279428812359241282979297285283850338964993773227397528608557211742425548651971558377656644211835094019462699301650412862894391885325969143805924684662849869947172175608502179438901337558870349697233790535, 58756559706647121529575085912021603170286163639572075337348109911506627489265537716060463072086480156516641723700802217411122982693536541892986623158818442274840863016647800896033363360822503445344748132842451806511693779600370832206455202293028402486647422212959763287987847280322100701242139127654031151565924132562837893975505159702015125483479126108892709063135006366792197127007229210558758401679638300464111782814561428899998471531067163715, 34828685390969672139784723764579499920301439564705391196519314224159563070870933754477650614819514127121146216049444888554338415587165719098661141454627820126445291802801256297252654045398330613075575527685542980264993711077876535643646746742646371967302159565887123638001580042027272379341650995728849759541960087953160211696369079708787543303742132161742979856720539914370868829868891655221361545648778590685232034703220732697083024449894197969, 26717968456600556973167180286909817773394160817933525240720067057464671317174201540556176814203780603153696663101158205367554829261808020426363683474848952397963507069306452835776851274959389849223566030857588019845781623271395012194869024566879791449466064832273531795430185178486425688475688634844530106740480643866537205900809400383304665727460014210405339697947582657505028211149470787536144302545259243549176816653560626044921521516818788487]
c = 39297018404565022956251803918747154798377576057123078716166221329195959669756819453426741569480551313085435037629493881038383709458043802420338889323233368852331387845200216275712388921820794980987541224782392553528127093154957890356084331463340193478391679540506421250562554424770350351514435220782124981277580072039637811543914983033300225131364246910828188727043248991987332274929827173923543187017105236008487756190002204169623313222748976369
alpha = 400 / int(NN).bit_length()
for i in range(1, len(elist)+1):
var("e%d" % i)
var("d%d" % i)
var("k%d" % i)
g, N, s = var('g'), var('N'), var('s')

for i in range(len(elist)):
elist[i] = Integer(elist[i])
phi = attack(NN, elist, alpha)

d = gmpy2.invert(65537, phi)
m = int(pow(c, d, NN))
print(libnum.n2s(m))
# NKCTF{F10w3r_Hav3_r3start_Day_N0_Man_iS_Y0ung_Aga1n}

baby_classical

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import string
import re
import numpy as np
flag = ''
print('flag length:',len(flag))
dic = string.ascii_uppercase+string.ascii_lowercase+string.digits+'+/'
f1nd = lambda x : dic.find(x)
class KeyEncryption:
def __init__(self, m: int, fillchar: str="z", key: np.ndarray=None):
self.m = m
self.key = key
self.dicn2s = {i: dic[i] for i in range(64)}
self.dics2n = dict(zip(self.dicn2s.values(), self.dicn2s.keys()))
self.fillchar = self.dics2n[fillchar]
def setM(self, m: int) -> None:
assert m > 0
self.m = m
def setKey(self, key: np.ndarray=None) -> None:
if key is None:
while key is None or KeyEncryption.modInv(np.linalg.det(key)) == -1:
key = np.random.randint(0, 65, size=(self.m, self.m))
print("random matrix:\n", key)
else:
assert KeyEncryption.modInv(np.linalg.det(key)) != -1
self.key = key
@staticmethod
def modInv(x: int):
y = 0
while y < 64:
y += 1
if (x * y) % 64 == 1:
return y
return -1
def _loopCrypt(self, long: np.ndarray, K: np.ndarray) -> np.ndarray:
ans = np.array([])
for i in range(long.shape[0] // self.m):
ans = np.mod(np.hstack((
ans,
np.dot(long[i*self.m:i*self.m+self.m], K)
)), 64)
return ans.astype(np.int64)
def encrypt(self, plaintext: np.ndarray):
assert self.m !=None and self.key is not None
if plaintext.shape[0] % self.m:
plaintext = np.hstack((
plaintext,
[self.fillchar] *(self.m - plaintext.shape[0] % self.m)
))
return self._loopCrypt(plaintext, self.key)
def translate(self, s, to: str):
if to == "text":
return "".join([self.dicn2s[si] for si in s])
elif to == "num":
s = s.replace(" ", "")
return np.array([self.dics2n[si] for si in s])
def getKey(key):
he = KeyEncryption(m=3)
he.setKey()
nums = he.translate(key, "num")
res = he.encrypt(nums)
enkey = ''.join(dic[i] for i in res.tolist())
print('Encrypt key:',enkey)
return enkey
if __name__ == '__main__':
fir1 = ' '.join(map(lambda _:_[::-1],re.split("[ { _ } ]" , flag.swapcase())))
ciphertext1 = ''
key = ""
enkey = getKey(key)
_enkey=[f1nd(i) for i in key]
print('key lengeh:',len(_enkey))
j = 0
for i in fir1:
if f1nd(i)>=0:
ciphertext1 += dic[(f1nd(i) + _enkey[j % len(_enkey)])%64]
else:
ciphertext1 += i
j += 1
ciphertext = ciphertext1.replace(' ','_')
print('ciphertext:%s{%s}' % (ciphertext[0:5],ciphertext[6:-1]))

'''
flag length: 48
random matrix:
[[13 37 10]
[15 17 41]
[13 0 10]]
Encrypt key: pVvRe/G08rLhfwa
key lengeh: 14
ciphertext:1k2Pe{24seBl4_a6Ot_fp7O1_eHk_Plg3EF_g/JtIonut4/}
'''

题解

矩阵逆运算(chatgpt写的)恢复key,然后再恢复flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import string
import numpy as np

dic = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'
f1nd = lambda x: dic.find(x)


class KeyEncryption:
def __init__(self, m: int, fillchar: str = "z", key: np.ndarray = None):
self.m = m
self.key = key
self.dicn2s = {i: dic[i] for i in range(64)}
print("self.dicn2s =", self.dicn2s)
self.dics2n = dict(zip(self.dicn2s.values(), self.dicn2s.keys()))
print("self.dics2n =", self.dics2n)
self.fillchar = self.dics2n[fillchar]
print("fillchar =", self.fillchar)

def setM(self, m: int) -> None:
assert m > 0
self.m = m

def setKey(self, key: np.ndarray = None) -> None:
if key is None:
while key is None or KeyEncryption.modInv(np.linalg.det(key)) == -1:
key = np.random.randint(0, 65, size=(self.m, self.m))
print("random matrix:\n", key)
else:
assert KeyEncryption.modInv(np.linalg.det(key)) != -1
self.key = key

@staticmethod
def modInv(x: int):
y = 0
while y < 64:
y += 1
if (x * y) % 64 == 1:
return y
return -1

def _loopCrypt(self, long: np.ndarray, K: np.ndarray) -> np.ndarray:
ans = np.array([])
for i in range(long.shape[0] // self.m):
ans = np.mod(np.hstack((
ans,
np.dot(long[i * self.m:i * self.m + self.m], K)
)), 64)
return ans.astype(np.int64)

def encrypt(self, plaintext: np.ndarray):
assert self.m != None and self.key is not None
if plaintext.shape[0] % self.m:
plaintext = np.hstack((
plaintext,
[self.fillchar] * (self.m - plaintext.shape[0] % self.m)
))
print("plaintext", plaintext)
return self._loopCrypt(plaintext, self.key)

def translate(self, s, to: str):
if to == "text":
return "".join([self.dicn2s[si] for si in s])
elif to == "num":
s = s.replace(" ", "")
return np.array([self.dics2n[si] for si in s])

def decrypt(self, ciphertext: np.ndarray) -> str:
self.key = np.array( [[13,37,10],[15,17,41],[13,0,10]])
assert self.m is not None and self.key is not None
plaintext = ''
inv_key = KeyEncryption.modInv(np.linalg.det(self.key)) * np.round(
np.linalg.inv(self.key) * np.linalg.det(self.key))
for i in range(ciphertext.shape[0] // self.m):
tmp = np.mod(np.dot(ciphertext[i * self.m:i * self.m + self.m], inv_key), 64)
plaintext += ''.join([self.dicn2s[int(tmp[j])] for j in range(self.m)])
plaintext = plaintext.rstrip(self.dicn2s[self.fillchar])
return plaintext



def getKey(key):
he = KeyEncryption(m=3)
he.setKey()
nums = he.translate(key, "num")
print("nums =", nums)

res = he.encrypt(nums)
print('res =', res)
enkey = ''.join(dic[i] for i in res.tolist())
print("res.tolist() =", res.tolist())
print('Encrypt key:', enkey)
return enkey

he = KeyEncryption(m=3)
enc_key = 'pVvRe/G08rLhfwa'
enc_key = [f1nd(i) for i in enc_key]
enc_key = np.array(enc_key)
key = he.decrypt(enc_key)
print(key)
_enkey = [f1nd(i) for i in key]

c = '1k2Pe{24seBl4_a6Ot_fp7O1_eHk_Plg3EF_g/JtIonut4/}'
j = 0
tmp = {}
flag = ''
for i in c:
if f1nd(i) >= 0:
# tmp = (f1nd(i) + _enkey[j % len(_enkey)]) % 64
tmp = (f1nd(i) - _enkey[j % len(_enkey)]) % 64
flag += dic[tmp]
else:
flag += i
j += 1
print(flag)

for i in flag.split('_'):
print(i[::-1])
print('CISsALc'[::-1])

# 手动转向
flag = 'nkctf{cLAsSIC_C0DE_D0L1S_ArE_R3A1LY_INT3REsTING}'.swapcase()
print(flag)
# NKCTF{ClaSsic_c0de_d0l1s_aRe_r3a1ly_int3reSting}

Raven

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env sage
# Problem by rec, with a bad raven.
import os, hashlib
from Crypto.Util.number import *
from Crypto.Cipher import AES

def Raven(n: int, secret: bytes):
H = lambda x: hashlib.md5(os.urandom(8) + x).digest()

p = getPrime(728)
R.<z> = PolynomialRing(GF(p))

seed = H(secret)
f = R(
[bytes_to_long(secret)] + [bytes_to_long(H(seed)) for _ in range(n - 1)]
)
x = [getRandomRange(2, p - 1) for _ in range(n)]
y = [ZZ(f(xi)^2 + getPrime(256)) for xi in x]

pairs = list(zip(x, y))
return p, pairs

flag = b'#####'
key = os.urandom(16)
cipher = AES.new(key=key, IV=bytes(range(16)), mode=AES.MODE_CBC)
ct = cipher.encrypt(flag + os.urandom(16 - len(flag) % 16))
p, pairs = Raven(4, key)

print(f"{p = }\n{pairs = }\n{ct = }")
'''
p = 1018551160851728231474335384388576586031917743463656622083024684199383855595168341728561337234276243780407755294430553694832049089534855113774546001494743212076463713621965520780122783825100696968959866614846174188401153
pairs = [(615358616404864757405587650175842125441380884418119777842292095751090237848084440177153221092040264723889917863863854377665802549748720692225139890884830475485512763149974948701807492663962748292710803434009673589337265, 84982753624462868217739962129526665082932464631118597651920986288766037499319751354013335054886685186857222944776560264528363811382359242656883760986496856164448940929282013856762706210675691655747370624405968909408102), (528363810186974800127873139379943131424126521611531830591311656948009967709310974894584084912262479395720199930206495204352231804549705720854271566421006481173043064265399467682307971910488405265826107365679757755866812, 496810092723839642457928776423789418365006215801711874210443222720529161066621876103037104247173440072986344011599384793861949574577559989016501090247331146721371126871470611440468688947950954988175225633457347666551944), (68711183101845981499596464753252121346970486988311398916877579778110690480447199642602267233989256728822535174215153145632158860662954277116345331672194812126361911061449082917955000137698138358926301360506687271134873, 995428771589393162202488762223106955302099250561593105620410424291405842350539887383005328242236156038373244928147473800972534658018117705291472213770335998508454938607290279268848513727721410314612261163489156360908800), (61574167546312883246262193556029081771904529137922128124933785599227801608271357738142074310192454183183340219301304405636497744152219785042075198056952749425345561162612590170550454476602892138914473795478531165181812, 618169326093802548516842299173393893046765466917311052414967158839652012130855552015876657514610755108820971877570295328618373296493668146691687291894702228119875561585283226588768969944781923428807766632578060221034862)]
ct = b"|2\xf0v7\x05Y\x89\r]\xe93s\rr)#3\xe9\x90%Z\x9a\xd9\x9ck\xba\xec]q\xb8\xf2'\xc8e~fL\xcf\x93\x00\xd6^s-\xc9\xd6M"
'''

题解

起初见到这题,一直在想是否存在不用格的巧妙解法,有些本能的回避格了。

最后无可奈何了才想着用格来解决这类似门限方案的问题。

问题核心如下:

定义函数:$f(x) = ax^3+bx^2+cx+d \mod p$

getPrime(256)为t,题目给出p、四组x以及对应的$f(x_i)^2+t_i \mod p$, 即:
$$
\begin{aligned} y_i &= f(x_i)^2+t_i \\ &= a^2x_i^6+2abx_i^5+(b^2+2ac)x_i^4+(2bcd+2ad)x_i^3+(c^2+2bd)x_i^2+2cdx_i + d^2 + t_i \mod p \end{aligned}
$$
也即:
$$
\begin{aligned} a^2x_i^6+2abx_i^5+(b^2+2ac)x_i^4+(2bcd+2ad)x_i^3+(c^2+2bd)x_i^2+2cdx_i + d^2 -y_i +kp &= -t_i \end{aligned}
$$
起初如下构造了格:
$$
\begin{bmatrix} d^2 & 2cd & c^2+2bd & 2bcd+2ad & b^2+2ac & 2ab & a^2 & 1 &k_1 & \cdots & k_4 \end{bmatrix} \begin{bmatrix} x_1^0 & \cdots & x_4^0 \\ x_1^1 & \cdots & x_4^1 \\ \vdots & \cdots & \vdots \\ x_1^6 & \cdots & x_4^6 \\ -y_1 & \cdots & -y_4 \\ p \\ & \ddots \\ & & p \end{bmatrix} = \begin{bmatrix} -t_1 & -t_2 & -t_3 & -t_4 \end{bmatrix}
$$
格构造的特别狭长,结果当然是规约失败了。

现想来这种非满秩的矩阵,LLL规约效果等效于用0填充成方阵后的效果。

赛时来不及细想,想起之前赛事第一次遇见门限方案时,我是用crt解的,其后看到hash师傅的格解法,没细究。

这次卡住了便再去学习了格的构造,最后得到:
$$
\begin{bmatrix} d^2 & 2cd & \cdots & b^2+2ac & 2ab & a^2 & 1 &k_1 & \cdots & k_4 \end{bmatrix}
\begin{bmatrix} 1 & & & & x_1^0 & \cdots & x_4^0 \\ & \ddots & & & \vdots & \vdots & \vdots \\ & & 1 & & x_1^6 & \cdots & x_4^6 \\ & & & 2^{256} & -y_1 & \cdots & -y_4 \\ &&&&p \\ &&&&& \ddots \\ & &&&&& p \end{bmatrix}
=
\begin{bmatrix} d^2 & 2cd & \cdots & b^2+2ac & 2ab & a^2 & 2^{256} &-t_1 & \cdots & -t_4 \end{bmatrix}
$$
(还是生疏,说来就是一开始的格忘记加单位矩阵了…)

本地实际测试,发现得到的$d^2$不太准确。

但$a^2,2ab,2cd$都是准确的,那么就可以间接求出d了。

再接下来就是常规的AES解密,总exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import libnum, gmpy2
from Crypto.Cipher import AES

p = 1018551160851728231474335384388576586031917743463656622083024684199383855595168341728561337234276243780407755294430553694832049089534855113774546001494743212076463713621965520780122783825100696968959866614846174188401153
pairs = [(615358616404864757405587650175842125441380884418119777842292095751090237848084440177153221092040264723889917863863854377665802549748720692225139890884830475485512763149974948701807492663962748292710803434009673589337265, 84982753624462868217739962129526665082932464631118597651920986288766037499319751354013335054886685186857222944776560264528363811382359242656883760986496856164448940929282013856762706210675691655747370624405968909408102), (528363810186974800127873139379943131424126521611531830591311656948009967709310974894584084912262479395720199930206495204352231804549705720854271566421006481173043064265399467682307971910488405265826107365679757755866812, 496810092723839642457928776423789418365006215801711874210443222720529161066621876103037104247173440072986344011599384793861949574577559989016501090247331146721371126871470611440468688947950954988175225633457347666551944), (68711183101845981499596464753252121346970486988311398916877579778110690480447199642602267233989256728822535174215153145632158860662954277116345331672194812126361911061449082917955000137698138358926301360506687271134873, 995428771589393162202488762223106955302099250561593105620410424291405842350539887383005328242236156038373244928147473800972534658018117705291472213770335998508454938607290279268848513727721410314612261163489156360908800), (61574167546312883246262193556029081771904529137922128124933785599227801608271357738142074310192454183183340219301304405636497744152219785042075198056952749425345561162612590170550454476602892138914473795478531165181812, 618169326093802548516842299173393893046765466917311052414967158839652012130855552015876657514610755108820971877570295328618373296493668146691687291894702228119875561585283226588768969944781923428807766632578060221034862)]
ct = b"|2\xf0v7\x05Y\x89\r]\xe93s\rr)#3\xe9\x90%Z\x9a\xd9\x9ck\xba\xec]q\xb8\xf2'\xc8e~fL\xcf\x93\x00\xd6^s-\xc9\xd6M"

L=Matrix(ZZ,12,12)
for i in range(7):
L[i,i]=1

for i in range(4):
for j in range(7):
L[j,8+i]=pairs[i][0]^(j)

tmp = 2^256

L[7,7]=tmp
for i in range(4):
L[7,i+8]=-pairs[i][1]
L[8+i,8+i]=p
L = L.LLL()[1]
a = int(gmpy2.iroot(abs(L[6]), 2)[0])
b = abs(L[5])//(2*a)
c = (abs(L[4])-b^2)//(2*a)
d = abs(L[1])//(2*c)
key = libnum.n2s(int(d))
cipher = AES.new(key=key, IV=bytes(range(16)), mode=AES.MODE_CBC)
print(cipher.decrypt(ct))
# nkctf{..escape..}

PsychoRandom (Unsolved)

题目

task.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# Problem by rec, with a toy generator.
import os, utils

seed = int(os.urandom(16).hex(), 16)
gen = utils.ToyGen(seed)

sec = b'#####'
assert b'nkctf' in sec

msg = b'##MSG FROM NK: ' + sec
enc = bytes(m ^ next(gen) for m in msg).hex()
print(enc)
# 9c1250e1fefb6012cf74a7fd0156cd1a2817ee9381d086a1561399f5b7f519e5abf4437739fa254cd35b241375292d73aa8b8e6ff61f4977da3c68a699156e6bfbe2c38d7b08eed07e40e831c25f5327a21847bb156060228e2b

utils.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class ToyGen:
def __init__(self, state):
self.nbits = 128
self.state = state & ((1 << self.nbits) - 1)

self.mask = 230336355081348639216651218083300669636

self.alpha = 237299571639771708626086074576623691999
self.beta = 83015690654496181240783151904447565127

def func0(self, steps=1):
for _ in range(steps):
res = self.state & self.mask
bit = sum([(res >> i) & 1 for i in range(self.nbits)]) & 1
self.state = ((self.state << 1) ^ bit) & ((1 << self.nbits) - 1)
return

def func1(self):
res = (self.state ^ self.beta) & self.alpha
bit = sum([(res >> i) & 1 for i in range(self.nbits)]) & 1
return bit

def __next__(self):
out = 0
for _ in range(8):
self.func0(37)
bit = self.func1()
out = (out << 1) ^ bit
return out

题解

差这道AK密码也因此队伍无缘总分第一,有些遗憾。

但反思起来,无论是平日知识学习还是赛事训练确实都或有意无意的回避流密码。

也没啥好回避的,学!

官方题解

比赛的最后阶段,瞪了这题四小时,赛时也发现了如下这点
$$
out = \sum\limits^{n} _ {i=1} (s_i \oplus b_i) \& a_i = (\sum\limits^{n} _ {i=1} s_i \& a_i) \oplus (\sum\limits^{n} _ {i=1} b_i \& a_i)
$$
($\sum \limits^{n} _ {i=1} (s_i \oplus b_i) \& a_i$表示 s的第i位b的第i位 异或 后再与 a的第i位进行 与运算 再把i从1到n的结果在GF(2)上求和)

记$\sum\limits^{n} _ {i=1} s_i \& a_i$为out’,则:
$$
out’ = \sum\limits^{n} _ {i=1} s_i \& a_i = out \oplus (\sum\limits^{n} _ {i=1} b_i \& a_i) = out \oplus 1
$$
(题目中a, b固定,能计算确定$\sum\limits^{n} _ {i=1} b_i \& a_i=1$)

赛时到这一步便卡死了,确实发现异或beta的效果等效于不异或的结果取反,但不知道如何用多组 每刷新37次状态再给出的out 来恢复某一时刻的状态。

看到官方wp思路用的是矩阵,也释然了。

其实能想到要用矩阵、多项式来描述、求解问题,但平时只做理论学习没怎么实际训练,赛时会不敢想、不敢用

实际代码编写,再学习Van1sh师傅博客相关内容就行。

求解所有可能seed(初始状态)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# SageMath
import libnum
n = 128
msg = b'##MSG FROM NK: '
mask = 230336355081348639216651218083300669636
alpha = 237299571639771708626086074576623691999
enc = '9c1250e1fefb6012cf74a7fd0156cd1a2817ee9381d086a1561399f5b7f519e5abf4437739fa254cd35b241375292d73aa8b8e6ff61f4977da3c68a699156e6bfbe2c38d7b08eed07e40e831c25f5327a21847bb156060228e2b'
enc = bytes.fromhex(enc)


# 构建M矩阵
M = matrix(GF(2), n, n)
for i in range(n):
if i+1<n:
M[i+1, i] = 1
if mask&(1<<(n-i-1)):
M[i, -1] = 1
else:
M[i, -1] = 0

# 构建T向量
T = vector(GF(2),n)
for i in range(n):
if alpha&(1<<(n-i-1)):
T[i] = 1
else:
T[i] = 0


# 求解S,构建M2矩阵
# S*M2 = output_
M2 = matrix(GF(2), n, n)

for i in range(128): # 128!不是128//8 或者 len(msg)
tmp = M^(37*(i+1))*T
for y in range(n):
M2[y, i] = tmp[y]

# 构建output_s矩阵
output_s_base = []

for i in range(len(msg)):
tmp = msg[i]^^enc[i]
for x in range(8):
if tmp&(1<<(8-x-1)): # 因为beta,取反
output_s_base.append(0)
else:
output_s_base.append(1)

# 爆破后8位,得到所有可能初始状态
Ss = []
for i in range(1<<8):
output_s = [i for i in output_s_base]
for x in range(8):
if i&(1<<(8-x-1)):
output_s.append(1)
else:
output_s.append(0)
output_s = vector(GF(2), output_s)
try:
S = M2.solve_left(output_s)
Ss.append(list(S))
except:
continue
# print(Ss)

# 转换为整数
seeds = []
for i in Ss:
seed = int(''.join([str(each) for each in i]), 2)
seeds.append(seed)
print(seeds)
求解flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os, utils
from tqdm import tqdm

enc = '9c1250e1fefb6012cf74a7fd0156cd1a2817ee9381d086a1561399f5b7f519e5abf4437739fa254cd35b241375292d73aa8b8e6ff61f4977da3c68a699156e6bfbe2c38d7b08eed07e40e831c25f5327a21847bb156060228e2b'
enc = bytes.fromhex(enc)
seeds = [] # seeds复制过来
for seed in tqdm(seeds):
gen = utils.ToyGen(seed)
flag = bytes(c ^ next(gen) for c in enc)
if b'nkctf' in flag:
print(flag)
break
# b'##MSG FROM NK: Congratulations! Hope you enjoy the game and your flag is: nkctf{ez-got-it}'
# nkctf{ez-got-it}

12bbf71421706859cde23cac65ed54ba

写在最后

星盟安全团队纳新!

欢迎师傅们加群(346014666)学习、讨论!

xmcve