Monday, September 23, 2013

CSAW CTF Quals: Misc 300

This challenge was purely a scripting challenge.

When contacted the server would respond with a box made of #’s with a random arrangement of *’s in them and how many generations to go forward. Luckily, the team was familiar with Conway's Game of Life and so the challenge was able to be solved early. If you were not familiar with it then they later gave a hint about what it was.

Anyway, using the rules of the game of Life, we simply assumed that the stars represented alive pixels and the blanks represented dead pixels. From there we made a simple python program to scan the server response, go forward the stated number of generations, and then send back the resulting box. The trick was to make sure the box could be any size.

Here is the python script we used to solve the challenge. After 100 puzzle solves it gave you the key. :)

Example:
##### Round 1: 29 Generations #####
####################
#               *  #
#         *  *  *  #
#**  *    *     *  #
# * *      *       #
#*  **    *        #
#*    *            #
#                  #
#                  #
#           **     #
#     *    **      #
#    *     *       #
#     * * *        #
#       *          #
#           *  *   #
#          *  **   #
#         *     ** #
#     *     *  *** #
#  *      * *      #
#   *  *       *   #
#       *      *  *#
####################

Here is the python script we used:
def lifebot((HOST,port)):
 sock = socket.socket()
 sock.connect((HOST, port))
 p = fdpexpect.fdspawn(sock)
 p.logfile = sys.stdout
 #100 rounds to win...
 for rounds in range(100):
  #parse server response
  p.expect("#####")
  p.expect('Round ')
  p.expect(': ')
  p.expect(' Generations')
  numgen = int(p.before)
  p.expect("#####\n")
  p.expect('##\n')
  p.expect('##')
  initgen = p.before
  #put into 2D array
  lifegrid = []
  for line in initgen.split('\n')[:-1]:
   lifegrid.append([char for char in line if char != '#'])
  #go ahead that many gens
  for i in xrange(numgen):
   lifegrid = getnextgen(lifegrid)
  answer = '#'*(len(lifegrid[-1])+2) +'\n'+ ''.join('#'+''.join(char for char in line)+'#\n' for line in lifegrid) + '#'*(len(lifegrid[-1])+2)+'\n'
  p.send(answer)
 #wait for server to send us key :)
 for i in xrange(5):
  time.sleep(1)
  print sock.recv(1000)
 p.close()
 sock.close()

def getnextgen(lifegrid):
 newlifegrid = []
 for i in xrange(len(lifegrid)):
  newlifegrid.append([])
  for j in xrange(len(lifegrid[i])):
   #count how many neighbors
   count = 0
   for k in [-1,0,1]:
    for l in [-1,0,1]:
     if len(lifegrid)>i+k>=0 and len(lifegrid[i])>j+l>=0 and not k == l == 0 and lifegrid[i+k][j+l] == '*':
      count+=1
   #depending on how many neighbors, determine next gen pixel
   if count == 3:
    newlifegrid[-1].append('*')
   elif count == 2:
    newlifegrid[-1].append(lifegrid[i][j])
   else:
    newlifegrid[-1].append(' ')
 return newlifegrid

-keenlooks

No comments:

Post a Comment