CTFshow元旦水友赛 Crypto wp

发布时间 2024-01-13 00:21:09作者: 欢黎明陌

[CTFshow元旦水友赛]麻辣兔头又一锅

听说有人不喜欢短尾巴的兔兔?肿么可能?我也很疑惑呢。
126292,165298,124522,116716,23623,21538,72802,90966,193480,77695,98618,127096,15893,65821,58966,163254,179952,134870,45821,21712,68316,87720,156070,16323,86266,148522,93678,110618,110445,136381,92706,129732,22416,177638,110110,4324,180608,3820,67750,134150,23116,116772,50573,149156,5292
60144,146332,165671,109800,176885,65766,76908,147004,135068,182821,123107,77538,86482,88096,101725,16475,158935,123018,42322,144694,186769,176935,59296,134856,65813,131931,144283,95814,102191,185706,55744,67711,149076,108054,135112,100344,35434,121479,14506,145222,183989,17548,38904,27832,105943

“兔子”并不一定是栅栏密码,还有可能是斐波那契数列

import gmpy2 
a = "126292,165298,124522,116716,23623,21538,72802,90966,193480,77695,98618,127096,15893,65821,58966,163254,179952,134870,45821,21712,68316,87720,156070,16323,86266,148522,93678,110618,110445,136381,92706,129732,22416,177638,110110,4324,180608,3820,67750,134150,23116,116772,50573,149156,5292".split(",")
b = "60144,146332,165671,109800,176885,65766,76908,147004,135068,182821,123107,77538,86482,88096,101725,16475,158935,123018,42322,144694,186769,176935,59296,134856,65813,131931,144283,95814,102191,185706,55744,67711,149076,108054,135112,100344,35434,121479,14506,145222,183989,17548,38904,27832,105943".split(",")
for i in range( len( a ) ):
    print(chr((gmpy2.fib(eval(a[i]))^gmpy2.fib(eval(b[i])))&0xff),end='' )

我们需要计算出两行的斐波那契数然后异或,使用python的gmpy2.fib即可计算斐波那契数列的任意位

flag:ctfshow{6d83b2f1-1241-4b25-9c1c-0a4c218f6c5f}

问题:这道题是如何构造的

全体正整数n和fib(n)构成单射,而非一一映射,出题人是如何构造的,是否可以根据指定的flag来构造密文

猜想:由于最终对Oxff进行与运算,故只需要考虑16进制下的最后两位;总共有255,如果是直接进行与运算,最劣情况下进行不超过65536次运算即可得到一个字母对应的斐波那契数;其序数可以进行暴力运算进行逆推;或者构造一组“最小剩余系”来表示所有需要的数,容量为256,进行组合即可

反驳:对于所有的已知数据,没有一个是重复的

回答:可以不是随机,每256个数就存在一个数符合预期要求;也不需要有重复的数字,python对于斐波那契数列的算力很强;故由一个flag,可以随机出一个a序列,然后暴力计算出b序列

[CTFshow元旦水友赛]NOeasyRSA

from Crypto.Util.number import long_to_bytes
from Crypto.Util.strxor import strxor
from random import randint
from flag import FLAG
 
def f(x, n):  
    return (pow(u,n,p)*x + v*(1-pow(u,n,p))*pow(1-u, -1, p)) % p  
 
