The Flag Game
原创2023年11月23日...大约 6 分钟
練功練功
好過喺度亂想一通
講到天花龍鳳
帶人遊西北東
I'm so turn off 唔該你練功練功
坐而言起而行練練功
你已經玩過密碼遊戲了吧?來玩旗幟遊戲!
0x01 分析
The flag game
特别像 Password-Game
随便玩一下发现规则很多,查看 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_}"
再关注到后面的判断方式是函数 e
和 f
判断,搜索 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}
Powered by Waline v3.3.1