この大会は2022/4/23 9:00(JST)~2022/4/25 9:00(JST)に開催されました。
今回もチームで参戦。結果は1020点で653チーム中45位でした。
自分で解けた問題をWriteupとして書いておきます。
sanity_check (misc)
Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。
bctf{b01ler_up_4nd_h4mm3r_d0wn_h4ck3r}
crackme (rev)
Ghidraでデコンパイルする。
bool main(void) { int iVar1; char local_48 [60]; undefined4 local_c; local_c = 0; printf("Product Key> "); fgets(local_48,0x2f,stdin); iVar1 = check(local_48); if (iVar1 == 0) { printf("Key incorrect, not activating.\n"); } else { printf("Key correct, activating.\n"); } return iVar1 == 0; } undefined4 check(char *param_1) { undefined4 local_c; if (*param_1 == 'b') { if (param_1[1] == 'c') { if (param_1[2] == 't') { if (param_1[3] == 'f') { if (param_1[4] == '{') { if (param_1[5] == '1') { if (param_1[6] == '3') { if (param_1[7] == '3') { if (param_1[8] == '&') { if (param_1[9] == '_') { if (param_1[10] == 'l') { if (param_1[0xb] == 'e') { if (param_1[0xc] == 't') { if (param_1[0xd] == 'm') { if (param_1[0xe] == 'e') { if (param_1[0xf] == 'i') { if (param_1[0x10] == 'n') { if (param_1[0x11] == '_') { if (param_1[0x12] == '1') { if (param_1[0x13] == '2') { if (param_1[0x14] == '3') { if (param_1[0x15] == '}') { local_c = 1; } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } } else { local_c = 0; } return local_c; }
1文字ずつチェックしているのがわかるので、それを連結する。
bctf{133&_letmein_123}
crackme_2 (rev)
Ghidraでデコンパイルする。
bool main(void) { int iVar1; long in_FS_OFFSET; char local_48 [56]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); printf("Product key> "); fgets(local_48,0x2f,stdin); iVar1 = check(local_48); if (iVar1 == 0) { puts("Key incorrect, not activating."); } else { puts("Key correct, activating."); } if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return iVar1 == 0; } char check(char *param_1) { char cVar1; if ((((*param_1 == 'b') && (param_1[1] == 'c')) && (param_1[2] == 't')) && ((param_1[3] == 'f' && (param_1[4] == '{')))) { if (param_1[5] == '4') { if (param_1[6] == 'l') { if (param_1[7] == 'g') { if (param_1[8] == '3') { if (param_1[9] == 'b') { if ((byte)(param_1[10] ^ param_1[9]) == 0x10) { if (param_1[0xb] + -1 == (int)param_1[8]) { if (param_1[0xc] == '!') { cVar1 = param_1[0xd]; if (cVar1 != '}') { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } } else { cVar1 = '\0'; } return cVar1; }
条件を満たすよう、簡単な計算で入力文字を算出できる。
#!/usr/bin/env python3 flag = list(b'bctf{4lg3b') + [b''] * 4 flag[10] = flag[9] ^ 0x10 flag[0xb] = flag[8] + 1 flag[0xc] = ord('!') flag[0xd] = ord('}') flag = ''.join([chr(c) for c in flag]) print(flag)
bctf{4lg3br4!}
Hardcore (crypto)
サーバの処理概要は以下の通り。
・diff: 難易度選択(1 or 2) ・diff == 1の場合 ・FLAG = FLAG1 ・Level(1) ・diff == 2の場合 ・FLAG = FLAG2 ・Level(0.9) ■Level(probability) ・encrypted_secret: FLAGのsha256 ・encrypted_secret表示 ・以下繰り返し ・array = parse_input() ・bitstring: 2進数文字列入力 ・array: bitstringをnumpy配列に変換→返却 ・predictor(array, probability = probability)の結果を表示 ・x_r: FLAGの2進数表記と異なるビットはTrueとなっている配列 ・np.random.seed(x_r) ・chance = np.random.rand() ・prediction = 0 ・chanceがprobability以下の場合 ・prediction = generate_hardcore(digest_to_array(FLAG), r) ・chanceがprobabilityより大きい場合 ・prediction = 1 - generate_hardcore(digest_to_array(FLAG), r) ・predictionを返却
難易度1の方を解く必要がある。generate_hardcore関数はFLAGのbit配列と、指定したbit配列の内積を算出し、その和の2で割った余りを返す。1ビットずつ0の場合と1の場合を指定し、返却値が変わらなければ0、変化したら1であるとわかる。このことから1ビットずつ割り出すスクリプトにし、フラグを求める。
#!/usr/bin/env python3 import socket 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(('ctf.b01lers.com', 9003)) data = recvuntil(s, b':') print(data + '1') s.sendall(b'1\n') data = recvuntil(s, b'\n').rstrip() print(data) data = recvuntil(s, b'\n').rstrip() print(data) b_flag = '' for i in range(256): b_tmp = b_flag + '0' + '0' * (255 - i) print(b_tmp) s.sendall(b_tmp.encode() + b'\n') hc0 = recvuntil(s, b'\n').rstrip() print(hc0) b_tmp = b_flag + '1' + '0' * (255 - i) print(b_tmp) s.sendall(b_tmp.encode() + b'\n') hc1 = recvuntil(s, b'\n').rstrip() print(hc1) if hc0 == hc1: b_flag += '0' else: b_flag += '1' flag = '' for i in range(0, len(b_flag), 8): flag += chr(int(b_flag[i:i+8], 2)) print(flag)
実行結果は以下の通り。
Select a difficulty (1/2):1 We're looking to find the secret behind this SHA1 hash <d578448067f47a44e1d97974492a07ca4b3f230ae70bb0f9129bb8d62d197703>. Luckily for you, this socket takes a bitstring and predicts the dot product of the secret with that bit string (mod 2) with 100% accuracy and sends you back the answer. 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0 : : 0110001001100011011101000110011001111011011001000110111101011111011110010110111101110101010111110110110001101001011010110110010101011111011010000110000101110010011001000110001101101111011100100110010101011111011000110110100001100001011011000111001101111100 0 0110001001100011011101000110011001111011011001000110111101011111011110010110111101110101010111110110110001101001011010110110010101011111011010000110000101110010011001000110001101101111011100100110010101011111011000110110100001100001011011000111001101111101 1 bctf{do_you_like_hardcore_chals}
bctf{do_you_like_hardcore_chals}