p = 97201997431130462639713476119411091922677381239967611061717766639853376871260165905989218335681560177626304205941143288128749532327607316527719299945637260643711897738116821179208534292854942631428531228316344113303402450588666012800739695018334321748049518585617428717505851025279186520225325765864212731597
u = 14011530787746260724685809284106528245188320623672333581950055679051366424425259006994945665868546765648275822501035229606171697373122374288934559593175958252416643298136731105775907857798815936190074350794406666922357841091849449562922724459876362600203284195621546769313749721476449207319566681142955460891977927184371401451946649848065952527323468939007868874410618846898618148752279316070498097254384228565132693552949206926391461108714034141321700284318834819732949544823937032615318011463993204345644038210938407875147446570896826729265366024224612406740371824999201173579640264979086368843819069035017648357042
v = 16560637729264127314502582188855146263038095275553321912067588804088156431664370603746929023264744622682435376065011098909463163865218610904571775751705336266271206718700427773757241393847274601309127403955317959981271158685681135990095066557078560050980575698278958401980987514566688310172721963092100285717921465575782434632190913355536291988686994429739581469633462010143996998589435537178075521590880467628369030177392034117774853431604525531066071844562073814187461299329339694285509725214674761990940902460186665127466202741989052293452290042871514149972640901432877318075354158973805495004367245286709191395753
w = 30714296289538837760400431621661767909419746909959905820574067592409316977551664652203146506867115455464665524418603262821119202980897986798059489126166547078057148348119365709992892615014626003313040730934533283339617856938614948620116906770806796378275546490794161777851252745862081462799572448648587153412425374338967601487603800379070501278705056791472269999767679535887678042527423534392867454254712641029797659150392148648565421400107500607994226410206105774620083214215531253544274444448346065590895353139670885420838370607181375842930315910289979440845957719622069769102831263579510660283634808483329218819353
a = randint(0, 2**2048)
b = randint(0, 2**2048)
A = f(w, a)
B = f(w, b)
key = long_to_bytes(f(B, a))[:len(FLAG)]
enc = strxor(FLAG, key)
print(f"{A = }")
print(f"{B = }")
print(f"{enc = }")

"""
A = 19000912802080599027672447674783518419279033741329820736608320648294849832904652704615322546923683308427498322653162857743332527479657555691849627174691056234736228204031597391109766621450008024310365149769851160904834246087493085291270515883474521052340305802461028930107070785434600793548735004323108063823
B = 73344156869667785951629011239443984128961974188783039136848369309843181351498207375582387449307849089511875560536212143659712959631858144127598424003355287131145957594729789310869405545587664999655457134475561514111282513273352679348722584469527242626837672035004800949907749224093056447758969518003237425788
enc = b'\xfd\xc1\xb7\x9d"$\xc2\xb0\xb5\xee\xf89\xa4V\x8e\x17\x01K9\xbc.\x92=\x85\x80\xd4\x03\xefAl"\xbd\x8b\xcdL\xb5\xa3!'
"""

只要思想不滑坡,这题就是推推式子(呜呜呜我自己做的时候把抄错好几个数死活调不出来呜呜...)

import gmpy2
from Crypto.Util.number import long_to_bytes
from Crypto.Util.strxor import strxor

p = 97201997431130462639713476119411091922677381239967611061717766639853376871260165905989218335681560177626304205941143288128749532327607316527719299945637260643711897738116821179208534292854942631428531228316344113303402450588666012800739695018334321748049518585617428717505851025279186520225325765864212731597
u = 14011530787746260724685809284106528245188320623672333581950055679051366424425259006994945665868546765648275822501035229606171697373122374288934559593175958252416643298136731105775907857798815936190074350794406666922357841091849449562922724459876362600203284195621546769313749721476449207319566681142955460891977927184371401451946649848065952527323468939007868874410618846898618148752279316070498097254384228565132693552949206926391461108714034141321700284318834819732949544823937032615318011463993204345644038210938407875147446570896826729265366024224612406740371824999201173579640264979086368843819069035017648357042
v = 16560637729264127314502582188855146263038095275553321912067588804088156431664370603746929023264744622682435376065011098909463163865218610904571775751705336266271206718700427773757241393847274601309127403955317959981271158685681135990095066557078560050980575698278958401980987514566688310172721963092100285717921465575782434632190913355536291988686994429739581469633462010143996998589435537178075521590880467628369030177392034117774853431604525531066071844562073814187461299329339694285509725214674761990940902460186665127466202741989052293452290042871514149972640901432877318075354158973805495004367245286709191395753
w = 30714296289538837760400431621661767909419746909959905820574067592409316977551664652203146506867115455464665524418603262821119202980897986798059489126166547078057148348119365709992892615014626003313040730934533283339617856938614948620116906770806796378275546490794161777851252745862081462799572448648587153412425374338967601487603800379070501278705056791472269999767679535887678042527423534392867454254712641029797659150392148648565421400107500607994226410206105774620083214215531253544274444448346065590895353139670885420838370607181375842930315910289979440845957719622069769102831263579510660283634808483329218819353
A = 19000912802080599027672447674783518419279033741329820736608320648294849832904652704615322546923683308427498322653162857743332527479657555691849627174691056234736228204031597391109766621450008024310365149769851160904834246087493085291270515883474521052340305802461028930107070785434600793548735004323108063823
B = 73344156869667785951629011239443984128961974188783039136848369309843181351498207375582387449307849089511875560536212143659712959631858144127598424003355287131145957594729789310869405545587664999655457134475561514111282513273352679348722584469527242626837672035004800949907749224093056447758969518003237425788
enc = b'\xfd\xc1\xb7\x9d"$\xc2\xb0\xb5\xee\xf89\xa4V\x8e\x17\x01K9\xbc.\x92=\x85\x80\xd4\x03\xefAl"\xbd\x8b\xcdL\xb5\xa3!'

