Daily AlpacaHack Week6 (2026-1-5 ~ 2026-1-11)
Daily AlpacaHack の Writeup.
(2026/1/5 - 2026/1/11)
後から解いたものなど含むまとめ.
Encoding Basics (Misc, Crypto, 2026/1/5)
- バイト列, 16 進数, Base64 でフラグの断片がエンコードされている
- python で逆処理を掛けるとフラグ獲得できる
from Crypto.Util.number import * import base64 with open("chall.txt", "r") as f: long_val, hex_val, base_val = f.readlines() flag1 = long_to_bytes(int(long_val.split()[-1].strip())) hex_str = hex_val.split()[-1].strip().strip('"') flag2 = bytes.fromhex(hex_val.split()[-1].strip().strip('"')) flag3 = base64.b64decode(base_val.split()[-1].strip().strip('"')) print((flag1+flag2+flag3).decode(errors="replace"))
jailiaj (Misc, 2026/1/6)
- 渡された入力が対称になっている場合にのみ
evalで実行するプログラム - 入力はすべて文字列で受け取るため python のコメントアウト "#" を用いることでフラグを読み込むスクリプトを流し込める
eval_str = 'print(open("flag.txt").read())' out_str = eval_str + "#" + eval_str[::-1] print(out_str) print(out_str[::-1])
Square RSA (Crypto, 2026/1/7)
- RSA 暗号の素数 $p, q$ が同じになっている
- 素因数分解がただの平方根の計算となるため, 復号鍵は以下で算出可能
$$d \equiv e^{-1} \mod (p-1)p$$
- 復号は以下となる
$$(m^e)^d \equiv m^{ed} \equiv m^{1+kp(p-1)} \mod p^2$$
- $k$ は整数であり, $\varphi(p^2) = p(p-1)$ よりオイラーの定理で以下が成立
$$m^{p(p-1)} \equiv 1 \mod p^2$$
- よって復号が成立する
import math from Crypto.Util.number import * with open("output.txt", "r") as f: n, c = [int(x.split()[-1].strip()) for x in f.readlines()] e = 65537 p = math.isqrt(n) d = inverse(e, (p-1)*p) m = pow(c, d, n) print(long_to_bytes(m))
secret-table (Web, 2026/1/8)
- 典型的な SQL Injection が可能な web アプリケーション
- フラグは "secret" というテーブルにあるが, 入力文字列に "secret" という文字列があるとブロックされる
- SQLite3 ではテーブル名の大文字小文字が判別されないので, 大文字を使えばフラグ獲得 (
username, passwordが表示されるためNULLで 1 列分確保する)
' UNION SELECT *, NULL FROM SECRET WHERE '1' = '1
SwapSwap (Misc, 2026/1/9)
- python の
swapcaseを 2 回かけたときに元の入力と別になればフラグ獲得 - 公式ドキュメント に
swapcaseを 2 回かけても同じものに戻るとは限らないと書いてある (bytes型のプロパティの方では保証されている) - unicode がらみでそういう文字があるらしく, そのうちの一つである
ßを入力してフラグ獲得 - 以下が実験用コード
>>> "ß".swapcase().swapcase() 'ss'
RSA2026 (Crypto, 2026/1/10)
- $2$ から $2026$ までの範囲における素数から 2026 個選択したものの積で法となる $n$ を指定した RSA 暗号
- $n$ の対象が絞れるため素因数分解が可能
$$n = p_1^{k_1}p_2^{k_2} \dots$$
- 異なる素数は当然互いに素であるため, オイラー関数は次で計算される
$$\varphi(n) = \varphi(p_1^{k_1})\varphi(p_2^{k_2}) \dots = p_1^{k_1-1}(p_1-1)p_2^{k_2-1}(p_2-1) \dots$$
- オイラー関数における $e$ の逆元が復号鍵となるためフラグ獲得
from Crypto.Util.number import * import sys import math sys.set_int_max_str_digits(20 << 26) with open("output.txt", "r") as f: n, e, c = [int(x.split()[-1].strip()) for x in f.readlines()] e = 65537 all_primes = [x for x in range(2026) if isPrime(x)] prime_parts = [] exponents = [] for pr in all_primes: if n % pr == 0: prime_parts.append(pr) exp_itr = 0 n_cp = n while True: if n_cp % pr == 0: exp_itr += 1 n_cp = n_cp // pr else: break exponents.append(exp_itr) n2 = 1 for i in range(len(prime_parts)): n2 *= pow(prime_parts[i], exponents[i]) euler_func = 1 for i in range(len(prime_parts)): euler_func *= pow(prime_parts[i], exponents[i]-1)*(prime_parts[i] - 1) d = inverse(e, euler_func) m = pow(c, d, n) print(long_to_bytes(m))
crazython (Rev, 2026/1/11)
- バイナリ化されたコードを
execで実行している - どのようなコードになっているかを調べたいが, vscode で編集するとバイト列が壊れるらしくうまく動作しなくなる
test.binというファイルを作成しviを用いて編集しコードを表示するようexecの代わりに以下を追加する
code_bytes = zlib.decompress(b) print(code_bytes)
- 上記で作成したファイルを
pythonコマンドで実行したところ, フラグの各文字のハッシュ値が保存されており 1 文字ずつ比較されていた - ハッシュ値を出力結果からコピペし文字列の総当たりで解読しフラグ獲得
import hashlib import string flag_hash = r"[\'e3b98a4da31a127d4bde6e43033f66ba274cab0eb7eb1c70ec41402bf6273dd8\', \'aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123\', \'de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7\', \'043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'e3b98a4da31a127d4bde6e43033f66ba274cab0eb7eb1c70ec41402bf6273dd8\', \'3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea\', \'2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6\', \'aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7\', \'043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'0bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6\', \'043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89\', \'3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea\', \'18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a1\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'acac86c0e609ca906f632b0e2dacccb2b77d22b0621f20ebece1a4835b93f6f0\', \'252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111\', \'de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7\', \'1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9\', \'cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb\', \'e3b98a4da31a127d4bde6e43033f66ba274cab0eb7eb1c70ec41402bf6273dd8\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'e3b98a4da31a127d4bde6e43033f66ba274cab0eb7eb1c70ec41402bf6273dd8\', \'aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123\', \'3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29\', \'acac86c0e609ca906f632b0e2dacccb2b77d22b0621f20ebece1a4835b93f6f0\', \'3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4\', \'3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'acac86c0e609ca906f632b0e2dacccb2b77d22b0621f20ebece1a4835b93f6f0\', \'252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111\', \'d2e2adf7177b7a8afddbc12d1634cf23ea1a71020f6a1308070a16400fb68fde\', \'2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6\', \'aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123\', \'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb\', \'62c66a7a5dd70c3146618063c344e531e6d4b59e379808443ce962b3abd63c5a\', \'148de9c5a7a44d19e56cd9ae1a554bf67847afb0c58f6e12fa29ac7ddfca9940\', \'de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7\', \'65c74c15a686187bb6bbf9958f494fc6b80068034a659a9ad44991b08c58f2d2\', \'1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9\', \'043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89\', \'aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123\', \'de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7\', \'148de9c5a7a44d19e56cd9ae1a554bf67847afb0c58f6e12fa29ac7ddfca9940\']" flag_hash_list = [x.strip().replace("\\", "").strip("'") for x in flag_hash.strip("[").strip("]").split(",")] flag = "" for hash_val in flag_hash_list: hit_flag = 0 for tmp_str in string.printable: if hashlib.sha256(tmp_str.encode()).hexdigest() == hash_val: hit_flag += 1 flag += tmp_str print("hit:", flag) break if hit_flag == 0: print("no hit...") print(hash_val) exit() print("flag", flag)