2022DASCTF X SU 三月春季挑战赛-Crypto-FlowerCipher

2022DASCTF X SU 三月春季挑战赛

Crypto

0x01 FlowerCipher

源码

题目源码
# python3

from secret import flag
import random

# flag = b'flag{%s}' % md5(something).hexdigest()
# note that md5 only have characters 'abcdef' and digits

def Flower(x, key):
    flower = random.randint(0, 4096)
    return x * (key ** 3 + flower)

flag = flag[5:-1]
rounds = len(flag)

L, R = 1, 0
for i in range(rounds):
    L, R = R + Flower(L, flag[i]), L

print(L, R)
'''
15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
'''

解析

纵观整个文件,逻辑结构比较简单,接下来就逐步分析代码;

  1. # flag = b'flag{%s}' % md5(something).hexdigest()
    # note that md5 only have characters 'abcdef' and digits
    

    ​ 给了一段注释,说 \(flag\) 的内容是由花括号内的部分转为字解以后与某个字符串的 md5 值进行取模运算,后面的 hexdigest() 函数的作用,根据函数名大致可以猜出是把字符串转为十六进制,具体作用查找资料以后证实与猜测符合。

    ​ 第二段的注释说 something 的内容是'abcdef'和数字,简而言之就是16进制,由于md5大部分是32位,这里又没有给出具体的值,若在这一步进行了运算,是得不出 \(flag\) 的,所以这里的 \(flag\) 就是我们最终解出的字样。

  2. def Flower(x, key):
        flower = random.randint(0, 4096)
        return x * (key ** 3 + flower)
    

    ​ 该函数的作用暂时还不清楚,就是一个简单的运算,只不过中间有一个 \(0-4095\) 的随机数,后续应该是爆破这个随机数,量也不大,也没有其他方法。

  3. flag = flag[5:-1]
    rounds = len(flag)
    
    L, R = 1, 0
    

    ​ 进行基本的赋值操作,第一步是取出 \(flag\) 字符串中花括号里的内容,第二步是计算 \(flag\) 的长度, \(L\)\(R\) 往下看就知道是循环计算的值。

  4. for i in range(rounds):
        L, R = R + Flower(L, flag[i]), L
    

    ​ 一个简单的 for 循环,看到 \(flag[i]\) 可以知道遍历了 \(flag\) 中的每一个字符进行运算,每一次运算将 \(L\)\(R\) 交换位置赋值,可能是为了改变二者的值,若不改变位置赋值,那么 \(R\) 就是无用的,另一方面是为了将每一次运算结果嵌入到下一次运算,使得每一次运算都是息息相关的。

  5. print(L, R)
    '''
    15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
    '''
    

    ​ 输出 \(L\)\(R\) 的值,题目也给了对应的值。

  6. 至此为止,程序分析完了,就是简单的循环计算,只需要逆推整个过程每一次计算的返回值我们就都一目了然,模仿数学归纳法那样举几个例子更好理解。

    L R
    image image
    image image
    image image

decode

​ 为了解决整个题目我们有几个需要解决的问题:

  1. 上面提到的随机数,怎么去确定,暂时的解决办法就是遍历所有的值,因为这种计算式子哪怕几万个结果对于计算机来说也是一瞬间的,时间代价很低,可以尝试。
  2. 每一次计算都会交换 \(L\)\(R\) 的值,要去分离所有的 \(L\)\(R\) ,分离了 \(L\)\(R\) 才能去尝试分离出每一次的函数返回值。
  3. 函数返回值的表达式是一定要逆推拿到 \(L\) 的输入值,因为本次函数的输出值关乎到 \(L\) 的值是多少,上一次 \(L\) 的值关乎到上上次的计算...

​ 我们可以通过逆推去还原代码的执行过程。发现imageimage什么意思呢,就是说同一次得出的 \(L\) 减去 \(R\) 就可以得到函数的返回值。

​ 但是问题又来了,尽管这样我们只能推算一步而已,怎么拿到除了最后一步之外的值呢,这里有个小细节,就是每一次赋值语句后的 \(L_n\)\(R_n\) 的值,始终成立 \(L_n>R_n\) ,为什么呢,因为,imageimage,并且其中函数返回值一定大于1。知道这些有什么用呢,已知函数返回值是 \(L_n\) 的整数倍,且 \(L_n>R_n\) 恒成立,怎么得到image,此时此刻想到的是模运算,image,拿到了image之后就可以拿到image,以此类推,就拿到了所有的 \(L\)\(R\)

listL = []
listR = []
n = 0
while L > 1:
    listL.append(L)
    listR.append(R)
    L, R = R, L % R
    n += 1
listL.append(L)
listR.append(R)
listL = listL[::-1]#逆序
listR = listR[::-1]

​ 这里的 \(n\) 的作用是看他循环了多少次,因为我们知道循环到最初的时候 \(L=1\) ,这就是循环结束的条件,但是结束的时候 \(L=1\) 并没有写入列表中,所以需要额外在添加一次,但我们是逆序反推的,为了后面运算方便,将他们逆序过来。