ua = ((u-1)*A+v)*gmpy2.invert((u-1)*w+v,p) % p
key = (ua * B + v * ( 1 - ua ) * gmpy2.invert( 1-u , p ) ) % p
flag = strxor( enc , long_to_bytes(key)[:len(enc)] )
print( flag )

flag:ctfshow{This_Is_Really_Not_So_Smooth!}

问题:为什么取负运算在模域上对值没有改变

ua = ((u-1)*A+v)*gmpy2.invert((u-1)*w+v,p) % p
ub = ((A*((1-u))-v) * gmpy2.invert(w*(1-u)-v,p)) % p
assert ua == ub

通过yafu计算,p是质数

image-20240109134635922

回答:因为有逆元,是分式;分子分母同时取负,值不变

[CTFshow元旦水友赛]NOeasyRSA

import random
from hashlib import md5
from Crypto.Util.number import *
from flag import flag

def get_state(kbits, k):
    seed = [(random.getrandbits(kbits) >> k) & 0xfffffff for i in range(624)]
    state = (3, tuple(seed + [0]), None)
    return state


def give_gift(kbits, num):
    gift = [random.getrandbits(kbits) for i in range(num)]
    e = random.getrandbits(7)
    l_num = num - e
    s_box = list(range(num))
    random.shuffle(s_box)
    l_gift = [gift[i] for i in s_box[:l_num]]
    return (l_gift, s_box[:l_num], e)


def enc_flag(state, e):
    key = bytes_to_long(md5(long_to_bytes(state[1][e])).digest())
    enc = bytes_to_long(flag) ^ key
    return enc


kbits, k, num = random.randrange(64), random.randrange(16), random.randrange(400, 600)
state = get_state(kbits, k)
random.setstate(state)
gift = give_gift(kbits, num)
enc = enc_flag(state, gift[2])
print(gift, enc)

