Problem

Didn’t save the original text but here are my words:

Imagine an infinite 2d grid. Start at (0, 0). Move one unit right, then turn left whenever possible so that you don’t intersect with your trail. I.e. make a counter clock wise spiral. The challenge input is the number of iterations, the solution is the coordinate where the point ends up.

For input=4, the solution is (-1, 1)

  1. ----------
  2. ------ |
  3. | | |
  4. | .--- |
  5. --------

Solution

It took a while for me to get what the challenge really was about. Instead of wasting time on trying to solve the problem, I did what a proper script kiddie does well - I used Google. I found a very good solution on stackoverflow that takes the number of iterations and returns the coordinates in O(1) time.

The challenge input is a huge number, sometimes over 1024 bits in length, so we need to support that.

I re-wrote the code in python, rotated the coordinates (since the spiral went clockwise in the code above) and adapted it to use decimal to get arbitrary precision. Then just hooked it up to the game server and got the flag.

  1. import math
  2. import decimal
  3. from pwn import *
  4. context.log_level = 0
  5. _ctx = decimal.getcontext()
  6. _ctx.prec=2**12
  7. def floor(x):
  8. with decimal.localcontext() as ctx:
  9. #ctx.prec=100000000000000000
  10. ctx.prec=1
  11. ctx.rounding=decimal.ROUND_FLOOR
  12. return x.to_integral_exact()
  13. # http://stackoverflow.com/a/19287714/1747702
  14. def spiral(n):
  15. #given n an index in the squared spiral
  16. #p the sum of point in inner square
  17. #a the position on the current square
  18. #n = p + a
  19. _n = decimal.Decimal(n)
  20. #r = math.floor((math.sqrt(n + 1) - 1) / 2) + 1
  21. r = long(floor((decimal.Decimal(_n + 1).sqrt() - 1) / 2) + 1)
  22. #compute radius : inverse arithmetic sum of 8+16+24+...=
  23. p = (8 * r * (r - 1)) / 2
  24. #compute total point on radius -1 : arithmetic sum of 8+16+24+...
  25. en = r * 2
  26. #points by face
  27. a = (1 + n - p) % (r * 8)
  28. #compute de position and shift it so the first is (-r,-r) but (-r+1,-r)
  29. #so square can connect
  30. pos = [0, 0, r];
  31. tmp = math.floor(a / (r * 2))
  32. #find the face : 0 top, 1 right, 2, bottom, 3 left
  33. if tmp == 0:
  34. pos[0] = a - r
  35. pos[1] = -r
  36. elif tmp == 1:
  37. pos[0] = r
  38. pos[1] = (a % en) - r
  39. elif tmp == 2:
  40. pos[0] = r - (a % en)
  41. pos[1] = r
  42. elif tmp == 3:
  43. pos[0] = -r
  44. pos[1] = r - (a % en)
  45. #print("n : ", n, " r : ", r, " p : ", p, " a : ", a, " --> ", pos)
  46. newpos = [-pos[1], pos[0], r]
  47. return newpos
  48. #for i in xrange(25):
  49. # print i+1, spiral(i)
  50. #print spiral(87617132336372079846506616471286455749443259655954533789357600981378524569118335678751536947646080176816437606601550323221987024289898039719680451033326652052129641143066615453270361535742146132971398209593358690841000867875335581644900086496061447470988285895603240925546341429765197561195418284611512072176183221118915681135559699902117689293065428013532910524117825539447351947261308698064828704511533056969797355257686729816425986743810441213016227815358114008621623753229561235048044)
  51. p = process("openssl s_client -connect programming.pwn2win.party:9004", shell=True)
  52. p.recvuntil("Verify return code: 0 (ok)\n---\n")
  53. while True:
  54. N=p.recvuntil("\n")
  55. print "N=", N
  56. ret = spiral(long(N) - 1)
  57. p.sendline(str(ret[0]) + " " + str(ret[1]))
  58. print p.recv()
  59. #CTF-BR{iT-Was-JusT-BIgInteGeR-MFQnQRqKLcSHi}