L:

L的值
1
133317
137492755075
24316418691677517
2694478038943586736328
449366186013055209469307061
424678007756192434300006917804988
67952303343509961405922862120527631953
10722465754210488857842384539746544074196670
11050144307727113700681557772687121323224647867153
11731219952144596819377276074864534430521345582519171825
1501209023627137765492979001172871435243212151481455508796928
240324048977128823416619126180138745528644638124733113619292984561
241267801518963217329803327254141129383508497053892152707957403620167975
32759342090485149698017824597983901673872922475506121132811189377165700630061
5830376668137452804173383567980586211563348379884185911787096393298400138955904511
6028609474886885541605763758989943967354486126474121155263363791803356933057570965004061
973825402922208545745882895848854992390620148165434035074196392656950555217820068399921894085
163194634853135239779527687110852732238802459017066087158243026833107794785760861815584881897662446
19287157921091613716265688246942013055491723611322575658962386161345041119412098008892719335475158074595
19304497076225869711849746340455541612339463403087957113496859433662333338211557279788474751973335123601723351
19346619488865481717482094100686681292384530125288986759529832156605546935716879938892385301891033660176897469426477
18822751726365286700612339826340137082689797360168751039458371318582478795225200597245268849966216725478600774872948579145
17728566345779292838907909381612640668036643431117165902908905722221490552536570008262521006387722966311695266888986102760148482
16713517279670522179142602316669021266414545548551242366498025076135157482269671171234675566764239156725485371108735804221489129242235
3121683903445470016877317983137081025437455800044243487676152297523129079630621593231064333666220053742946978640516933836161839706107832842
3038050870004975946934828279229998090001629942971672705946371743686684953534372767609080560274203027849883925292484330032865963662762987021572213
363542281260527120641507826394376579427002124891256726811704925452455933892306777570036028677323021255266880206017499363363356743613369155668503557061
41491807647864532203061547188977816042392604608090542687445179257686072390683442091157724792609311622180322599523073162631870961894947012137520634996058265
7402968320895532116930768370098929764678065093602516751185225609968053961398195671796668035067389408306736179462173593882795916384659802649189800851665219198361
935298420671754230833014738849730432588169238033228173469583131476419084794695511761146278309606770027490667271610796624269392034586175088396235641537756093736185366
139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899

R:

R的值
0
1
133317
137492755075
24316418691677517
2694478038943586736328
449366186013055209469307061
424678007756192434300006917804988
67952303343509961405922862120527631953
10722465754210488857842384539746544074196670
11050144307727113700681557772687121323224647867153
11731219952144596819377276074864534430521345582519171825
1501209023627137765492979001172871435243212151481455508796928
240324048977128823416619126180138745528644638124733113619292984561
241267801518963217329803327254141129383508497053892152707957403620167975
32759342090485149698017824597983901673872922475506121132811189377165700630061
5830376668137452804173383567980586211563348379884185911787096393298400138955904511
6028609474886885541605763758989943967354486126474121155263363791803356933057570965004061
973825402922208545745882895848854992390620148165434035074196392656950555217820068399921894085
163194634853135239779527687110852732238802459017066087158243026833107794785760861815584881897662446
19287157921091613716265688246942013055491723611322575658962386161345041119412098008892719335475158074595
19304497076225869711849746340455541612339463403087957113496859433662333338211557279788474751973335123601723351
19346619488865481717482094100686681292384530125288986759529832156605546935716879938892385301891033660176897469426477
18822751726365286700612339826340137082689797360168751039458371318582478795225200597245268849966216725478600774872948579145
17728566345779292838907909381612640668036643431117165902908905722221490552536570008262521006387722966311695266888986102760148482
16713517279670522179142602316669021266414545548551242366498025076135157482269671171234675566764239156725485371108735804221489129242235
3121683903445470016877317983137081025437455800044243487676152297523129079630621593231064333666220053742946978640516933836161839706107832842
3038050870004975946934828279229998090001629942971672705946371743686684953534372767609080560274203027849883925292484330032865963662762987021572213
363542281260527120641507826394376579427002124891256726811704925452455933892306777570036028677323021255266880206017499363363356743613369155668503557061
41491807647864532203061547188977816042392604608090542687445179257686072390683442091157724792609311622180322599523073162631870961894947012137520634996058265
7402968320895532116930768370098929764678065093602516751185225609968053961398195671796668035067389408306736179462173593882795916384659802649189800851665219198361
935298420671754230833014738849730432588169238033228173469583131476419084794695511761146278309606770027490667271610796624269392034586175088396235641537756093736185366
139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003

​ 既然都获取到了所有的 \(L\)\(R\) ,那我们就把所有的函数值返回值拿到。

for i in range (len(listL) - 1):
    num = int((listL[i+1] - listR[i]))
    flowers.append(num)