# ([91463260584, 97520150804, 134987178347, 134745660347, 23369346769, 88869916197, 67723104206, 132211190015, 74383600340, 57357411421, 80301226226, 2847043233, 46071508714, 76391425800, 71113777427, 12603028605, 127607785895, 82661956584, 48539405830, 131191473154, 137430688091, 48026249914, 105523652421, 58217141456, 135651011411, 37099885733, 101903983367, 117525416468, 49720139903, 123719748136, 58611168240, 68135859850, 6355615539, 23769720298, 7999623487, 19601432037, 49460687576, 34510812373, 97988805553, 120381187017, 37643325426, 79314538948, 128727827227, 41938289773, 74120986880, 29052999070, 21215042789, 76176648906, 82899209179, 90338690991, 102277220210, 109016314367, 2419923303, 75246152672, 109203867772, 87030346778, 119151949871, 134868756437, 124854798665, 122116306769, 31536426951, 82104297926, 118556737102, 78417017414, 81807286830, 24688295471, 126360674284, 8870569872, 105339369180, 61910863416, 56597235604, 50122937080, 135836683348, 75685244539, 112566491901, 86217144353, 110999080631, 91114786530, 94967775022, 52680440255, 76947914257, 133052296759, 22589975272, 104632324223, 47428022416, 106941367714, 119250845700, 80196618477, 92917756830, 52764061858, 82855761133, 26800124167, 129317288037, 44051967549, 70500283649, 165355182, 78293334339, 45001066520, 84638985033, 32566871344, 38421055041, 56145488218, 83396525174, 116762960131, 58381974438, 132249926372, 36091120717, 35213963219, 88756092150, 45288405267, 27461079382, 19589246113, 28308681656, 47161727545, 69898448282, 22959597168, 132569999975, 100557577568, 127037292334, 29708117311, 33229333831, 29311547868, 135347707719, 85435007922, 54540391811, 109544478077, 66841548339, 47159376439, 42574542524, 62176229940, 3138675000, 21267865120, 22618290315, 126018690563, 21590061225, 9799239940, 10617934652, 40956988582, 131053131140, 90043238501, 81283244185, 109338223936, 68311960398, 25088200986, 28895564195, 17646619057, 82775422880, 81522377214, 28334564831, 100791800926, 85872403124, 127915503356, 72496838376, 109007653011, 96263138881, 69693106974, 4718076407, 68334177311, 31708464646, 96111162918, 48965277868, 54931198292, 105535767797, 105680940066, 109968562576, 23573023928, 48569942163, 106967716286, 94835446653, 92803971955, 53791818332, 14453746086, 132101017989, 26361874022, 32122658200, 51724426274, 114997634813, 75838224666, 89848273104, 73619960674, 97795812498, 132466249292, 25997032367, 40732063573, 59142286405, 68524304985, 49545031400, 28044368864, 95700359624, 108201671504, 127043767055, 9384509797, 120972803416, 41782179648, 76653307257, 44056421640, 101631026937, 99078185959, 54885001820, 69316726710, 19710227322, 86035277688, 42289562955, 98051921147, 79098792488, 106490144808, 13834874, 69114014086, 4418515159, 109316722991, 92603496375, 68830244931, 111949257703, 102637560761, 5012149380, 43811237017, 4526712578, 102995188930, 9165821006, 63456393327, 68912422322, 104913358841, 108860651772, 52967416635, 84227988465, 101715630295, 26297443306, 110653579906, 91487440397, 116959430145, 83499469513, 48913630229, 76988993305, 41832173701, 13694488408, 135450931748, 39634435716, 41679152695, 126540504548, 91399825525, 99004649347, 19517357430, 8279948639, 133596449559, 1449103211, 50732184406, 52247676129, 74928416312, 64326525401, 124673786795, 92042480385, 24404916254, 99622146133, 51463314254, 36722967192, 4007778602, 39109534005, 120478575332, 99886542155, 5756463131, 91679854224, 3608646835, 35655876863, 121959477025, 20408412916, 36341277711, 43627610089, 24855949002, 128669830633, 70347508117, 9425085453, 2022963949, 5053312318, 63243834495, 21497715007, 5936366400, 44266914863, 119468825913, 91726986385, 126494307832, 93847533617, 22070910941, 20204251399, 42254244260, 60489335607, 40705184865, 80919639775, 73360223499, 132743946450, 88897376509, 103144368275, 9982808097, 131532980487, 91081435155, 78915930938, 72790758029, 120696671493, 78255313725, 13309583510, 23841020581, 116634908326, 73400462338, 57323203784, 46210923108, 41134724194, 43089395737, 118503520944, 111039189867, 99418263301, 59298127775, 45252940179, 40345195432, 16841439060, 100422187771, 65791698364, 61167532292, 30338914082, 14930863404, 4703203112, 124912009656, 9195518396, 18552364400, 7303227315, 105753747788, 3079040268, 116480022128, 1215344111, 9934249637, 76178148585, 20033461169, 87344780021, 72391242953, 129540048833, 15495213032, 49963621916, 84362224351, 97100635498, 105086571577, 51150506310, 118045067326, 65966867679, 7925108854, 131280748402, 66481282233, 107509392827, 78521145687, 35456851157, 97461157961, 30244093674, 24123083085, 27909475052, 69646113342, 131930611276, 97792139629, 135917828529, 32305782568, 59325645293, 84962280113, 74529748221, 22659244720, 54776660364, 66934871192, 14824496938, 37231294479, 102244198902, 31674646475, 128196911226, 90158594889, 121714346066, 64647669235, 105263204191, 127988380741, 130175056631, 114272442969, 135960937840, 62465712860, 32333037569, 137012433094, 92929672123, 86030288893, 73602847949, 58136148471, 118893337093, 97692245318, 99539974338, 116231441994, 32445182154, 115683286754, 114711297102, 102210385893, 7687212992, 73626254322, 242951419, 5952493527, 96817591608, 45197171621, 122928115217, 106192593180, 99889552302, 125596158762, 136959359712, 67291405558, 71974425715, 115789979144, 59321975202, 84748820897, 133266408556, 6800817333, 110678933813, 96832595879, 97681824039, 89341148630, 84626208563, 58523733456, 93000780873, 68444996084, 775177345, 17204124036, 129474447019, 73589942581, 65415043899, 131703332659, 101783987222, 61388598262, 103435807803, 104030629529, 19123072760, 63612557945, 38245223725, 54345357864, 62016904380, 34602169486, 51229280420, 66624757580, 68760378559, 131556923700, 21935621011, 36349470821, 10120892182, 25883848878, 71735922493, 62883391871, 90647098, 41388569318, 52175456448, 71822304690, 19251125978, 91308465291, 50110754397, 91050175581, 83697004380, 6165622900, 129188497722, 71424103672, 57569171583, 13220579058, 118266862549, 21791521844, 70064705221, 83120075317, 83316886784, 111745960042, 26241940218, 32402511427, 118604113535, 98847819357, 117058412964, 57680263912, 83166477192], [508, 300, 327, 517, 431, 195, 41, 162, 110, 358, 433, 105, 40, 256, 172, 50, 474, 55, 67, 284, 215, 118, 513, 98, 120, 26, 155, 298, 4, 233, 243, 267, 428, 478, 494, 226, 146, 488, 20, 113, 143, 136, 49, 236, 128, 346, 501, 264, 498, 0, 413, 30, 410, 99, 1, 220, 443, 369, 290, 374, 119, 511, 483, 199, 248, 351, 388, 335, 131, 79, 496, 245, 414, 244, 158, 451, 255, 412, 47, 473, 254, 95, 299, 462, 169, 519, 493, 12, 257, 385, 432, 417, 59, 93, 455, 324, 52, 90, 407, 288, 112, 34, 528, 29, 192, 101, 419, 203, 123, 176, 177, 167, 204, 445, 416, 485, 196, 302, 424, 425, 6, 418, 258, 17, 370, 262, 227, 326, 387, 294, 295, 174, 25, 188, 81, 408, 469, 11, 472, 80, 400, 84, 382, 448, 201, 344, 7, 502, 163, 312, 484, 349, 239, 108, 411, 315, 303, 377, 36, 383, 78, 339, 491, 271, 216, 187, 322, 140, 405, 296, 402, 516, 450, 22, 482, 361, 371, 249, 453, 64, 152, 72, 194, 66, 345, 492, 447, 58, 486, 357, 149, 200, 83, 212, 219, 504, 333, 23, 439, 376, 457, 332, 153, 348, 210, 237, 173, 359, 129, 179, 426, 71, 19, 321, 338, 444, 139, 307, 515, 88, 266, 475, 182, 323, 336, 354, 272, 384, 330, 2, 211, 446, 238, 397, 230, 278, 141, 506, 181, 70, 316, 314, 459, 235, 121, 286, 76, 518, 280, 43, 111, 62, 487, 429, 524, 364, 86, 228, 353, 275, 104, 441, 268, 13, 500, 68, 87, 109, 403, 520, 231, 391, 42, 51, 328, 253, 436, 60, 497, 313, 481, 522, 53, 61, 420, 225, 189, 325, 183, 56, 100, 229, 27, 39, 3, 184, 291, 415, 454, 75, 28, 107, 347, 421, 166, 224, 279, 16, 342, 206, 207, 171, 368, 198, 456, 464, 406, 365, 151, 320, 161, 9, 89, 479, 142, 259, 401, 232, 523, 449, 150, 218, 15, 97, 287, 133, 458, 221, 63, 185, 350, 74, 135, 404, 466, 214, 116, 507, 355, 213, 178, 318, 423, 126, 395, 465, 440, 452, 157, 366, 190, 343, 467, 247, 509, 91, 205, 114, 193, 409, 375, 269, 373, 389, 148, 69, 396, 398, 317, 145, 122, 147, 512, 32, 130, 386, 94, 435, 310, 57, 422, 308, 305, 217, 8, 154, 156, 309, 223, 44, 24, 82, 160, 392, 477, 356, 134, 54, 138, 378, 331, 379, 250, 96, 489, 306, 399, 46, 18, 283, 470, 21, 360, 209, 168, 495, 180, 514, 191, 270, 510, 381, 186, 442, 31, 390, 5, 85, 92, 363, 33, 127, 197, 285, 380, 265, 48, 352, 505, 208, 438, 329, 468, 282, 45, 159, 301, 362, 341, 65, 263, 393, 222, 521, 175, 293, 37, 490, 35], 60) 912396759652812740801869061695733452669218533249083289698313292427681899514848561025221753354562922565560034

