Wani CTF 2023 | guess

#wani_ctf_2023

import os
import random

ANSWER = list(range(10**4))
random.shuffle(ANSWER)
CHANCE = 15


def peep():
    global CHANCE
    if CHANCE <= 0:
        print("You ran out of CHANCE. Bye!")
        exit(1)
    CHANCE -= 1

    index = map(int, input("Index (space-separated)> ").split(" "))
    result = [ANSWER[i] for i in index]
    random.shuffle(result)

    return result


def guess():
    guess = input("Guess the numbers> ").split(" ")
    guess = list(map(int, guess))
    if guess == ANSWER:
        flag = os.getenv("FLAG", "FAKE{REDACTED}")
        print(flag)
    else:
        print("Incorrect")


def main():
    menu = """
    1: peep
    2: guess""".strip()
    while True:
        choice = int(input("> "))
        if choice == 1:
            result = peep()
            print(result)
        elif choice == 2:
            guess()
        else:
            print("Invalid choice")
            break
main()

数あてゲーム

10000までの数字が一つずつあって、シャッフルされた配列を15回のクエリで求める。

クエリは「添字iの値」を取得できるやつだがシャッフルされて返ってくるので素直には解けない。

とはいえ重複が許可されるので0 1 1 とかを送って333 999 333 だったらARRAY[0] = 999 みたいな感じで解ける

重複が許されない場合も添字の下から1bitずつ求めるみたいなことができるらしい → https://qiita.com/kusano_k/items/b63cc22c38cbf172f79d#guess-normal

from ptrlib import Socket, Process
from collections import Counter
import ast

ans = []
sock = Socket("nc guess-mis.wanictf.org 50018")
# sock = Socket("localhost", 9999)

for i in range(10):
    sock.sendlineafter("> ", "1")

    query = []
    for j in range(1000):
        query.append(" ".join([str(1000*i + j) for _ in range(j+1)]))

    sock.sendlineafter("> ", " ".join(query))
    xs = ast.literal_eval(sock.recvline().decode())
    ans.extend([v[0] for v in Counter(xs).most_common()][::-1])
    print(len(ans))
sock.sendlineafter("> ", "2")
sock.sendlineafter("> ", " ".join(str(a) for a in ans))
sock.interactive()

カテゴリ一覧