BreizhCTF 2019: Tous les chemins mènent au flag
Challenge details
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
BreizhCTF 2019 | Tous les chemins mènent au flag | Prog | 150 | ??? |
TL;DR
We had to win 500 game of “TicTacToe” playing with a bot. I wrote a python script but some teams managed to beat the bot by themself !
Methodology
First game
To understand the challenge I decided to run a netcat on the given ip/port.
nc ctf.bzh 42000
Turn number 1
Where would you like to place S (1-9):1
Humans: 0 Machines: 0
The board look like this:
S | |
================
| |
================
| |
Turn number 2
Humans: 0 Machines: 0
The board look like this:
S | |
================
K | |
================
| |
Turn number 3
Where would you like to place S (1-9):
[SNIP]
Where would you like to place S (1-9):3
Humans: 4 Machines: 0
The board look like this:
S | S | S
================
| K |
================
| | K
Turn number 6
Humans: 4 Machines: 0
The board look like this:
S | S | S
================
| K | K
================
| | K
HUMANS WIN!
Humans: 5 Machines: 0
The board look like this:
| |
================
| |
================
| |
Turn number 1
Where would you like to place S (1-9):
[SNIP]
Scripting
There were 2 problems to solve. The first one was the parsing of the game and I decided to use pwn module for this. The second problem was the algorithm to choose the best movement, and I decided to use TicTacToe Master which implement Minimax algorithm. (Note, I’ve been looking for “Best Move TicTacToe python” on google to find the script).
I had to fix part of the given script due to the implementation with “S” and “K” in our game instead of “X” and “O” in the script. Here is the modified script (md5sum : dcfe7ef172cc3a708f968a9c830d9708)
And finaly here is my script using the getAIMove
function of TicTacToe Master:
import TicTacToeMaster as ttt
from pwn import *
def getBestMove(board):
return int(ttt.getAIMove(board, "S", "S")[0])
def extractMatrice(s): # Convert board with ====|==== to list [1,2,3,4,5,6,7,8,9]
s = s.split("\n")
l1 = s[2].strip().replace(" ","").split("|")
l2 = s[4].strip().replace(" ","").split("|")
l3 = s[6].strip().replace(" ","").split("|")
return l1+l2+l3
HOST = "ctf.bzh"
PORT = 42000
r = remote(HOST, PORT)
def solveGame():
bestMove = "1"
while 1:
rec = r.recvuntil("(1-9)? ") # Do the first movement
print("[PLAY] "+bestMove)
r.sendline(bestMove)
r.recvuntil("The board look like this:") # player
x = r.recvuntil("The board look like this:") # bot
if "HUMANS WIN!" in x:
print(x)
return
rec = r.recvuntil("Turn number")
#print(rec)
m = extractMatrice(rec)
#print(m)
bestMove = str(getBestMove(m)+1) # +1 due to list index
for i in range(499):
solveGame()
r.interactive()
Once run, the script stop at the last game and let us play the final game 8).
Flag
breizhctf{???}