首先读代码

#生成三个随机数,数据范围很小,属于可爆破范围
kbits, k, num = random.randrange(64), random.randrange(16), random.randrange(400, 600)

#生成624个不大于28bits的随机数,打包进state里
seed = [(random.getrandbits(kbits) >> k) & 0xfffffff for i in range(624)]
state = (3, tuple(seed + [0]), None)

#设置随机数内部状态
random.setstate(state)

#生成一个随机长度,随机大小的gift
gift = [random.getrandbits(kbits) for i in range(num)]
#生成一个e,不大于7bits
e = random.getrandbits(7)
l_num = num - e
#将小于num的数构成一个列表,并打乱顺序
s_box = list(range(num))
random.shuffle(s_box)
#把又是一个随机的数打包进gift
l_gift = [gift[i] for i in s_box[:l_num]]
gift = (l_gift, s_box[:l_num], e)

#用一个随机的不大于28bits的数生成密钥
key = bytes_to_long(md5(long_to_bytes(state[1][gift[2]])).digest())
enc = bytes_to_long(flag) ^ key

print(gift, enc)

读了半天,才发现前面的全是随机数的随机数,只有key的生成这一句有用,直接爆破一个大小不大于28bits的数即可

给了一堆gift,对于得到flag没有什么作用

from hashlib import md5
from Crypto.Util.number import *

