Task:
Universal dangerous positive: 194.226.244.125:1024. Send me your password: "3k8bbz032mrap75c8iz8tmi7f4ou00". Flag format is "RUCTF_.*"
Solution:
"Universal dangerous positive" hints us, that there is UDP protocol. So lets connect to given ip and send password:
UDP_IP = "194.226.244.125" UDP_PORT = 1024 message = "3k8bbz032mrap75c8iz8tmi7f4ou00" sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(1) sock.sendto(message, (UDP_IP, UDP_PORT)) print sock.recv(100000)
This code prints:
Hello stranger! You can go down(1280) with password: g5op3e6wxcy71m24dgcmhq714nd799 You can go right(1025) with password: 084399ptmy7u4bxwy003x2ko2oa06n
Ok, we have a maze, each cell of maze is defined by port and password. When we send correct password to port it responds with information about it's neighbors. So we have to write some code
First thing: maze's answers recognition (it's ugly, but it works):
res = sock.recv(100000)
print res
#Parse the answer
mess = []
dirs = []
while True:
#looking for direction:
ind1 = res.find("can go ")
if -1 == ind1:
break
ind1 = ind1 + len("can go ")
dirs.append(res[ind1:ind1+1])
#looking for password
ind = res.find("password: ")
if -1 == ind :
break
ind = ind + len("password: ")
mess.append(res[ind: ind+30])
res = res[ind+30:]Now we have array with password and corresponding array with directions (with first letters of them). We need some maze-solving algorithm, for example right-hand methond:
#declare in the begining order = ["r","d","l","u"] #right-hand alg order direction = 3 #and do this in cycle: #Compute next turn (right-hand method) next_dir = (direction + 1) % 4 next_i = -1 while True: for i in xrange(0, len(dirs), 1): if dirs[i] == order[next_dir]: next_i = i break if -1 != next_i: break next_dir = (next_dir - 1) %4 message = mess[next_i] #update port and coordinates if next_dir == 0: UDP_PORT +=1 if next_dir == 2: UDP_PORT -=1 if next_dir == 1: UDP_PORT +=256 if next_dir == 3: UDP_PORT -=256
direction = next_dir
So we choose next direction, trying to turn to the right every time when it possible and then update message and port to new values. As you can see, each time you go left and right port simply dec/increments, but when you go up and down it changes by 256... it's obvious from first server answer. (All other answer does not specify port, only passwords.)
Last thing we need.. some cool gui to draw this maze.. i used pygui... and there is result:
And full code of solving script:
#!/usr/bin/python
import socket
from time import sleep
import sys
from GUI import Application, ScrollableView, Document, Window, Cursor, rgb
from GUI.StdColors import black, red, white
from GUI.Files import FileType
from GUI.Geometry import pt_in_rect, offset_rect, rects_intersect
class MazeView(ScrollableView):
hero_x = 0
hero_y = 0
maze_walls = [[0 for x in xrange(256)] for x in xrange(256)]
offset = 10
multi = 4
def add_point(self, p_x ,p_y):
self.maze_walls[p_x][p_y]=1
def move_hero(self, p_x ,p_y):
self.hero_x = p_x
self.hero_y = p_y
self.invalidate_rect(( self.offset + (p_x - 3) * self.multi, self.offset + (p_y -3) * self.multi, self.offset + (p_x+3) * self.multi, self.offset + (p_y+3) * self.multi ))
self.update()
def draw(self, canvas, update_rect):
#canvas.erase_rect(update_rect)
#draw main wall
canvas.fill_frame_rect((self.offset-self.multi,self.offset-self.multi,self.offset+257*self.multi,self.offset+257*self.multi))
canvas.fillcolor = white
canvas.pencolor = white
canvas.fill_frame_rect((self.offset,self.offset,self.offset+256*self.multi,self.offset+256*self.multi))
#draw hero
canvas.fillcolor = red
canvas.pencolor = red
canvas.fill_frame_rect((self.offset + self.hero_x*self.multi, self.offset + self.hero_y*self.multi ,self.offset + self.hero_x*self.multi + self.multi,self.offset + self.hero_y*self.multi+ self.multi))
#draw inner walls
canvas.fillcolor = black
canvas.pencolor = black
for k in xrange(self.hero_x-5,self.hero_x+5,1):
for l in xrange(self.hero_y-5,self.hero_y+5,1):
if k < 0 or l <0 or k>= 256 or l >=256 : continue
if 1 == self.maze_walls[k][l]:
if True == pt_in_rect((self.offset + k*self.multi, self.offset + l*self.multi), update_rect):
canvas.fill_frame_rect((self.offset + k*self.multi, self.offset + l*self.multi,self.offset + k*self.multi + self.multi,self.offset + l*self.multi+ self.multi))
win = Window(size = (258*4+20, 258*4+20))
view = MazeView(extent = (512*4, 512*4))
win.place(view, left = 0, top = 0, right = 0, bottom = 0, sticky = 'nsew')
win.show()
UDP_IP = "194.226.244.125"
order = ["r","d","l","u"] #right-hand alg order
message = "3k8bbz032mrap75c8iz8tmi7f4ou00"
UDP_PORT = 1024
direction = 3
cur_x = 0
cur_y = 0
while True: # ti recover after disconnect
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1)
while True:
sock.sendto(message, (UDP_IP, UDP_PORT))
print "Current position: " + str(cur_x) + ", " + str(cur_y)
res = sock.recv(100000)
print res
#Parse the answer
mess = []
dirs = []
while True:
#looking for direction:
ind1 = res.find("can go ")
if -1 == ind1:
break
ind1 = ind1 + len("can go ")
dirs.append(res[ind1:ind1+1])
#looking for password
ind = res.find("password: ")
if -1 == ind :
break
ind = ind + len("password: ")
mess.append(res[ind: ind+30])
res = res[ind+30:]
view.move_hero(cur_x,cur_y)
if (dirs.count('r') == 0):
view.add_point(cur_x+1,cur_y)
if (dirs.count('l') == 0):
view.add_point(cur_x-1,cur_y)
if (dirs.count('u') == 0):
view.add_point(cur_x,cur_y-1)
if (dirs.count('d') == 0):
view.add_point(cur_x,cur_y+1)
#Compute next turn (right-hand method)
next_dir = (direction + 1) % 4
next_i = -1
while True:
for i in xrange(0, len(dirs), 1):
if dirs[i] == order[next_dir]:
next_i = i
break
if -1 != next_i:
break
next_dir = (next_dir - 1) %4
message = mess[next_i]
#update port and coordinates
if next_dir == 0:
cur_x += 1
UDP_PORT +=1
if next_dir == 2:
cur_x -= 1
UDP_PORT -=1
if next_dir == 1:
cur_y +=1
UDP_PORT +=256
if next_dir == 3:
cur_y -= 1
UDP_PORT -=256
direction = next_dir
except Exception, e:
print e
Running sports | jordan Release Dates