跳至主要內容

The Flag Game

Haynes原创...大约 6 分钟CTFReverseHKCert23

練功練功
好過喺度亂想一通
講到天花龍鳳
帶人遊西北東
I'm so turn off 唔該你練功練功
坐而言起而行練練功

你已經玩過密碼遊戲了吧?來玩旗幟遊戲open in new window

0x01 分析

The flag game 特别像 Password-Gameopen in new window

随便玩一下发现规则很多,查看 js 文件可以发现所有规则

{
    description: "Your flag must be at least 6 characters.",
    checker: e=>e.length >= 6
}, {
    description: "Your flag must start with <code>hkcert23</code>.",
    checker: e=>e.startsWith("hkcert23")
}, {
    description: "Your flag must include exactly one <code>{</code> and one <code>}</code>.",
    checker: e=>1 === e.split("").filter((e=>"{" === e)).length && 1 === e.split("").filter((e=>"}" === e)).length
}, {
    description: "The length of your flag must be a prime.",
    checker: e=>m(e.length)
}, {
    description: "The digits in your flag must add up to 26.",
    checker: e=>26 === e.split("").filter((e=>"0123456789".includes(e))).map((e=>parseInt(e))).reduce(((e,t)=>e + t), 0)
}, {
    description: "The length of your flag must not be greater than the answer to the ultimate question of life, the universe, and everything.",
    checker: e=>e.length <= 42
}, {
    description: "Your flag must contain at least three underscores.",
    checker: e=>e.split("").filter((e=>"_" === e)).length >= 3
}, {
    description: "Your flag must not contain the substring <code>flag</code>.",
    checker: e=>!e.includes("flag")
}, {
    description: "Your flag must fulfil the flag format.",
    checker: e=>e.match(/^hkcert23{.*}$/)
}, {
    description: "The number of digits in your flag must be a prime.",
    checker: e=>m(e.split("").filter((e=>"0123456789".includes(e))).length)
}, {
    description: "The number of <code>1</code>'s in your flag must be thrice the number of <code>6</code>'s in your flag.",
    checker: e=>e.split("").filter((e=>"1" === e)).length === 3 * e.split("").filter((e=>"6" === e)).length
}, {
    description: "At most 30% of your flag are digits.",
    checker: e=>e.split("").filter((e=>"0123456789".includes(e))).length / e.length <= .3
}, {
    description: "Your flag must not contain any characters from <code>fail</code>.",
    checker: e=>0 === e.split("").filter((e=>"fail".includes(e))).length
}, {
    description: "Your flag must include at most two distinct vowels.",
    checker: e=>e.split("").filter((e=>"aeiou".includes(e.toLowerCase()))).filter(((e,t,r)=>r.indexOf(e) === t)).length <= 2
}, {
    description: "Your flag must include five characters, not necessarily distinct, from <code>mystiz</code>.",
    checker: e=>5 === e.split("").filter((e=>"mystiz".includes(e))).length
}, {
    description: "Your flag must contain exactly 20 distinct characters.",
    checker: e=>20 === e.split("").filter(((e,t,r)=>r.indexOf(e) === t)).length
}, {
    description: "Your flag must not contain upper-case characters.",
    checker: e=>0 === e.split("").filter((e=>"ABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(e))).length
}, {
    description: "Your flag must contain the substring <code>y0u</code>.",
    checker: e=>e.includes("y0u")
}, {
    description: "Your flag must not contain consecutive double letters.",
    checker: e=>e.length > 1 && [...Array(e.length - 1).keys()].every(((t,r)=>e[r] !== e[r + 1]))
}, {
    description: "At least 40% of your flag are hexadecimal digits.",
    checker: e=>e.split("").filter((e=>"0123456789abcdefABCDEF".includes(e))).length / e.length >= .4
}, {
    description: "Your flag must match the REGEX <code>/[A-Za-z0-9]{9}/</code>.",
    checker: e=>e.match(/[A-Za-z0-9]{9}/)
}, {
    description: "The ASCII values of the characters in your flag must sum up to a multiple of 65.",
    checker: e=>e.split("").map((e=>e.charCodeAt(0))).reduce(((e,t)=>e + t), 0) % 65 === 0
}, {
    description: "Every occurrance of <code>n</code> in your flag must immediately followed by a digit.",
    checker: e=>e.split("").map(((t,r)=>"n" !== t || "0123456789".includes(e[r + 1]))).every((e=>e))
}, {
    description: "No characters in your flag can occur more than 6 times.",
    checker: e=>0 === e.length || e.split("").map((t=>[e.split("").filter((e=>t == e)).length, t])).sort().pop()[0] <= 6
}, {
    description: "Rule 22 should still be satisfied if each of the <code>3</code>s in your flag have been replaced by a <code>@</code>.",
    checker: e=>e.replace(/3/g, "@").split("").map((e=>e.charCodeAt(0))).reduce(((e,t)=>e + t), 0) % 65 === 0
}, {
    description: 'Your flag must reach a strength 4 in <a href="https://dropbox.tech/security/zxcvbn-realistic-password-strength-estimation" target="_blank" ref="nofollow">zxcvbn password test</a>.',
    checker: e=>4 === g(e).score
}, {
    description: "Rule 20 should no longer be satisfied if all of the <code>d</code>s in your flag are removed.",
    checker: e=>e.replace(/d/g, "").split("").filter((e=>"0123456789abcdefABCDEF".includes(e))).length / e.replace(/d/g, "").length < .4
}, {
    description: "Y̸͇̥͙̙̼̰̬͔̜̠̺̮̍̅̊͆͆̂͆̐͊̏͜͝͠ö̵͓̩̲̱͎̠͓̈́͂͂̑̆̌̈́̈́̀̔́̃͛̕u̷̜̜͎̼͙̝͋͆̿̄̕r̵̛͈͉͕̾͂̏̿͌̉ ̸̛̛̛̝̳̩̙͒̔͋ͅf̴͎̲͈̤̠̗͙̠̮͂̀̇̈́̊̄̏͊͘̕͘͘l̷̡͔̤̣̮̓̐̃̆̀̇̂̓͐͝ą̵̛̹͓͈̟͖̒̂̔̑̀̓̓̈̌̓͌͌̀̕ͅǧ̸̨̉̈́̑͋̀͘ ̸̨̺̬̾̓̃̌̔m̸͕̗̏̏̏̉̽͘͘u̵̡̧̢̺̮̘̪̖͖̗̝̲̥͌͂s̶̛̲̥̦̰̊̃́́̉̎̈̂͗͛́̌͘͝t̵̤̳̩͓̦̹͚̫̹̣̪̠͛̃̏́̓̽̃̈̉̐̿̄͋̑͜ ̷̛̭͙͔͉̪͍͖̪̥͙͓̱͍̉̓̈́́̾̎͋͊̈́̈̈́b̸̡̛̗͙̤̠͖̳̄̃̽͂͆͌͠͝e̵̢̛̬̼͖͕̰͍̳̠̟̱͍̞̼͍̍͌̀́́̐̅̽ ̸̛̞̙̓̓͊͛̉̓̀̀̍͋͗̕͘͝▒̴̡̱͋͒̋̐̈́█̴̲̈̀͊͐̀̐̓̆͆͒̊̈̑̐̕▒̷̢̮̗̤̙͖̤̎̿͐▓̸̮̃▓̷͚̩͚͕̯́̉̓̂͝ͅ█̸͚͌͗̑̂̋͛̉͛͋̋͘̚͜▒̴̖͒͝͝▓̸̣̦̊͗̌́̈̓͝█̵̡̡̼̹͖̼̜̦̟̙͖͓͆͊▓̷̨̡̩̼̗̐̋̏̄̒̔͌͂̆͜͝▒̷̛̥̒͂͋͘͠▓̴̢̧͓̠̲̘̖͓̜̱̦̭̭͓͆̈́̀̋̑̔̔͊͗͜͠▒̸͚̬̺̙̪̗̟͋̆̍̎̃̍͑̌̑̿̔̓̈͘͘͜█̶̧̛̞̯̻̥͍̑̽̉̂͂͆͋͌̍̓̋̉͝͝▒̷̫̞̄͛̐́̃̚̕▓̴̨̡̲̬̯̝͉̥̅̇͐͠.̸̨̨̛̠̲̹̮̙̤̬̞̼̖̿͐̒̉̓̎̔̾́͆͝",
    checker: e=>f(e.substr(0, 8)).startsWith("b08c89")
}, {
    description: "Y̴̢͚͉̞̙͕̫͚̝̜͕̩̍̈́̈́̽̃ǫ̴̧̢̳̫̤̰̝͖͖̜̼͚̼̓̇̀́̇̾͑͒̑̈̀̂̓u̷̯̫͎͙̤̰̩̜͇͐̋̌̄́̇̽̈̒̒̈̕͜͜͝r̴̡̧̗̩̼͕͓̗̬͈̤̘̣̟͚̊͒̍̈́͊̚͝ ̷̹̹̺̜̗̮͕̩̗̪̩̗̓̃̋̌͂̐̆͌͘̕̚͝f̶̘̥̘͚̣̝͖̫̬̬̘̝͉̈́̈́̿̈́̑͆̽̾͘͝l̴̢͈̱̜̤̞̬̜̬̟̯̻͒̈́͒̽̓̇͒̊͆͘͠͠ą̸̢̛̞̥̤̞̭̬̻̥̱͆̇͛̒̐̀̅̍̌̉̈́͝͝g̵̡̜͈͎͙̺̘̱̩͈͓̭̈́͊̃̍̃̊̈́͆̓̄͜͝͝ ̵̧̞̜̝̰̻̯̟͖̭̫̒͋͒́̄̓̓͘̕͜͝ͅͅm̸̡̨̧̧͍̻͈̼̜͕͖͚̯̪̅̄̋̉̊̈͐̈́͗̈́̚ǘ̵̮̱̩̋́̈́̀̌̓͒̄̐͌̚͝s̷̨̘͎͓̜͈̙̮̙͍͖͊t̴̙̲͗̽̿͛̊̽̔͋̒̐̎ ̷̝̱͓̞͉̫̏̐́́̔̆̓̀̌͘͝͠b̴̝̗͙͇̘͖̬̲̘̗͍͂̈́̔̾͗̓̽̔̓̕̕͘͝ͅę̴͍̘̲͕́͂͛̅́̓̾̽̚͘̚͜͝͝ ̵̨̛͎͈̙̬̎͐̑̀͗͆͘ͅ▒̸̛͍͓̈́̈́́̂͂̐́̕͠▓̷͚̥̳̼̔͗̒͑̀̃ͅ█̸̥̟̬̝͚̖͔̹̋̃̂͌͑͗̚̕█̸̨̖͓͚͙͙̙̝͔̻̯̲̮͚͐͆͑͗̈̄̎̀̂͒̈͘͜͝█̶̱̳͚̜̘͖̱̼̊̈́͆̓͋͑̄̀̉̐̚▓̴̧̢̡̱̺͚̠̖͋́̑̃̓́̊̔̈́̊͘̚̚▒̵̨̡̢̻̗͎͕͖̱̹̜̝̝̲̉̅͊̀▒̶̡͙̪͕̜͔̬̜͍͗▓̸̥̣̣͗̍͐͠͠█̶̯̯̤̊͋̋̎͊͆͋̾̂̌̅̈́̄̑▓̸͇͓̝̈̒̈́͂█̵̡͎̥̦̙̑̉͒̽͐̂̊̌̔̄̌̽̕͝▒̶̡̨̙͖̬̗͓̞͚̆̚▓̸̧͔͙͓̹͈̫͕̗̅͗̀͑̂͗̂̄̓̀̐̚▒̶͈̭̄͜█̶̨̢̧̧̥͖͕̯͕̗͙͐͊̃̀̎̍̉̍͐̐̃̉̿͜.̴̧̧̡͎̳̻̯̞͖͔̦͔͆͒̅̇̋̍͋̑̿͜",
    checker: e=>p(e.substr(0, 14)).startsWith("d0687a")
}, {
    description: "Ỷ̶̭͙̈́̋͗͒̔̂̋͗̋͝͝ơ̶̡̨͉̤̜̫͍̩̂̿͊̒̄͛͜ų̸̻̙̭̱̆͑̃̋̚͝ͅȑ̴̢̝͈̠͙͍͈̭͙̪̳͉͇̂ ̸̲͇͐̃̋͛͂̓̓̀̾̚͠f̸̨͚̗̺̹̀̈́͆̈̈́̊̀͝l̵̥̝̯̥̗̗̝̙̜̦̝̩̺̊̍̇̑̂̈͑̍̄̇̑͐͘͝͝a̶̡̮͕̩̰͍̩̩͐̽̄̒̇͑̈́̉̍̍͛͊͊͘ģ̸̨̡͇̩̼̪̫̘̬̭̦͓̈́̀̂͝ ̴̛̱̙̜͇͚͖͒͗̑̅́͂̅̊̊̕̚̚͜͝m̷͍̫̖̰͓̀͛̂̿̿͠͝u̷̖͎̰̙̰̘̬͕̒̐͛́s̴̱͍̯͎̘̬̻͎̟̄̋͛͝ṭ̷̨̙̪̗̥͙̝̦̲́̍̃̋̉̑̒͛͘͝ ̸̨̢̡̛͉̹̝̟̜̩͕̼̆̇̄̊̾̓͌̓̃̊́ͅb̴̡̨̡̛͔̥̱̟̱̫̠͚̖̺̀̃̐̇̍̽̿̀̇̏͒͂̚͝ẹ̴͚̟̟͚͖̺̱͕͙̬͎̯̫̝̉ ̴̧̢̘͖͎̤̩̙̳̺̖̅͆́̀̈́̍̉̓͐͛̀̏͂͘͠ͅ█̸̨̤̫̗̬̮̞̤̟́̾̀͘█̷̛͙̰̤̹̼̥̏̐̅̑̊͆́̎͛͋͝͝▓̵̡͈̗͇͔̟̖̮͚̳̙̝͓͗̍͊́̆͊̋͐͊̈́̔̚͠█̷̠̤̽͂̀̎̀̈́̕̚█̷̨̧̦̰̘̱͚̰̣̏͌̇͝▒̸̛̪͕̐͒̑́̀̊͑̃̇̂̈̚▒̶̦̣̙̮̦͓̖̹͚͇̯̋̐͛̔͛͛̊̈́̂̇̌͗͘̕▓̷̬̂̈̈͑̇͛̚▓̸͔̞̬̩͉͍̈́͋͐̑͂͗̀̌̄͒̒̕͠█̴̝͕͙̩̦̺̰̖͍̩̙͖̻̬̖̽̃́͌̈́̌̒̊͠▓̵̢̛̞̳̻͓̣̻̙̖̘̲̐̔́́͗̈́̇̅̒̇͝▓̸͇͔̩̜̖̗̼̔̋̎̽̍̔͂̔̓̒̑͂̔▒̵̡͖̼̺̰͔̜̩͔̺̫̯͉̖̝͗͂̑̎̊͐̉̀̈́̄̔͑͗́█̷̢̛̳̤̣͔͔̯̂͋͑̓̏̔̈́͝ͅ█̵̧̰̓̾̈́͊̒̀͛́̐̐▒̷̨̨̢̧̜͕̲̗̒̾͛͋̎͠͠.̷̧̦͓͇̫̮͚͌͛͊̐̑̉̍̊̈́̚̕ͅ",
    checker: e=>p(e.substr(0, 12)).startsWith("87b3c7")
}, {
    description: "Ŷ̴̝ǒ̶̬̼͝ȕ̵͉̺̊r̵͈̎́ ̷̘̆͌f̶̟̎l̸̲͐ạ̶̜͐̈́g̷̨̖͝ ̷̛̰̽m̶͉͙̽ū̶͖̥̀ś̸̢͔͝ẗ̴͕̮̌ ̸̪̾́b̵̜̋e̵̟̟͌̓ ̵̨̍̚▓̸̬̕▒̷̻̙̉▒̴̳̘͂█̴̜̆͛▓̸̽ͅ▓̷̬̅͂▒̴̬̗̏▒̴̳͚́̇█̷̞͛▓̶̱͕̐▒̷̳̒▒̵̲̿▓̵̝̯͘▓̶̠̈̈́▓̵̜̘͐▒̷̼̙̓̏.̸̧̹̎",
    checker: e=>f(e.substr(0, 22)).startsWith("8b035b")
}, {
    description: "Ỷ̴̮͍͒ǫ̴̈́ŭ̸̧͚͒r̴̳̓ ̵̘͇̅͆f̷̮̑ḻ̴̡̂ă̵͇͋͜g̵͇͆ ̸̝̯͐̇m̵͚̿u̵͙̜͆̽s̷̢͠t̴̩̳̔̕ ̴͈̤̒̒b̵͓̄è̷̞̉ ̴̘̓̍█̷̧̖̈́▒̸̈́̕ͅ▒̵̟͛█̵̟͑̀▓̴͍͊▓̴͖͚̓̎█̶͙̝̍█̶̠̐̕▒̴͍̐̊█̴̮̑̾ͅ█̵̿ͅ▓̸͓̂█̴̧̯̊̒█̶̲̞̍▒̴̱̉͠▒̸̪̑.̷̻̅",
    checker: e=>f(e.substr(0, 40)).startsWith("8a9de8")
}, {
    description: "Y̶̼̥̔̚ȏ̴̟̦u̶̗͆r̴̨̛ ̸̤͖̉f̶̪̣͒l̷͎̾a̵͖̜̒́ḡ̵̣͖̇ ̸̺͕͌͗m̸̞̫͊̉u̶̫͎̓s̸̜͑̊t̵͈͕̚ ̶̹̋̽b̶̯̑̈ẻ̴̜̈́ ̴̟́̽▓̶̛̹͂▓̴̡̈́█̴͚̻̃̉█̸̦͇̓▓̴͓̻͊̅▓̴̗̹͂▓̸̯͈̈́̉█̸̹̠̏▓̷̐̾͜█̸͔̃▒̶̺͐͜▓̶͚̯͗͛▓̴̹̖̈́͑█̴̙̬̄▓̶̖͔̔̔█̶͔͖͊͛.̷͓̎̾",
    checker: e=>p(e.substr(0, 26)).startsWith("7be965")
}, {
    description: "Y̴̬͊͘͝ö̵̺́ȗ̴͈̌͐r̸͇̀͐͗ ̷̗̬̭͒͛͐f̴̗͓̂ḻ̴͎̝̄a̵̡̚g̷̻̹̯̒̾ ̷̜̎͘m̶̪̎͌ṷ̴̿ṡ̶̺̇̕t̷͖́̃ ̷̺͛͝b̸͈͑̋́e̷̢͇͒ ̷̭̪̈́█̶̲̔▒̵̧̺͂͂͜▓̴̦̰̉̄▒̸̗̓̔▓̴͉̻̇̑͘͜▓̶̛͎̀▒̶̧̆█̴̢̪̻̐▓̸̥̗̞̓̒͊▒̷̹̋̂̀▓̶̧̠͖̈̌▒̷̯͆█̶̙͈̟̓͛▓̶̰̉▒̷̡̟̾̕▒̴̟̑̎̽ͅ.̸̯͈̾͌̔ͅ",
    checker: e=>f(e.substr(0, 30)).startsWith("bf7eeb")
}, {
    description: "Y̴̨̠̓̕͘ő̶̥̖̈́u̸̪̎͆̊r̵͕̀ ̶̧̞͔̄̈́̕f̴͙͌l̸̲̩̫̀ḁ̸͚̎̅͑g̵͉̲̬̀͊̔ ̵̤͎͒̅̾m̵̼̮͋̑̌u̷͉̤͔̔̏̃s̵̬̋̔t̷̥͚̘̃̑ ̷̞͆̏b̴̩͙̓̕ê̸̖ ̷̨͚̒́▓̷͉̉▓̷̙̯̹̆͐█̸̡̨̮͗̍▓̷͋͜▒̷͍̩͌̈́̏▒̶̢̽͂͒▒̵̙̹̯̑̈́̈́▒̷̥̮̣̋͂̾▓̵̢̈̅̏▒̴̰͚̈́̎́▒̵͇͎͛̀█̷̲̦̈̓̔█̷̡̇̈́█̸̜̬͆̈́̀▒̷̡̦̆̓▓̵͎̱̱͂̍.̶̮̿̓̕",
    checker: e=>p(e.substr(0, 36)).startsWith("7ef31a")
}, {
    description: "Y̷̡͍̠͆̈́o̵̰̹̫̍͑ǘ̴̳͍̑̂r̵͍̀͆̃ͅ ̶̲̿̋̽f̴̤̊l̶̢̐͒͜a̷̧̘̥͋́̋g̵̳̅ ̵̼̣̱̀͂m̴̰͍̮̂u̸̜̞̲͐̽̀s̴̪̄̑ṯ̷̬̋ ̸̟̪̓͘͝b̴͍̄ë̸͖͖̙͘̕ ̴̛̟̃̍ͅ▒̵̖̊͊͜█̵̢͎͒█̵͕̯̈́█̸̞̊̋̌▓̷̘́̐▓̵͙͐▒̶̤̏͊͝▓̶̜͒▓̷̤̗͙̊̚▒̶̟̙͕͑̀̔▓̴̢̦͗̀͝▒̶̙͈̈▓̴͖̌█̶̖͚̥͝▓̵̡̮̂▓̴̥͉̄.̴̛͔̙̓̀",
    checker: e=>p(e.substr(0, 24)).startsWith("40f34c")
}, {
    description: "Y̴̨̤̒͜ŏ̸̝͇͜u̷̡̹̇r̷̺͎̘͝ ̷͕͚̋f̵͕͖̗̈̋l̵͉̣̕ậ̵̛̂ǵ̸͓ ̴̨̣̪̄͐͐m̸̻̀̋̑ṵ̵̡̖̌ś̶̩̗͌͒t̵͓̙̀̽̒ ̴̰͓̱̓͗b̴̢̈́͛͜ȇ̴̹ ̵̰̐█̸̱̰̭̂█̶̘̈̉█̸̖̟͇͆█̵̧̪̒̿█̴̜͂͗▓̴̥͚͓̀█̶̡̛̼̥̅͘▒̴̻͓͂▒̷̳̿▓̵̰̹̬̍▓̶̜̗̉̾▓̶̺̆̊̏ͅ█̶̳̬̆▓̸̨̬̤̂͑̏▓̶̼̠̹̈́█̵̹̞͗̀̚.̶̘̍̏̇",
    checker: e=>p(e.substr(0, 20)).startsWith("b72709")
}, {
    description: "Y̷̳̮̓͑́o̵̰̩̾̓̎ű̷͙͇r̸̰̫̰̃̇̑ ̵̨̙̟͂̔̄f̴͓̝͑l̵̝̺̥̑̈́a̷͖͓̔͜g̵̝͇̅́͂ ̵͉̺̊̓̀ṁ̵̭̙̆u̵̲͂̉s̵̩̅͑ͅt̵̙̳̒̚ͅ ̴̢̲̩͒̊b̷̳̤̈è̷̡̈ ̸̞͙͛̋̒█̴̨̺̿̃ͅ▒̷̹͑͜█̸̯̎͒̌█̸͍̘͐̈́▒̷̩̲͈͆▓̵̥̖̈́▒̴̺̂̽█̴̨̪̣̚▒̵̲̮̊▓̷̳͐▒̷̼̹͈͋͝█̵̟̳̻̂͘▒̶̧̪̇▒̸̦͉̭̈█̸̃͛ͅ█̸̡̇.̶͙̻͒̄̋",
    checker: e=>p(e.substr(0, 38)).startsWith("e3c817")
}, {
    description: "Y̶̮͙͆̓̄o̵͈͎̅̉̔u̴̲̻͋̑r̷̰̰͐̚ ̷̦̫̪̎͠f̶̼̀l̷̹̇̆͝a̴̛͓̰̺g̵̯͒ ̴̛̯͉͛͠m̷̹͙̓̉̏ụ̷̊s̵̨̠̕t̸͓̫̞̆ ̷͍͝b̷̲́̉͠ė̶̡̺̱ ̴͖̀█̸̝͗̂▒̷̠́́͝▓̸̙̝͈̎́▓̴͓͑▒̸͎̈́̿̕▓̶̪̀▓̶̧͕̇ͅ█̴̜̰͛̎▓̴̡̯̰̇͒▒̵͖̌▓̶͓̦̈̀▒̵͎͎͚̔█̵͔͉͆̔█̶̩̦̞̃█̷̨̣͈́█̵̱̣̩̊̃.̵̛̗͒",
    checker: e=>f(e.substr(0, 28)).startsWith("0b67cb")
}, {
    description: "Ȳ̷̢͙̒͒o̵̡̩̳̗͑̄ũ̴͔̱̉̒̃r̶͎̯̱͐́ ̷̠̦̀̑̚ͅf̵̠̤̭́͠l̴͕̲̿͝͠a̸̘͕̭̹͌g̸̬̹̏ ̵̮͐̑m̶̮̫̟͋̔ụ̸͇̅s̴͎͇̆̔͆̚ţ̶̙̮̼̐̌ ̴͙͒̓͋̇b̷̢̒͝e̶̙͈͖̊̽͜͠ ̸̩̝̕͝▓̵̼͈́͜▒̷̙͈̓͛̕͜█̸͓̘̤͂͑͋͌▒̶̙̱̗͇̑͆͠͝█̸̦͆̓█̵͔͓́▓̵̡̩́▒̵̛̦̫̬͔▓̶̦̹̯̒ͅ█̵͔͖̊̿̇▒̸͍̜͂̚▒̴̲̋͐▒̴͎̻͝▓̸̫̾͊█̷̡͍͓̼̄̀̿̒▓̴̄̃̄͜.̷̢̟͌̔̎̈",
    checker: e=>p(e.substr(0, 32)).startsWith("f9f48b")
}, {
    description: "Y̵͖͇͐̌̇ö̶͖͆u̴̪̍ŗ̵̛̼̗̦̒ ̷̠̣̠͆̋͜͝f̸͖͛l̸̡̢̛̠͒a̷̡̩̗͗g̶̖͍̅́̋͛ ̸̨̮̺̯͝m̵̩͍͛͜͝͠u̶͎̩͑̊̈́̀s̵͕̀͛ṫ̴̩̣̰̺ ̶͍̦̃͂b̷̲̣͝e̶͇̮̊̈́ ̴̢͓͊͝▓̶̣̳̠̻͗͑▓̵̌̀̈́́ͅ▓̶̘͎̅͋̇͊█̷̣̰̥͎̽█̵̢̜̩͎̆̅̀̓▓̴̘̦̦͉͂̉͒̚█̴̟̭͎̱̈́▓̴̭͔̗͐̏̇͗͜▓̷̻̪̝͆͝█̶͉̬̠̥̉̑̔█̵͚̠͈̦̈́́͊▒̸͓͎͈́́▒̷̱̲̖̾̽▓̷̱̺̋̈́͋̽▒̸̨͗̾͐▒̶̛͈͓̺̯̃́.̴̱̺͎̽̈́̿",
    checker: e=>f(e.substr(0, 34)).startsWith("69260f")
}, {
    description: "Ỵ̶͕̹͆́o̵̪͙̖͛̈́́͝ȕ̸͓̭̈́͠ṟ̵̌͗̎ ̸͚̘͐́f̶̡̛̫̻̤̔l̵͈͂̉͝ͅa̸͈͠͝g̷̝͂̒͐̒ ̵̢̦̈́̊̀͊m̸̗̅̌̋͜͝u̴̢̩̇̎͘͠s̸͇̟̻͐͘t̸̩̮̯͗̀͠ ̸̖̄͜͠b̵̮̤́̓͘ē̵̙̙͋̒ ̵̨̠̈́̾█̴̞̌͠▓̵̧͉̲̼͑█̸̗̫̽▒̷̃͒̃͜█̷̻̼̯̽̈́̔▓̶͓̩̪̌█̴̡̙͍̻̈͊█̸̨̬̱̎͑̎█̵̦͈̈́̎̔ͅ▒̸̝͍̼̥͂͂͊͘▒̴̛̯̥̯̣̇̕▓̵̬̮̟͉̋▒̷̤̪͓̼͒▒̴̧̛͈͖͊̌͒͜▓̵̡̂͆▓̷̭̙̫̿.̸̳̚",
    checker: e=>p(e.substr(0, 18)).startsWith("c25dd2")
}, {
    description: "Ỳ̷̼͝o̴͈̊u̴̞̱̹̒̑̕ṙ̴̼̳̱͖̚͜ ̴̠̦̃͋̕͝f̷̨̲̣́̈́l̷͚͊̉̎ã̶̧̲̱̩g̴̠͓̊̑̾ ̶̺͇̗̂̂͑ḿ̴̳̎̋̈́̕u̸̯̭̳͂͌̊s̸͕͖̬͓͋̉̃̏̑ţ̷̯̟̃̉̏̄ ̶̗̞̣̦̤̄͗͌͑̀b̷̨̭̗̈́̓̐e̸̹̰̱̫͛̑̑̚ ̸̨̬̱̲̮͑̓̓▒̷̪̲͆̇▒̷̠͌̈̓͂͝▓̴͎̖̃́͗̇█̴̖̲̀▓̶̨̭͈̗̃͜▒̸̢̭̑̊̆█̷̭͍͈̍̑͘͝█̵̠̼̺̠̭̒̑̃́█̵̣̈͘█̷͚̫̮̔̆́̕▓̶͖̭͙̼͗̐█̸̱͔̇͊̐͗̓͜█̷̡̤̯͖̉͗͊̉̉█̴̡͛̔͠█̷̜͛͑̃̂█̴̢̦̥̯̽.̸̳͔͓͙̈̈̏̔ͅ",
    checker: e=>p(e.substr(0, 16)).startsWith("cbe2c9")
}, {
    description: "Ÿ̶̻́̍͒͂̒ǫ̵̔̍͝û̶̯̯͙̌̾͛̂ŕ̸̜̥̪̓̂̈́ ̵̝͇͑̉̓̽͠ͅf̷̧̖͖̌ḻ̵̨̅̒a̸̳͍͔̭͗̽͋̽g̴̼̉̄͑̔̕ ̷̪̹̃̇̆̾̇ḿ̷͔͖̤͘ų̴̫̓̈́̍s̷̢̹̎t̴̞̬͋̑̒͜ ̷̡̭͙̠̃͑̈́̅͒b̷̻̟̜͇̏̾̏͌̕ȇ̶̢͕̜͖̜́̄̈ ̷̝͕̦̦̾̒▒̵̧͖̤̑͛͐̎̈́▓̵̨̝͗̔̈́͘█̵̰̻̐̿͌͂͌▓̸͔̙͎̥̀̌́̓▓̸̛̯̤͈̦̓͛▓̴̧̢͇͔̈́̃͆͘̕█̵̯̤̲̦̗̈█̷̢̣̳̙̰̈́̚█̸̙̬̩̗̂̃̓̍͐█̷̪̗͇͙͒̔͜▓̷͈̱̻̬͇̑█̵̱̫̯̪̙́̋͐█̴͙͕̟̱̞͋█̸͓̏͋̀▒̵̥͕͆͊̾͘͝▒̸̺̗͎̫̏.̵̺͝",
    checker: e=>f(e.substr(0, 10)).startsWith("ce45fd")
}, {
    description: "Y̶̤̺̝͋͊̑͠͝o̸͎͈̩͌͂̅̒ṷ̸̪̈́̽r̴̙̯̦̗̈̄̿̀͗ ̸̜̿̌f̵̧̼͎͍͗̓ͅļ̶̛̼͇̅a̴̖̦̯͆͆͝͝g̴̘̅̿̓͛ ̸̰͓̩͙̐͘͝m̵̫̳̙͌̀̎ụ̶̉̃s̶͋ͅt̶̥͖̜̟̒̽͂͝ ̶̲̜̘͑̐͋̈́b̷̞̐̈̔̋̽͜e̷̡̻̰̅̍͗̓̒ ̵͚̠̠͍̒̑▒̸̫̜̉̉́͠▓̴̢͚́̑̿̈́█̶̬̖̞̓͂̀͒▒̴̩͙͜͝▒̵̗̦̕͠█̷̯̫̝͒̽̾̋▓̷̭̺̻͕̄̄̉̏̇▒̷̧̎▒̶̣̫̱̐̒▒̶̫͚̙̈́▒̴̺̬̼͈̏̎̐̕█̶͓̩͗͂̐̐▒̸̱̗̹̬͒̍▓̸̠̦̋̿̊̈▒̵̝̑̐̊̓̈█̶̜̔̊ͅ.̶̧̛̣͊͐̂",
    checker: e=>p(e.substr(0, 42)).startsWith("e3c817")
}

可以看到 description 为 Rule 的描述, checker 为 Rule 的判断方式
后面的题目描述都看不清了,说明直接玩游戏是不可能得到 flag 的,需要通过 Rule 来计算

由可以看到的 Rules 中,我们可以记住几个关键的 Rule :

  • flag 开头是 hkcert23
  • flag 的长度是奇数
  • flag 中需要包含 _
  • flag 中不能包含 fail 中的任意字符

根据字符的限制,我们可以得到 flag 可能包含的字符

characters = "bcdeghjkmnopqrstuvwxyz0123456789_}"

再关注到后面的判断方式是函数 ef 判断,搜索 js 代码后可以发现
f 代表 sha224 ; e 代表 sha256

const { sha224: f, sha256: p } = r(9946);

同时,哈希的计算包含了每一个字符,所以我们可以通过计算来得到 flag 的每一个字符

0x02 Exploit

用 Python 编写脚本计算

import hashlib
import itertools

rules = [
    # (8, "sha224", "b08c89"),
    (10, "sha224", "ce45fd"),
    (12, "sha256", "87b3c7"),
    (14, "sha256", "d0687a"),
    (16, "sha256", "cbe2c9"),
    (18, "sha256", "c25dd2"),
    (20, "sha256", "b72709"),
    (22, "sha224", "8b035b"),
    (24, "sha256", "40f34c"),
    (26, "sha256", "7be965"),
    (28, "sha224", "0b67cb"),
    (30, "sha224", "bf7eeb"),
    (32, "sha256", "f9f48b"),
    (34, "sha224", "69260f"),
    (36, "sha256", "7ef31a"),
    (37, "sha224", "8a9de8"), # 长度为40跑不出结果,猜测已经达到长度上限,改为比40小的第一个质数
    # (40, "sha224", "8a9de8"),
    # (38, "sha256", "e3c817"),
    # (42, "sha256", "e3c817"),
]


def generate_combinations(characters, length):
    for p in itertools.product(characters, repeat=length):
        yield "".join(p)


def test_rule(candidate):
    # 用candidate去匹配rules
    for length, algorithm, hexdigest in rules:
        hash = hashlib.new(algorithm)
        if length > len(candidate):
            continue
        hash.update(candidate[:length].encode())
        if hash.hexdigest()[: len(hexdigest)] != hexdigest:
            return False
    return True


def get_flag(prefix, length):
    characters = "bcdeghjkmnopqrstuvwxyz0123456789_}"
    for candidate in generate_combinations(characters, length):
        candidate = prefix + candidate
        print(candidate)
        # 测试规则
        if test_rule(candidate):
            print(f"Found: {candidate}")
            return candidate
    return "not found"


prefix = "hkcert23{"
# 生成长度为length的只包含characters中字符的字符串的全排列
for length, algorithm, hexdigest in rules:
    print(f"Trying length {length - len(prefix)}")
    flag = get_flag(prefix, length - len(prefix))
    if flag != "not found":
        prefix = flag
    else:
        flag = get_flag(prefix, length - len(prefix))
# prefix 包含hkcert{ 和 } 就break
if "hkcert{" in flag and "}" in flag:
    exit(0)

0x03 Flag

hkcert23{h0p3_y0u_u53d_th3_s0urc3m4p}
上次编辑于:
贡献者: HaynesChen,HaynesChennn
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3