enc = 912396759652812740801869061695733452669218533249083289698313292427681899514848561025221753354562922565560034

for i in range( int(0xfffffff)+1 ):
    key = bytes_to_long(md5(long_to_bytes(i)).digest())
    flag = long_to_bytes(key^enc)
    if "\\" in str(flag):
        continue
    else:
        print( i , flag )

由于数据量过大,直接查关键字ctfshow出现的数据过多,而table我又不会用,故可以直接查找不存在十六进制无法翻译成字符的,可以得到flag

image-20240111155315912

找出一个没有奇怪字符、大括号在最后面的即为flag

观赏了学长的代码,巧妙地运用了table,不用手动选择flag了(不过时间复杂度一样,都是线性的)

还有tqdm,有了它,就可以看到进度条了(不过不知道为什么我的电脑上用tqdm总是卡崩掉)

from tqdm import tqdm
from Crypto.Util.number import *
from hashlib import md5
import string

def dec(num):
    num = int(num)
    key = bytes_to_long(md5(long_to_bytes(num)).digest())
    m = enc ^ key
    m = long_to_bytes(m)
    try:
        flag = m.decode()
        if all(f in table for f in flag):
            print(flag)
            print(f"num = {num}")
    except:
        return

table = string.ascii_letters + '0123456789_-{}'

enc = 912396759652812740801869061695733452669218533249083289698313292427681899514848561025221753354562922565560034

for i in tqdm(range(0xfffffff+1)):
    dec(i)

flag:ctfshow{F2AD971D-66C2-2D1D-69D6-CE7DE2A49B35}

[CTFshow元旦水友赛]哪位师傅知道这个是什么密码啊?

image-20240113000226608

import os
from Crypto.Util.number import *

F = lambda x: x * F(x-1) if x > 0 else 1
G = lambda x, y: F(x) // (F(y) * F(x-y))

def get_keys(n: int):
    p = getPrime(-11+45-14)
    print('Please wait...')
    s_list, t_list, u_list = [], [], []
    for i in range(n):
        print(f'Progress: {i+1} / {n}')
        while True:
            t, s = sorted(getPrime(101) for _ in 'NB')
            u = (G(s, t) % p) & 0xFF
            if (u != 0):
                s_list.append(s)
                t_list.append(t)
                u_list.append(u)
                break
    return (s_list, t_list, p), u_list 

FLAG = os.getenv('FLAG', 'ctfshow{never_gonna_give_you_flag}')
print( FLAG )
pubkey, privkey = get_keys(len(FLAG))
print( pubkey, privkey )
ciphertext = bytes(x ^ k for x, k in zip(FLAG.encode(), privkey))
print(f'{pubkey = }')
print(f'{ciphertext.hex() = }')

