この大会は2023/11/25 3:00(JST)~2023/11/27 3:00(JST)に開催されました。
今回もチームで参戦。結果は550点で831チーム中87位でした。
自分で解けた問題をWriteupとして書いておきます。
Welcome challenge (intro)
Discordに入り、#rulesチャネルにあるルール内にフラグが書いてあった。
gctf{w3lc0m3_t0_g1ac13rctf_2023}
Skilift (intro)
逆算して、tmp1を算出し、keyの1つを割り出す。
#!/usr/bin/env python3 tmp4 = 0x5443474D489DFDD3 tmp3 = tmp4 + 12345678 tmp2 = tmp3 ^ int.from_bytes(b'HACKERS!', 'big') tmp1 = tmp2 >> 5 print(hex(tmp1))
この結果は以下の通り。
0xe0102030604060
これを入力する。
$ nc chall.glacierctf.com 13375 ∗ ∗ ∗ ∗ ∗ ∗ ∗ ◦◦╽◦◦ ∗ ∗ ∗ ◦◦ █ ◦ ∗ ◦◦ █ ∗ ∗ ∗ ◦◦ █ ∗ ∗ ◦╽◦◦ ◦◦◦◦ █ ◦◦ █ ◦◦◦ ◦◦╽◦◦◦◦◦◦ █ ◦◦ █ ◦◦◦◦◦◦◦◦◦◦◦ █ █ ■■■■■■■■ ◦◦◦◦ █ ▛ █ ∗ █ ∗ ▟ ▙ ◦◦◦ █ ∗ ▌ █ ∗ █ ∗ ▟ ▙ █ ██████ ∗ █ █ ▟ ▙ ∗ █ █ █ █ █ ▛▀▀▀▀▀▀▀▀▀▀▀▀▜ █ ██████ █ █░░░ ▌ ▐ █ █ ∗ ░░░░░ ▌ ▐ ∗ █ █ ░░░░░▒▒ ▌ ▛▀▀▀▜ ▐ █ ∗ █ ░░░░░▒░░░ ∗ ▌ ▌ ▐ ▐ ∗ █ ∗ ░░░░░░░▓░░░░░░▒▒░░░ ▌ ▌ ╾ ▐ ▐ █░░░░░ ░░░░▒░░░░▓░░░░░░░░░░░░ ▌ ▌ ▐ ▐ ░░░░░▒▒▒░░░░░░░░░░░░░░░░░▒▒▒░░░░░░░▓▓▓ ▙▄▄▙▄▄▄▟▄▄▄▄▄▟ ░░░░▒▒░░░░▓▓░░░░░░░░░▓░░░░░░░░░░░░░░░░ ░░░░░░░░░░░▒▒▒░░░░▒░░░░░░░░░░░░░░░░░░░░▓▓░░░░░░░░░▓▓░░▒▒░░░░ ░░▓░░▒░░░▓░░░░░░░░░░░░░░░░░▒░▓░░░▒░░░░▓░░░░░▒░░░░▓▓░▒▒░░░░░░ ░▓▓░░▒░░░░░░▒░░░░░░░░░░░░░░░▓▓▓░░░▒░░░░░░░░░▒▒░▒░░░░░░░░▒░░░ ░░░░░░░▒░░░░░░░░▓▓▓░░░░▒▒░░▒░░░░░░▒▓▓░░▒▒░░░░░░▓░░▓░░░░▓▒░░░ ░░░▒░░░▓░░░░░▒░░░░░░▒▓░░░░░░░░░░░░░▓░░░░░░░▓░░▓░▓░░░░░░▓░░░░ ░░░░░░▓▓░░░▒▒▒░░░░░░░▓▓▓▓▓░░░░▒░░░░░▒░░░░░░░░░░▒░░░░▒░░░░░░░ ░░░░▓░▒▒▒░░░░░░░░░░▒░░░░░░░░░░▓▓▓▒░░░░░░░░░▒░░░░▓░░░░░▓▓░░▒░ ░░▓▓░░░░░░░▓░░▒░░░░░░░░░▒▒▒▒▒░░░░░░░░▒░▒▒░░░░░▓▓░░░░▓▓░░░░░░ ╔═════════════════════════════╗ ║ > Welcome to SkiOS v1.0.0 ║ ║ ║ ║ > Please provide the ║ ║ master key to start ║ ║ the ski lift ║ ║ ║ ║ (format 0x1234567812345678) ║ ║ ║ ╚═════════════════════════════╝ Please input your key >0xe0102030604060 gctf{V3r1log_ISnT_SO_H4rd_4fTer_4ll_!1!}
gctf{V3r1log_ISnT_SO_H4rd_4fTer_4ll_!1!}
ARISAI (intro)
Multi-Prime RSAの問題。構成する素数のビット数は小さいので、Nをfactordbで素因数分解する。
N = 8441831 * 8450987 * 8452019 * 8473027 * 8476817 * 8523661 * 8525711 * 8608673 * 8633423 * 8641453 * 8725153^2 * 8786017 * 8796721 * 8824679 * 8850601 * 8913481 * 8933437 * 9016037 * 9041551 * 9075889 * 9095939 * 9126197 * 9142547 * 9163981 * 9172531 * 9196001 * 9223867 * 9253319 * 9265309 * 9277921 * 9298747 * 9300803 * 9357883 * 9368759 * 9405353 * 9444839 * 9552029 * 9569057 * 9584371 * 9663629 * 9696719 * 9720223 * 9748049 * 9770723 * 9801269 * 9828727 * 9836483 * 9838117 * 9853043 * 9873373 * 9883469 * 9884603 * 9905167 * 9989579 * 10000759 * 10064897 * 10114409 * 10122389 * 10213001 * 10214591 * 10228861 * 10235447 * 10344643 * 10428001 * 10433911 * 10438013 * 10441523 * 10476001 * 10514083 * 10523977 * 10605817 * 10650929 * 10667479 * 10699517 * 10731407 * 10732091 * 10754837 * 10773781 * 10849837 * 10861127 * 10893173 * 10918459 * 10943417 * 10944433 * 11028001 * 11049739 * 11057621 * 11073793 * 11084419 * 11113789 * 11152859 * 11156681 * 11230451 * 11239903 * 11369903^2 * 11462177 * 11470343 * 11504419 * 11519971 * 11543971 * 11559637 * 11625619 * 11633267 * 11661121 * 11768401 * 11847721 * 11909747 * 11915809 * 11925691 * 11928173 * 11945093 * 11990089 * 12010259 * 12089663 * 12109277 * 12231853 * 12240667 * 12274813 * 12319117 * 12339689 * 12350357 * 12358079 * 12387329 * 12407609 * 12407959 * 12515033 * 12550357 * 12599803 * 12621067 * 12652597 * 12705883 * 12804707 * 12808151 * 12824027 * 12932669 * 12967831 * 13046717 * 13059269 * 13076249 * 13128433 * 13170671 * 13202297 * 13227367 * 13328803 * 13366687 * 13371181 * 13415921 * 13417357 * 13424921 * 13430423 * 13534007 * 13561657 * 13566431 * 13568981 * 13587683 * 13625263 * 13653811 * 13655797 * 13669967 * 13673927 * 13755149 * 13799299 * 13823059 * 13865617 * 13870601 * 13997617 * 14013617 * 14044937 * 14046449 * 14086979 * 14103413 * 14162843 * 14217041 * 14311291 * 14339863 * 14340289 * 14377679 * 14407667 * 14423561 * 14435203 * 14465153 * 14466281 * 14475521 * 14482381 * 14535811 * 14548939 * 14549063 * 14588369 * 14624459 * 14633851 * 14650763 * 14693927 * 14713939 * 14738869 * 14797501 * 14880347 * 14910199 * 14922409 * 14982181 * 15005579 * 15020413 * 15031937 * 15103373 * 15181499 * 15185399 * 15209617 * 15232961 * 15299831 * 15365261 * 15441739 * 15459343 * 15470893 * 15475193 * 15489707 * 15501071 * 15682181 * 15689647 * 15689981 * 15707093 * 15707143 * 15748631 * 15792169 * 15793247 * 15798877 * 15922301 * 15947639 * 16032721 * 16045049 * 16071229 * 16080319 * 16175597 * 16177433^2 * 16198717 * 16199101 * 16212913 * 16225283 * 16254883 * 16312763 * 16336267 * 16359283 * 16405027 * 16432721 * 16497373 * 16593167 * 16594681 * 16629163 * 16632713 * 16643707 * 16657153 * 16679137 * 16701907 * 16738913 * 16755269
このことを元に同じ値のべき乗があることに注意しphiを算出し、さらにdを算出し復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * with open('output.txt', 'r') as f: params = f.read().splitlines() N = int(params[0].split('=')[1]) e = int(params[1].split('=')[1]) ct = int(params[2].split('=')[1]) factor = '8441831 * 8450987 * 8452019 * 8473027 * 8476817 * 8523661 * 8525711 * 8608673 * 8633423 * 8641453 * 8725153^2 * 8786017 * 8796721 * 8824679 * 8850601 * 8913481 * 8933437 * 9016037 * 9041551 * 9075889 * 9095939 * 9126197 * 9142547 * 9163981 * 9172531 * 9196001 * 9223867 * 9253319 * 9265309 * 9277921 * 9298747 * 9300803 * 9357883 * 9368759 * 9405353 * 9444839 * 9552029 * 9569057 * 9584371 * 9663629 * 9696719 * 9720223 * 9748049 * 9770723 * 9801269 * 9828727 * 9836483 * 9838117 * 9853043 * 9873373 * 9883469 * 9884603 * 9905167 * 9989579 * 10000759 * 10064897 * 10114409 * 10122389 * 10213001 * 10214591 * 10228861 * 10235447 * 10344643 * 10428001 * 10433911 * 10438013 * 10441523 * 10476001 * 10514083 * 10523977 * 10605817 * 10650929 * 10667479 * 10699517 * 10731407 * 10732091 * 10754837 * 10773781 * 10849837 * 10861127 * 10893173 * 10918459 * 10943417 * 10944433 * 11028001 * 11049739 * 11057621 * 11073793 * 11084419 * 11113789 * 11152859 * 11156681 * 11230451 * 11239903 * 11369903^2 * 11462177 * 11470343 * 11504419 * 11519971 * 11543971 * 11559637 * 11625619 * 11633267 * 11661121 * 11768401 * 11847721 * 11909747 * 11915809 * 11925691 * 11928173 * 11945093 * 11990089 * 12010259 * 12089663 * 12109277 * 12231853 * 12240667 * 12274813 * 12319117 * 12339689 * 12350357 * 12358079 * 12387329 * 12407609 * 12407959 * 12515033 * 12550357 * 12599803 * 12621067 * 12652597 * 12705883 * 12804707 * 12808151 * 12824027 * 12932669 * 12967831 * 13046717 * 13059269 * 13076249 * 13128433 * 13170671 * 13202297 * 13227367 * 13328803 * 13366687 * 13371181 * 13415921 * 13417357 * 13424921 * 13430423 * 13534007 * 13561657 * 13566431 * 13568981 * 13587683 * 13625263 * 13653811 * 13655797 * 13669967 * 13673927 * 13755149 * 13799299 * 13823059 * 13865617 * 13870601 * 13997617 * 14013617 * 14044937 * 14046449 * 14086979 * 14103413 * 14162843 * 14217041 * 14311291 * 14339863 * 14340289 * 14377679 * 14407667 * 14423561 * 14435203 * 14465153 * 14466281 * 14475521 * 14482381 * 14535811 * 14548939 * 14549063 * 14588369 * 14624459 * 14633851 * 14650763 * 14693927 * 14713939 * 14738869 * 14797501 * 14880347 * 14910199 * 14922409 * 14982181 * 15005579 * 15020413 * 15031937 * 15103373 * 15181499 * 15185399 * 15209617 * 15232961 * 15299831 * 15365261 * 15441739 * 15459343 * 15470893 * 15475193 * 15489707 * 15501071 * 15682181 * 15689647 * 15689981 * 15707093 * 15707143 * 15748631 * 15792169 * 15793247 * 15798877 * 15922301 * 15947639 * 16032721 * 16045049 * 16071229 * 16080319 * 16175597 * 16177433^2 * 16198717 * 16199101 * 16212913 * 16225283 * 16254883 * 16312763 * 16336267 * 16359283 * 16405027 * 16432721 * 16497373 * 16593167 * 16594681 * 16629163 * 16632713 * 16643707 * 16657153 * 16679137 * 16701907 * 16738913 * 16755269' ps = factor.split(' * ') phi = 1 for p in ps: if '^' in p: b = int(p.split('^')[0]) pwr = int(p.split('^')[1]) phi *= pow(b, pwr - 1) * (b - 1) else: phi *= int(p) - 1 d = inverse(e, phi) m = pow(ct, d, N) flag = long_to_bytes(m).decode() print(flag)
gctf{maybe_I_should_have_used_bigger_primes}
Password recovery (rev)
Ghidraでデコンパイルする。
undefined8 main(void) { byte bVar1; int iVar2; ulong uVar3; size_t sVar4; long in_FS_OFFSET; ulong local_b8; ulong local_b0; byte local_98 [64]; char local_58 [56]; long local_20; local_20 = *(long *)(in_FS_OFFSET + 0x28); printf("Enter your name: "); __isoc99_scanf(&DAT_00102016,local_98); printf("Enter your password: "); __isoc99_scanf(&DAT_00102016,local_58); local_b8 = 0; while( true ) { sVar4 = strlen((char *)local_98); if (sVar4 <= local_b8) break; uVar3 = next_rand_value(); sVar4 = strlen((char *)local_98); bVar1 = local_98[local_b8]; local_98[local_b8] = local_98[uVar3 % sVar4]; local_98[uVar3 % sVar4] = bVar1; local_b8 = local_b8 + 1; } local_b0 = 0; while( true ) { sVar4 = strlen((char *)local_98); if (sVar4 <= local_b0) break; local_98[local_b0] = local_98[local_b0] ^ *(byte *)((long)&key + (ulong)((uint)local_b0 & 7)); local_98[local_b0] = (char)local_98[local_b0] % '\x1a'; local_98[local_b0] = local_98[local_b0] + 0x61; local_b0 = local_b0 + 1; } iVar2 = strcmp((char *)local_98,local_58); if (iVar2 == 0) { puts("Valid!"); } else { puts("Invalid!"); } if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; } undefined8 next_rand_value(void) { state = xor_shift(state); return state; } ulong xor_shift(ulong param_1) { param_1 = param_1 ^ param_1 << 0xd; param_1 = param_1 ^ param_1 >> 0x11; return param_1 ^ param_1 << 5; } state XREF[4]: Entry Point(*), next_rand_value:00101227(R), next_rand_value:00101236(W), next_rand_value:0010123d(R) 00104010 37 13 00 undefined8 0000000000001337h 00 00 00 00 00 key XREF[3]: Entry Point(*), main:001013a3(*), main:001013cf(*) 00104018 de c0 ef undefined8 1337DEADBEEFC0DEh be ad de 37 13
nameからpasswordを算出している。gdbで比較している文字列を確認する。
$ gdb -q ./app Reading symbols from ./app... (No debugging symbols found in ./app) gdb-peda$ start Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated. Use 'set logging enabled off'. Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated. Use 'set logging enabled on'. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [----------------------------------registers-----------------------------------] RAX: 0x555555555246 (<main>: endbr64) RBX: 0x7fffffffde78 --> 0x7fffffffe203 ("/media/sf_Shared/app") RCX: 0x555555557d98 --> 0x5555555551a0 (<__do_global_dtors_aux>: endbr64) RDX: 0x7fffffffde88 --> 0x7fffffffe218 ("CLUTTER_IM_MODULE=xim") RSI: 0x7fffffffde78 --> 0x7fffffffe203 ("/media/sf_Shared/app") RDI: 0x1 RBP: 0x7fffffffdd60 --> 0x1 RSP: 0x7fffffffdd60 --> 0x1 RIP: 0x55555555524e (<main+8>: push rbx) R8 : 0x0 R9 : 0x7ffff7fcfaf0 (<_dl_fini>: push rbp) R10: 0x7ffff7fcb858 --> 0xa00120000000e R11: 0x7ffff7fe1cf0 (<_dl_audit_preinit>: mov eax,DWORD PTR [rip+0x1b162] # 0x7ffff7ffce58 <_rtld_global_ro+888>) R12: 0x0 R13: 0x7fffffffde88 --> 0x7fffffffe218 ("CLUTTER_IM_MODULE=xim") R14: 0x555555557d98 --> 0x5555555551a0 (<__do_global_dtors_aux>: endbr64) R15: 0x7ffff7ffd000 --> 0x7ffff7ffe2c0 --> 0x555555554000 --> 0x10102464c457f EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x555555555246 <main>: endbr64 0x55555555524a <main+4>: push rbp 0x55555555524b <main+5>: mov rbp,rsp => 0x55555555524e <main+8>: push rbx 0x55555555524f <main+9>: sub rsp,0xb8 0x555555555256 <main+16>: mov rax,QWORD PTR fs:0x28 0x55555555525f <main+25>: mov QWORD PTR [rbp-0x18],rax 0x555555555263 <main+29>: xor eax,eax [------------------------------------stack-------------------------------------] 0000| 0x7fffffffdd60 --> 0x1 0008| 0x7fffffffdd68 --> 0x7ffff7ded6ca (<__libc_start_call_main+122>: mov edi,eax) 0016| 0x7fffffffdd70 --> 0x0 0024| 0x7fffffffdd78 --> 0x555555555246 (<main>: endbr64) 0032| 0x7fffffffdd80 --> 0x100000000 0040| 0x7fffffffdd88 --> 0x7fffffffde78 --> 0x7fffffffe203 ("/media/sf_Shared/app") 0048| 0x7fffffffdd90 --> 0x7fffffffde78 --> 0x7fffffffe203 ("/media/sf_Shared/app") 0056| 0x7fffffffdd98 --> 0x19653f11ae234a58 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Temporary breakpoint 1, 0x000055555555524e in main () gdb-peda$ disas main Dump of assembler code for function main: 0x0000555555555246 <+0>: endbr64 0x000055555555524a <+4>: push rbp 0x000055555555524b <+5>: mov rbp,rsp => 0x000055555555524e <+8>: push rbx 0x000055555555524f <+9>: sub rsp,0xb8 0x0000555555555256 <+16>: mov rax,QWORD PTR fs:0x28 0x000055555555525f <+25>: mov QWORD PTR [rbp-0x18],rax 0x0000555555555263 <+29>: xor eax,eax 0x0000555555555265 <+31>: lea rax,[rip+0xd98] # 0x555555556004 0x000055555555526c <+38>: mov rdi,rax 0x000055555555526f <+41>: mov eax,0x0 0x0000555555555274 <+46>: call 0x5555555550d0 <printf@plt> 0x0000555555555279 <+51>: lea rax,[rbp-0x90] 0x0000555555555280 <+58>: mov rsi,rax 0x0000555555555283 <+61>: lea rax,[rip+0xd8c] # 0x555555556016 0x000055555555528a <+68>: mov rdi,rax 0x000055555555528d <+71>: mov eax,0x0 0x0000555555555292 <+76>: call 0x5555555550f0 <__isoc99_scanf@plt> 0x0000555555555297 <+81>: lea rax,[rip+0xd7b] # 0x555555556019 0x000055555555529e <+88>: mov rdi,rax 0x00005555555552a1 <+91>: mov eax,0x0 0x00005555555552a6 <+96>: call 0x5555555550d0 <printf@plt> 0x00005555555552ab <+101>: lea rax,[rbp-0x50] 0x00005555555552af <+105>: mov rsi,rax 0x00005555555552b2 <+108>: lea rax,[rip+0xd5d] # 0x555555556016 0x00005555555552b9 <+115>: mov rdi,rax 0x00005555555552bc <+118>: mov eax,0x0 0x00005555555552c1 <+123>: call 0x5555555550f0 <__isoc99_scanf@plt> 0x00005555555552c6 <+128>: mov QWORD PTR [rbp-0xb0],0x0 0x00005555555552d1 <+139>: jmp 0x55555555536a <main+292> 0x00005555555552d6 <+144>: mov eax,0x0 0x00005555555552db <+149>: call 0x55555555521f <next_rand_value> 0x00005555555552e0 <+154>: mov rbx,rax 0x00005555555552e3 <+157>: lea rax,[rbp-0x90] 0x00005555555552ea <+164>: mov rdi,rax 0x00005555555552ed <+167>: call 0x5555555550b0 <strlen@plt> 0x00005555555552f2 <+172>: mov rcx,rax 0x00005555555552f5 <+175>: mov rax,rbx 0x00005555555552f8 <+178>: mov edx,0x0 0x00005555555552fd <+183>: div rcx 0x0000555555555300 <+186>: mov QWORD PTR [rbp-0x98],rdx 0x0000555555555307 <+193>: lea rdx,[rbp-0x90] 0x000055555555530e <+200>: mov rax,QWORD PTR [rbp-0xb0] 0x0000555555555315 <+207>: add rax,rdx 0x0000555555555318 <+210>: movzx eax,BYTE PTR [rax] 0x000055555555531b <+213>: mov BYTE PTR [rbp-0xb1],al 0x0000555555555321 <+219>: lea rdx,[rbp-0x90] 0x0000555555555328 <+226>: mov rax,QWORD PTR [rbp-0x98] 0x000055555555532f <+233>: add rax,rdx 0x0000555555555332 <+236>: movzx eax,BYTE PTR [rax] 0x0000555555555335 <+239>: lea rcx,[rbp-0x90] 0x000055555555533c <+246>: mov rdx,QWORD PTR [rbp-0xb0] 0x0000555555555343 <+253>: add rdx,rcx 0x0000555555555346 <+256>: mov BYTE PTR [rdx],al 0x0000555555555348 <+258>: lea rdx,[rbp-0x90] 0x000055555555534f <+265>: mov rax,QWORD PTR [rbp-0x98] 0x0000555555555356 <+272>: add rdx,rax 0x0000555555555359 <+275>: movzx eax,BYTE PTR [rbp-0xb1] 0x0000555555555360 <+282>: mov BYTE PTR [rdx],al 0x0000555555555362 <+284>: add QWORD PTR [rbp-0xb0],0x1 0x000055555555536a <+292>: lea rax,[rbp-0x90] 0x0000555555555371 <+299>: mov rdi,rax 0x0000555555555374 <+302>: call 0x5555555550b0 <strlen@plt> 0x0000555555555379 <+307>: cmp QWORD PTR [rbp-0xb0],rax 0x0000555555555380 <+314>: jb 0x5555555552d6 <main+144> 0x0000555555555386 <+320>: mov QWORD PTR [rbp-0xa8],0x0 0x0000555555555391 <+331>: jmp 0x555555555467 <main+545> 0x0000555555555396 <+336>: mov rax,QWORD PTR [rbp-0xa8] 0x000055555555539d <+343>: and eax,0x7 0x00005555555553a0 <+346>: mov rdx,rax 0x00005555555553a3 <+349>: lea rax,[rip+0x2c6e] # 0x555555558018 <key> 0x00005555555553aa <+356>: add rax,rdx 0x00005555555553ad <+359>: mov QWORD PTR [rbp-0xa0],rax 0x00005555555553b4 <+366>: lea rdx,[rbp-0x90] 0x00005555555553bb <+373>: mov rax,QWORD PTR [rbp-0xa8] 0x00005555555553c2 <+380>: add rax,rdx 0x00005555555553c5 <+383>: movzx edx,BYTE PTR [rax] 0x00005555555553c8 <+386>: mov rax,QWORD PTR [rbp-0xa0] 0x00005555555553cf <+393>: movzx eax,BYTE PTR [rax] 0x00005555555553d2 <+396>: xor edx,eax 0x00005555555553d4 <+398>: lea rcx,[rbp-0x90] 0x00005555555553db <+405>: mov rax,QWORD PTR [rbp-0xa8] 0x00005555555553e2 <+412>: add rax,rcx 0x00005555555553e5 <+415>: mov BYTE PTR [rax],dl 0x00005555555553e7 <+417>: lea rdx,[rbp-0x90] 0x00005555555553ee <+424>: mov rax,QWORD PTR [rbp-0xa8] 0x00005555555553f5 <+431>: add rax,rdx 0x00005555555553f8 <+434>: movzx edx,BYTE PTR [rax] 0x00005555555553fb <+437>: mov ecx,0x4f 0x0000555555555400 <+442>: mov eax,ecx 0x0000555555555402 <+444>: imul dl 0x0000555555555404 <+446>: shr ax,0x8 0x0000555555555408 <+450>: sar al,0x3 0x000055555555540b <+453>: mov ecx,edx 0x000055555555540d <+455>: sar cl,0x7 0x0000555555555410 <+458>: sub eax,ecx 0x0000555555555412 <+460>: mov ecx,0x1a 0x0000555555555417 <+465>: imul eax,ecx 0x000055555555541a <+468>: mov ecx,eax 0x000055555555541c <+470>: mov eax,edx 0x000055555555541e <+472>: sub eax,ecx 0x0000555555555420 <+474>: lea rcx,[rbp-0x90] 0x0000555555555427 <+481>: mov rdx,QWORD PTR [rbp-0xa8] 0x000055555555542e <+488>: add rdx,rcx 0x0000555555555431 <+491>: mov BYTE PTR [rdx],al 0x0000555555555433 <+493>: lea rdx,[rbp-0x90] 0x000055555555543a <+500>: mov rax,QWORD PTR [rbp-0xa8] 0x0000555555555441 <+507>: add rax,rdx 0x0000555555555444 <+510>: movzx eax,BYTE PTR [rax] 0x0000555555555447 <+513>: add eax,0x61 0x000055555555544a <+516>: mov ecx,eax 0x000055555555544c <+518>: lea rdx,[rbp-0x90] 0x0000555555555453 <+525>: mov rax,QWORD PTR [rbp-0xa8] 0x000055555555545a <+532>: add rax,rdx 0x000055555555545d <+535>: mov BYTE PTR [rax],cl 0x000055555555545f <+537>: add QWORD PTR [rbp-0xa8],0x1 0x0000555555555467 <+545>: lea rax,[rbp-0x90] 0x000055555555546e <+552>: mov rdi,rax 0x0000555555555471 <+555>: call 0x5555555550b0 <strlen@plt> 0x0000555555555476 <+560>: cmp QWORD PTR [rbp-0xa8],rax 0x000055555555547d <+567>: jb 0x555555555396 <main+336> 0x0000555555555483 <+573>: lea rdx,[rbp-0x50] 0x0000555555555487 <+577>: lea rax,[rbp-0x90] 0x000055555555548e <+584>: mov rsi,rdx 0x0000555555555491 <+587>: mov rdi,rax 0x0000555555555494 <+590>: call 0x5555555550e0 <strcmp@plt> 0x0000555555555499 <+595>: test eax,eax 0x000055555555549b <+597>: jne 0x5555555554ae <main+616> 0x000055555555549d <+599>: lea rax,[rip+0xb8b] # 0x55555555602f 0x00005555555554a4 <+606>: mov rdi,rax 0x00005555555554a7 <+609>: call 0x5555555550a0 <puts@plt> 0x00005555555554ac <+614>: jmp 0x5555555554bd <main+631> 0x00005555555554ae <+616>: lea rax,[rip+0xb81] # 0x555555556036 0x00005555555554b5 <+623>: mov rdi,rax 0x00005555555554b8 <+626>: call 0x5555555550a0 <puts@plt> 0x00005555555554bd <+631>: mov eax,0x0 0x00005555555554c2 <+636>: mov rdx,QWORD PTR [rbp-0x18] 0x00005555555554c6 <+640>: sub rdx,QWORD PTR fs:0x28 0x00005555555554cf <+649>: je 0x5555555554d6 <main+656> 0x00005555555554d1 <+651>: call 0x5555555550c0 <__stack_chk_fail@plt> 0x00005555555554d6 <+656>: mov rbx,QWORD PTR [rbp-0x8] 0x00005555555554da <+660>: leave 0x00005555555554db <+661>: ret End of assembler dump. gdb-peda$ b * 0x0000555555555494 Breakpoint 2 at 0x555555555494 gdb-peda$ c Continuing. Enter your name: LosCapitan Enter your password: password!! [----------------------------------registers-----------------------------------] RAX: 0x7fffffffdcd0 ("]^WR\\\\lcTI") RBX: 0x272c8fe355ddd8e8 RCX: 0x149 RDX: 0x7fffffffdd10 ("password!!") RSI: 0x7fffffffdd10 ("password!!") RDI: 0x7fffffffdcd0 ("]^WR\\\\lcTI") RBP: 0x7fffffffdd60 --> 0x1 RSP: 0x7fffffffdca0 --> 0x0 RIP: 0x555555555494 (<main+590>: call 0x5555555550e0 <strcmp@plt>) R8 : 0xb ('\x0b') R9 : 0x7ffff7f99aa0 --> 0xfbad2288 R10: 0x0 R11: 0x7ffff7f9a580 --> 0x7ffff7f96820 --> 0x7ffff7f5d5f7 --> 0x5a5400544d470043 ('C') R12: 0x0 R13: 0x7fffffffde88 --> 0x7fffffffe218 ("CLUTTER_IM_MODULE=xim") R14: 0x555555557d98 --> 0x5555555551a0 (<__do_global_dtors_aux>: endbr64) R15: 0x7ffff7ffd000 --> 0x7ffff7ffe2c0 --> 0x555555554000 --> 0x10102464c457f EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x555555555487 <main+577>: lea rax,[rbp-0x90] 0x55555555548e <main+584>: mov rsi,rdx 0x555555555491 <main+587>: mov rdi,rax => 0x555555555494 <main+590>: call 0x5555555550e0 <strcmp@plt> 0x555555555499 <main+595>: test eax,eax 0x55555555549b <main+597>: jne 0x5555555554ae <main+616> 0x55555555549d <main+599>: lea rax,[rip+0xb8b] # 0x55555555602f 0x5555555554a4 <main+606>: mov rdi,rax Guessed arguments: arg[0]: 0x7fffffffdcd0 ("]^WR\\\\lcTI") arg[1]: 0x7fffffffdd10 ("password!!") arg[2]: 0x7fffffffdd10 ("password!!") [------------------------------------stack-------------------------------------] 0000| 0x7fffffffdca0 --> 0x0 0008| 0x7fffffffdca8 --> 0x6100000000000000 ('') 0016| 0x7fffffffdcb0 --> 0xa ('\n') 0024| 0x7fffffffdcb8 --> 0xa ('\n') 0032| 0x7fffffffdcc0 --> 0x555555558019 --> 0x1337deadbeefc0 0040| 0x7fffffffdcc8 --> 0x2 0048| 0x7fffffffdcd0 ("]^WR\\\\lcTI") 0056| 0x7fffffffdcd8 --> 0x4954 ('TI') [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 2, 0x0000555555555494 in main () gdb-peda$
比較している文字列は以下であることがわかった。
"]^WR\\\\lcTI"
エスケープ文字列を外し、フラグ形式になるようラップする。
gctf{]^WR\\lcTI}
Missing Bits (crypto)
priv.keyは先頭何バイトか削除されている。
秘密鍵の構成は以下のようになっている。
RSAPrivateKey ::= SEQUENCE { version Version, modulus INTEGER, -- n publicExponent INTEGER, -- e privateExponent INTEGER, -- d prime1 INTEGER, -- p prime2 INTEGER, -- q exponent1 INTEGER, -- d mod (p-1) exponent2 INTEGER, -- d mod (q-1) coefficient INTEGER, -- (inverse of q) mod p otherPrimeInfos OtherPrimeInfos OPTIONAL }
priv.keyのわかっている範囲でbase64デコードする。各オフセットの以下の範囲で以下のような値が設定されていることがわかる。
0x001e-0x0020: 0x010001 ← e 0x0025-0x0124: 0x0a9a...6981 ← d 0x0128-0x01a8: 0x00e4...2a21 ← p 0x01ac-0x022c: 0x00f1...69e7 ← q :
このパラメータを元に、RSA暗号の復号を行う。
#!/usr/bin/env python3 from Crypto.Util.number import * from base64 import * with open('ciphertext_message', 'rb') as f: ct = bytes_to_long(f.read()) with open('priv.key', 'r') as f: lines = f.read().splitlines() data = b64decode(''.join(lines[6:-1])) e = int.from_bytes(data[0x001e:0x0021], 'big') d = int.from_bytes(data[0x0025:0x0125], 'big') p = int.from_bytes(data[0x0128:0x01a9], 'big') q = int.from_bytes(data[0x01ac:0x022d], 'big') phi = (p - 1) * (q - 1) assert inverse(e, phi) == d m = pow(ct, d, p * q) filecontent = long_to_bytes(m).decode() print(filecontent)
実行結果は以下の通り。
Hey Bob this is Alice. I want to let you know that the Flag is gctf{7hi5_k3y_can_b3_r3c0ns7ruc7ed}
gctf{7hi5_k3y_can_b3_r3c0ns7ruc7ed}
SLCG (crypto)
暗号化処理の概要は以下の通り。
・encryption = Encryptor() ・encryption.lcgs = (LCG.random_values(), LCG.random_values()) ・ct = encryption.encrypt(FLAG) ・result = [] ・FLAGの各文字のASCIIコードascii_charについて、以下を実行 ・bin_char: ascii_charの2進数のリスト ・bin_charの各bitについて以下を実行 ・next(encryption.lcgs[bit])をresultに追加 ・encryption.lcgs = ( LCG( next(encryption.lcgs[0]), next(encryption.lcgs[0]), next(encryption.lcgs[0]), next(encryption.lcgs[0]) ), LCG( next(encryption.lcgs[1]), next(encryption.lcgs[1]), next(encryption.lcgs[1]), next(encryption.lcgs[1]) ) ) ・ctを出力
フラグが"gctf{"から始まることを前提に考える。
>>> bin(ord('g')) '0b1100111' >>> bin(ord('c')) '0b1100011' >>> bin(ord('t')) '0b1110100' >>> bin(ord('f')) '0b1100110' >>> bin(ord('{')) '0b1111011'
最初のLCGを以下のように置く。
lcgs = (LCG(m0_0, a0_0, c0_0, s0_0), LCG(m1_0, a1_0, c1_0, s1_0))
このとき、以下のようになる。
s1_1 = (s1_0 * a1_0 + c1_0) % m1_0 = ct[0] s1_2 = (s1_1 * a1_0 + c1_0) % m1_0 = ct[1] s0_1 = (s0_0 * a0_0 + c0_0) % m0_0 = ct[2] s0_2 = (s0_1 * a0_0 + c0_0) % m0_0 = ct[3] s1_3 = (s1_2 * a1_0 + c1_0) % m1_0 = ct[4] s1_4 = (s1_3 * a1_0 + c1_0) % m1_0 = ct[5] s1_5 = (s1_4 * a1_0 + c1_0) % m1_0 = ct[6]
例えば"g"の場合などは"1"が5個あり、情報量からLCGの2つ目のみ、パラメータを割り出すことができる。パラメータを割り出したら、計算していき、あてはまる場合は"1"、そうでない場合は"0"にすれば復号できる。
#!/usr/bin/env python3 from Crypto.Util.number import * from functools import reduce with open('ciphertext.txt', 'r') as f: ct = eval(f.read().split(' = ')[1]) flag_head = b'gctf{' bin_flag_head = list(''.join([bin(c)[2:].zfill(7) for c in flag_head])) b0 = bin(flag_head[0])[2:].zfill(7) ct1 = [] for i in range(len(b0)): if b0[i] == '1': ct1.append(ct[i]) delta = [d1 - d0 for (d0, d1) in zip(ct1, ct1[1:])] p_mul = [d0 * d2 - d1 * d1 for (d0, d1, d2) in zip(delta, delta[1:], delta[2:])] m = reduce(GCD, p_mul) a = (delta[1] * inverse(delta[0], m)) % m c = (ct1[1] - a * ct1[0]) % m s = (ct1[0] - c) * inverse(a, m) % m flag = '' for i in range(0, len(ct), 7): s = (s * a + c) % m tmp_ct = ct[i:i+7] bin_char = '' for j in range(7): if tmp_ct[j] == s: bin_char += '1' s = (s * a + c) % m else: bin_char += '0' s_list = [] for j in range(4): s_list.append(s) s = (s * a + c) % m m, a, c, s = s_list flag += chr(int(bin_char, 2)) print(flag)
gctf{th15_lcg_3ncryp710n_w4sn7_s0_5s3cur3_aft3r_4ll}
Glacier Spirit (crypto)
サーバの処理概要は以下の通り。
・key: ランダム16バイト文字列 ・nonce, ct, tag = create_message_and_mac(key, FLAG) ・padded_message = pad_message(FLAG) ・first_block_pad: FLAGの長さを16で割った余り(0の場合は16) ・first_block_padのバイト文字を16-first_block_padの数分連結した文字列 + FLAGを返す。 ・nonce, ct = encrypt(key, padded_message) ・message_blocks: padded_message16バイトごとの配列 ・nonce: ランダム15バイト文字列 ・cts = [] ・message_blocksの各messageについて(インデックス:ctr)、以下を実行 ・cipher_input = nonce + [(ctr+1)の文字列(1バイト)] ・enc = ascon.encrypt(key, cipher_input, b'', b'') ・ct: messageとencのXOR ・ctsにctを追加 ・nonceとctsの連結文字列を返す。 ・tag = mac_creation(key, padded_message) ・message_blocks: padded_message16バイトごとの配列 ・enc_out = b"\x00" * 16 ・message_blocksの各messageについて、以下を実行 ・chaining_values: messageとenc_outのXOR ・enc_out = ascon.encrypt(key, chaining_values, b'', b'') ・enc_outを返す。 ・nonce, ct, tagを返す。 ・nonce, ct, tagを16進数表記で表示 ・8回以下繰り返し ・user_msg: 入力 ・msg: user_msgをhexデコード ・nonce, ct, tag = create_message_and_mac(key, msg) ・nonce, ct, tagを16進数表記で表示
ctは以下のように生成される。
'' --(nonce: nonce + \x01で暗号化)--> CT0 ^ PT0 '' --(nonce: nonce + \x02で暗号化)--> CT1 ^ PT1 '' --(nonce: nonce + \x03で暗号化)--> CT2 ^ PT2
tagは1ブロックの場合以下のように生成される。
'' --(nonce: PT0で暗号化) --> CT0
フラグの暗号化で使われたnonceを使ってメッセージを指定する。
1回目はmessage = nonce + '01'を指定し、そのタグとフラグの暗号化の1ブロック目をXORすれば1ブロック目を復号できる。
2回目以降同様にして2ブロック目以降を復号し、結合すればパディングしたフラグが得られ、フラグがわかる。
#!/usr/bin/env python3 import socket BLOCK_SIZE = 16 def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) def xor(a, b): return bytes([x ^ y for x, y in zip(a, b)]) def unpad_message(message): first_block_pad = message[0] assert message[:BLOCK_SIZE - first_block_pad] == bytes([first_block_pad]) * (BLOCK_SIZE - first_block_pad) return message[BLOCK_SIZE - first_block_pad:] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('chall.glacierctf.com', 13379)) data = recvuntil(s, b'glacier!\n').rstrip() print(data) nonce = data.splitlines()[13].split(', ')[0] ct = bytes.fromhex(data.splitlines()[13].split(', ')[1]) data = recvuntil(s, b'\n').rstrip() print(data) flag = b'' for i in range(len(ct) // BLOCK_SIZE): data = recvuntil(s, b':\n').rstrip() print(data) message = nonce + str(i + 1).zfill(2) print(message) s.sendall(message.encode() + b'\n') for _ in range(3): data = recvuntil(s, b'\n').rstrip() print(data) tag = bytes.fromhex(data.split(', ')[2]) flag += xor(ct[i*BLOCK_SIZE:(i+1)*BLOCK_SIZE], tag) print() flag = unpad_message(flag).decode() print(flag)
実行結果は以下の通り。
Glacier Spirit , /\.__ _.-\ /~\, __ /~ \ ./ \ ,/ /_\ _/ \ ,/~,_.~''\ /_\_ /'\ / \ /## \ / V#\/\ /~8# # ## V8 #\/8 8\ /~#'#'#''##V&#&# ##\/88#'#8# #' #\#&'##' ##\ j# ##### #'#\&&'####/###& #'#&## #&' #'#&#'#'\ /#'#'#####'###'\&##'/&#'####'### # #&#&##'#'### \ J#'###'#'#'#'####'\# #'##'#'##'#'#####&'## '#'&'##|\ The spirit of the glacier gifts you a flag! ce83fc02c986095dde690e9d842770, f922f14cbdbd3cf6fede7188c58594b6d07b24a29017f77cad54c46677c099c852b396bea4c0a5e30d1be5a11d56162c, 263866a764190098d4d2a13846c1ae29 Now you can bring forth your own messages to be blessed by the spirit of the glacier! Offer your message: ce83fc02c986095dde690e9d84277001 The spirit of the glacier has blessed your message! ec75573858082f6c7f9e8cb27d7b52, 86d38c2f74596dfd72ef42dbc74d3f8c, f6459238dbc67fa28c813cb8a1b6cbd5 Offer your message: ce83fc02c986095dde690e9d84277002 The spirit of the glacier has blessed your message! 656e8802cd862e066069db9a01f1a1, 84a67a9d9d5d811d9616fc6b5d048b31, b2187befa454a83dfe178b282884fc8e Offer your message: ce83fc02c986095dde690e9d84277003 The spirit of the glacier has blessed your message! 5a647b14be84a935ff6ddfea71f269, 7bb04770e826c9a3d3e2e7e81db179db, 61f2c29afb94edd0523f95906f1f4251 gctf{CTr_M0d3_cbc_M4C_ASCON_DeF3AT$_TH3_$p1rIT}
gctf{CTr_M0d3_cbc_M4C_ASCON_DeF3AT$_TH3_$p1rIT}