flowers:

flowers的值
133317
137492755074
24316418691544200
2694478038806093981253
449366185988738790777629544
424678007753497956261063331068660
67952303343060595219909806911058324892
10722465753785810850086192105446537156391682
11050144307659161397338047811281198461104120235200
11731219952133874353623065586006692045981599038444975155
1501209023616087621185251887472189877470525030158230860929775
240324048965397603464474529360761469453780103694211768036773812736
241267801517462008306176189488648150382335625618648940556475948111371047
32759342090244825649040695774567282547692783729977476494686456263546407645500
5830376667896185002654420350650782884309207250500677414733204240590442735335736536
6028609474854126199515278609291926142756502224800248232787857670670545743680405264374000
973825402916378169077745443044681608822639561953870686694312206745163458824521668260965989574
163194634847106630304640801569246968479812515049711601031768905677844430993957504882527310932658385
19287157920117788313343479701196130159642868618931955510796952126270844726755147453674899267075236180510
19304497076062675076996611100676013925228610670849154654479793346504090311378449485002713890157750241704060905
19346619488846194559561002486970415604137588112233495035918509580946584549555534897772973203882140940841422311351882
18822751726345982203536113956628287336349341818556411576055283361468981935791538263907057292686428250726627439749346855794
17728566345759946219419043899895158573935956749824781372783616735461960720379964461326804126448830581009804233228809205290722005
16713517279651699427416237029968408926588205411468552569137856325095699110951088692439450366166993887875519154383257203446616180663090
3121683903427741450531538690298173116055843159376206844245035131620220173908400102678527763657957532736559255674205238569272853603347684360
3038050869988262429655157757050855487684960921705258160397820501320186928458237610126810889102968352283119686135758844661757227858541497892329978
363542281257405436738062356377499261443865043865819271011660681964779781594783648490405407084091956921600660152274552384722839809777207315962395724219
41491807644826481333056571242042987763162606518088912744473506551739700646996757137623352025000231061906119571673189237339386631862081048474757647974486052
7402968320531989835670241249457421938283688514175514626293968883156349035945739737904361257497353379629413158206906713676778417021296445905576431695996715641300
935298420630262423185150206646668885399191421990835568861492588788973905537009439370462836218449045234881355649430474024746318871954304126501288629400235458740127101
139721425168891349281451572792544680133048837962069857150100615261867817820225178415462359077837226554096748311704122075309731667870724937930248453782400769574967523270642
15720197268010049967757675120469992186537658494704135479561283085920610969374470767952957875436059114121446299016141673102641832905150384839824642839374686669270876487929996533

​ 拿到之后在仔细分析以下函数的返回值。

def Flower(x, key):
    flower = random.randint(0, 4096)
    return x * (key ** 3 + flower)

image,所以我们直接在上一步处理一下 \(L\) 就可以得到一个更为简洁的式子 \(key^3+flower\)\(flower\) 是随机数,不好处理,但是有一个很关键的点, \(key^3\) ,这一项可以通过 \(gmpy2\) 库的 \(iroot()\) 函数来开方,正确的值开方返回值第二项应该是 \(True\) ,对于数字字母的ASCII码来说,相邻数的三次方差距已经超过了4096了,即便是最小的 '0' 和 '1' 的差值都达到了7057,所以可以放心的遍历所有 \(0-4095\) 之间的值。

for i in flowers:
    for j in range(4096):
        if iroot(i - j, 3)[1] == False:
            continue
        print(iroot(i - j, 3)[0], end=' ')
51 101 56 48 55 98 54 54 101 102 50 54 100 51 56 101 54 55 49 100 100 99 98 98 57 99 49 48 56 50 53 48
```![image](https://img2022.cnblogs.com/blog/2553489/202203/2553489-20220326213855426-1985494792.png)


​		到这一步就很简单了,一看就是ASCII码,直接在输出上加一个ASCII码即可。

```python
for i in flowers:
    for j in range(4096):
        if iroot(i - j, 3)[1] == False:
            continue
        print(chr(iroot(i - j, 3)[0]), end='')
3e807b66ef26d38e671ddcbb9c108250

​ 这就是flag了,提交即可。

整个解密代码:

解密源码
import random

L = 15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899

R = 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003

listL = []
listR = []
flowers = []

n = 0
while L > 1:
    listL.append(L)
    listR.append(R)
    L, R = R, L % R
    n += 1

listL.append(L)
listR.append(R)
listL = listL[::-1]
listR = listR[::-1]

print("n=:", n)
for i in range (len(listL) - 1):
    num = int((listL[i+1] - listR[i]) / listL[i])
    flowers.append(num)
for i in flowers:
    for j in range(4096):
        if iroot(i - j, 3)[1] == False:
            continue
        print(chr(iroot(i - j, 3)[0]), end='')
posted @ 2022-03-26 22:14  Sentry_InkCity  阅读(397)  评论(10编辑  收藏  举报