ʕ·ᴥ·ʔ






Tunnels

06/10/2022

By: HELLOPERSON

Tags: misc HSCTF-2022

Problem Description:

Catch b40m1k3


Notice how we can represent this problem using numbers. For each of the middle 6 numbers, the value of it can be split between the 2 values next to it on the next round, but for the edges, all of it goes to the one next to it, because it has 1 neighbor. Let’s write some code to simulate the problem:

start = [1, 1, 1, 1, 1, 1, 1, 1]
nex = [1, 1, 1, 1, 1, 1, 1, 1]
a = [1, 1, 2, 3, 4, 5, 6, 6]
for j in range(8):
  start[a[j]] = 0
  sum = 0
  for i in range(8):
    if i == 0:
      nex[0] = start[1]/2
    elif i == 7:
      nex[7] = start[6]/2
    elif i == 1:
      nex[1] = start[0] + start[2]/2
    elif i == 6:
      nex[6] = start[7] + start[5]/2
    else:
      nex[i] = start[i-1]/2 + start[i+1]/2
    sum += nex[i]
  print(nex)
  print(sum)
  for i in range(8):
      start[i] = nex[i]
print(200*(1-(sum/8)))

Cool! Now that we have code to simulate it, and is pretty fast, let’s bash all possible meaningful inputs (half of the inputs are equivalent). This gives us 4*8^7 possibilities to bash.

start = [1, 1, 1, 1, 1, 1, 1, 1]
nex = [1, 1, 1, 1, 1, 1, 1, 1]
old = 0
for i in range(4):
    for j in range(8):
        for k in range(8):
            for l in range(8):
                for m in range(8):
                    for n in range(8):
                        for o in range(8):
                            for p in range(8):
                                start = [1, 1, 1, 1, 1, 1, 1, 1]
                                nex = [1, 1, 1, 1, 1, 1, 1, 1]
                                a = [i, j, k, l, m, n, o, p]
                                for q in range(8):
                                  start[a[q]] = 0
                                  sum = 0
                                  for r in range(8):
                                    if r == 0:
                                      nex[0] = start[1]/2
                                    elif r == 7:
                                      nex[7] = start[6]/2
                                    elif r == 1:
                                      nex[1] = start[0] + start[2]/2
                                    elif r == 6:
                                      nex[6] = start[7] + start[5]/2
                                    else:
                                      nex[r] = start[r-1]/2 + start[r+1]/2
                                    sum += nex[r]
                                  for s in range(8):
                                      start[s] = nex[s]
                                c = (200*(1-(sum/8)))
                                if c > old:
                                    print(a)
                                    print(c)
                                    old = c
                                c = 0

After a few minutes, the program spits out [3, 6, 1, 4, 4, 1, 6, 3], with an average value of 179.6875. This appears to be the optimal solution.

Plugging it into some pwntools code, we can wait for the ~2.5% chance that we will succeed.

from pwn import *

io = remote("tunnels.hsctf.com", 1337)
io.recvline()
success = 0
guesses = input() # input guess sequence e.g. "12345678"
for j in range(200):
    io.recvline()
    print("TRIAL: %d" % j)
    for i in range(8):
        io.sendline(guesses[i].encode())
        r = io.recvline()
        if b"incorrect" not in r:
            success += 1
            break

print("success rate: " + str(success/200))
print(io.recv())

After a few minutes of running this in a loop, we find the flag in the console: flag{b4om1k3_15_4_v3ry_1nt3r35t1ng_p3r50n_924972020}