OverTheWire Advent Bonanza 2021 Writeup

この大会は2021/12/7 21:00(JST)~2021/12/19 21:00(JST)に開催されました。
今回もチームで参戦。結果は361点で103チーム中59位でした。
自分で解けた問題をWriteupとして書いておきます。

Grinch's Game (misc)

サーバの処理概要は以下の通り。

・r = random.Random(secrets.randbits(20))
・my_number: 100未満のランダム整数
・numbers_to_guess = 100
・lives_remaining = 20
・以下繰り返し
 ・answer: 整数入力
 ・answerとmy_numberが一致している場合
  ・numbers_to_guess: 1減算
  ・my_number: 100未満のランダム整数
 ・answerがmy_numberより小さい場合
  ・"Too low..."と表示
  ・lives_remaining: 1減算
 ・answerがmy_numberより大きい場合
  ・"Too high..."と表示
  ・lives_remaining: 1減算
 ・lives_remainingが0の場合、終了
 ・numbers_to_guessが0の場合、フラグを表示

secrets.randbits(20)の部分(=secretとする)が20bitランダム整数で、これをブルートフォースして求める。このとき、secretを特定するのに必要なランダム整数の数は4つ。失敗回数が20のため、失敗する可能性があるが、成功するまで実行して4つの整数が入手できたら、次以降の整数を割り出すことができる。

#!/usr/bin/env python3
import socket
import random

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(('grinchgame.advent2021.overthewire.org', 1217))

data = recvuntil(s, b'...\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)

nums = []
for _ in range(4):
    g = [0, 99]
    while True:
        data = recvuntil(s, b'\n').rstrip()
        print(data)
        ans = (g[0] + g[1]) // 2
        print(ans)
        s.sendall(str(ans).encode() + b'\n')
        data = recvuntil(s, b'\n').rstrip()
        print(data)
        if data == 'Correct!':
            nums.append(ans)
            break
        elif data == 'Too low...':
            g[0] = ans
        else:
            g[1] = ans

for secret in range(2**20):
    r = random.Random(secret)
    found = True
    for i in range(4):
        my_number = r.randrange(100)
        if my_number != nums[i]:
            found = False
            break
    if found:
        break

for _ in range(96):
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    ans = r.randrange(100)
    print(ans)
    s.sendall(str(ans).encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)

data = recvuntil(s, b'\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)

成功したときの実行結果は以下の通り。

SYSTEM INFO:
CPython 3.10.1 (main, Dec  8 2021, 03:30:49) [GCC 10.2.1 20210110] on linux

Are you feeling lucky? Let's play a game...

[round 1/100] Guess my number:
49
Too low...
[round 1/100] Guess my number:
74
Too high...
[round 1/100] Guess my number:
61
Too high...
[round 1/100] Guess my number:
55
Correct!
[round 2/100] Guess my number:
49
Too low...
[round 2/100] Guess my number:
74
Too high...
[round 2/100] Guess my number:
61
Too low...
[round 2/100] Guess my number:
67
Too high...
[round 2/100] Guess my number:
64
Too low...
[round 2/100] Guess my number:
65
Correct!
[round 3/100] Guess my number:
49
Too low...
[round 3/100] Guess my number:
74
Too high...
[round 3/100] Guess my number:
61
Too low...
[round 3/100] Guess my number:
67
Too high...
[round 3/100] Guess my number:
64
Too high...
[round 3/100] Guess my number:
62
Correct!
[round 4/100] Guess my number:
49
Too low...
[round 4/100] Guess my number:
74
Too high...
[round 4/100] Guess my number:
61
Too high...
[round 4/100] Guess my number:
55
Too high...
[round 4/100] Guess my number:
52
Too low...
[round 4/100] Guess my number:
53
Too low...
[round 4/100] Guess my number:
54
Correct!
[round 5/100] Guess my number:
68
Correct!
[round 6/100] Guess my number:
20
Correct!
[round 7/100] Guess my number:
42
Correct!
[round 8/100] Guess my number:
28
Correct!
[round 9/100] Guess my number:
85
Correct!
[round 10/100] Guess my number:
58
Correct!
        :
        :
[round 91/100] Guess my number:
71
Correct!
[round 92/100] Guess my number:
95
Correct!
[round 93/100] Guess my number:
74
Correct!
[round 94/100] Guess my number:
73
Correct!
[round 95/100] Guess my number:
71
Correct!
[round 96/100] Guess my number:
94
Correct!
[round 97/100] Guess my number:
33
Correct!
[round 98/100] Guess my number:
60
Correct!
[round 99/100] Guess my number:
18
Correct!
[round 100/100] Guess my number:
41
Correct!
YOU WIN! How are you so lucky!?!??
AOTW{wh3n_th3_0nly_w1nn1n6_m0ve_15_n0t_2_p14y}
AOTW{wh3n_th3_0nly_w1nn1n6_m0ve_15_n0t_2_p14y}