F是阶乘,G是组合数的计算过程

卢卡斯定理(OI-wiki)

image-20240113001008310

from Crypto.Util.number import *
from Crypto.Util.number import long_to_bytes
import gmpy2

pubkey = ([2244095333388513367565281205621, 2260083173627571225575272017643, 2232571619487249695276209431911, 1366892418499855676258266570183, 2453504829447242891596294199551, 1749886540398964782388250510153, 2400368813718195311072803190537, 2412199908745985611198006411271, 2136151769918417200012573467547, 2188326070621506831342201179489, 2490975888687886171609455918979, 2520972296586880497850481220517, 2505441601685892494158922143537, 2223691958889488499464345149631, 2419970291634469073461115862923, 1913431629076248544274472723887, 1516525599480634064271895075589, 1748534379194448515689583072903, 2254654291529452465905257115983, 2036853065650744279222351374007, 1942468846337869648732525843309, 2201940065043223214975123483717, 2420554654468916631069996311243, 1578933527329599278882739520739, 2185608727926152268827042689247, 2138991356060432718559850740837, 1993202582269353654593882658857, 1851957155599032687165578632711, 1675430935325353825921279241939, 1539732791462031791764734543397, 1452444069464058198195009866663, 1853102085689472930613090539653, 2422886163436887722911429199407, 2478151413643348620173265601687, 2081728653302754258684980999897, 1869475969698886966223998022243, 2514233209214621717689871577799, 1565641057982670427875243690007, 2470941525500295562801927618117, 1957593611795889447618691712899, 2380166810104233903974756831281, 2310844976072657607087683813659, 2138906021714896472557340201269, 2133283066222174180401711231107, 2307615052065649723749209072291], [1950345581706607236958613312239, 1513963021166149007673751427809, 2209549849936350178706915353711, 1282304331826641551367349314389, 1285901314103578143578261497933, 1732171004069526252052648123229, 1885905081824428587397820753449, 2156360504061214962564655540577, 2114387282072764844800146882587, 1713540614501303042289450513031, 1718611954585760080721231776949, 2395901674478208382890220594709, 1953786497785706690568567652501, 1434952765892339228311211916623, 1434633435633106679937918543013, 1272002714370288579710832521801, 1345903574845925448968871221921, 1599178580175752823633130749379, 2050880877544639868041580689117, 1268507788047119658102789429151, 1550740527937339681775447782103, 2026060127920636700353677740333, 2320801697813895006451348616587, 1489309276821468831592096904009, 1343134452830065788367338410993, 1825449623429915829785766822487, 1385771207130987392492516965847, 1681955135857458220104835916897, 1608580883454393934111909197727, 1417761672076182691155757676783, 1339284864034936616590020649969, 1741000210994367137067807994129, 1416704333290652593089933548759, 1833600804996263316791298228287, 1740533709307600192323357511421, 1516475145585568797228308698679, 2284536672877756851447268908997, 1271126734775727764840925368047, 1674941925848400149104085993761, 1826602689042665336846528498857, 1987838509832756026588063009051, 1689378070597281801400506154393, 1490675164221922597195547712943, 1601946500767026172849726987951, 2081320371490185790723799153587], 560113)
ciphertext = int('8b232301d0d8b5a681c1c982b04763b8765a8bbfb2bdf7332d0990f2a04b487dff3ffb0c6f1b1faefcd3037cf7',16)
( s_list , t_list , p ) = pubkey

def C( n , m , p ):
    up , down = 1 , 1
    for i in range( n - m + 1 , n + 1 ):
        up = up * i % p
    for i in range( 1 , m + 1 ):
        down = down * i % p
    return up * gmpy2.invert( down , p ) % p

def lucas( n , m , p ):
    if m == 0:
        return 1
    return C( n % p , m % p , p ) * lucas( n // p , m // p , p ) % p


u_list = []
for s,t in zip(s_list,t_list):
    u_list.append( lucas(s,t,p) & 0xFF )

flag = bytes(x ^ k for x, k in zip(long_to_bytes(ciphertext), u_list))
print(flag)

flag:ctfshow{a786316f-b09b-4b83-b52c-8e20ef3c23d7}(动态)