aszx87410/ctf-writeups

H@cktivityCon 2021 CTF - Words Church

aszx87410 opened this issue · 0 comments

Description

Tired of finding bugs and exploiting vulnerabilities? Want a classic brain buster instead? Why not play a wordsearch -- in fact, why not play thirty word searches!!

截圖 2021-09-20 上午11 08 32

Writeup

Nothing special, just parse strings and find the answer. The only problem is I am not familiar with the rules, I found that the coordinate can be a negative number. I thought it's a bug but it turns out it's valid.

var NetcatClient = require('node-netcat').client;
var client = NetcatClient(32332, 'challenge.ctf.games');
  
client.on('open', function () {
  console.log('connect');
});

let stage = 'before_start'
let board = []
let problem = null
let buffer = []
let timer = null

// x, y
let dir = [
  [-1, 1],
  [0, 1],
  [1, 1],
  [-1, -1],
  [-1, 0],
  [0, -1],
  [1, -1],
  [1, 0],
]
function isAns(board, x, y, problem) {
  if (board[y][x] !== problem[0]) return null
  if (problem.length === 1) {
    return `[(${x},${y})]`
  }

  let steps = []
  let isFound = false
  for(let d of dir) {
    let nowX = x
    let nowY = y
    let stepX = x
    let stepY = y
    let count = 1
    steps.push([x,y])
    
    while(true) {
      nowX += d[0];stepX += d[0]
      nowY += d[1];stepY += d[1]
      if (nowX === -1) { nowX = 15 }
      if (nowX === 16) { nowX = 0 }
      if (nowY === -1) { nowY = 15 }
      if (nowY === 16) { nowY = 0 }

      if (board[nowY] && board[nowY][nowX] === problem[count]) {
        count++
        steps.push([stepX,stepY])
        if (count === problem.length) {
          isFound = true
          break
        }
      } else {
        break
      }
    }

    if (isFound) {
      break
    } else {
      steps = []
    }
  }

  if (!isFound) {
    return null
  }
  console.log('found ans!')
  const aaa = '[' + steps.map(arr => `(${arr[0]}, ${arr[1]})`).join(', ') + ']'
  console.log(aaa)
  return aaa
}

function findAns() {
  for(let y=0; y<board.length; y++) {
    for(let x=0; x<board[y].length; x++) {
      if (board[y][x] !== problem[0]){
        continue
      }

      //console.log('log:', x, y)
      let result = isAns(board, x, y, problem)
      if (result) {
        return result
      }
    }
  }
}

function parseBoard() {
  board = board.filter(row => row !== '')
  const lastIndex = board.findIndex(row => row.includes('---') && row.length < 10)
  board = board.slice(2, lastIndex)
  board = board.map(row => {
    let r = row.replace(/\s/g, '').split('|')[1]
    return r
  })
}

function handler() {
  if (stage === 'before_start' && buffer.includes('> ')) {
    stage = 'receiving_board'
    client.send('play\n')
    buffer = []
    return
  }

  if (stage === 'receiving_board') {
    stage = 'receiving_problem' 
    board = []
    let index = buffer.findIndex(line => line.includes(': X'))
    for(let i=index; i<buffer.length; i++) {
      board.push(buffer[i])
    }
    parseBoard()
    console.log('[log] board:')
    console.log(board)

    let p = buffer[buffer.length - 1]
    problem = p.replace(/[:> \n\t]/g, '')
    console.log('[log] problem:', problem, problem.length)
    client.send(findAns() + "\n")
    buffer = []
    return
  }

  if (stage === 'receiving_problem') {
    if (buffer.find(l => l.includes('Onto the'))) {
      console.log('[log] next level')
      stage = 'receiving_board'
      handler()
      return
    }
    problem = buffer.join('').replace(/[:> \n\t]/g, '')
    console.log('[log] problem:', problem, problem.length)
    client.send(findAns() + "\n")
    buffer = []
    return
  }

}

client.on('data', function (data) {
  let str = data.toString('ascii')
  let lines = str.split('\n')
  console.log(str)

  buffer.push(...lines)
  clearTimeout(timer)
  timer = null
  timer = setTimeout(handler, 1000)
});

client.on('error', function (err) {
  console.log(err);
});

client.on('close', function () {
  console.log('close');
});

client.start();