[NDH 2016] [Forensics 150 – Draw Me a Sheep] Write Up

Description

It is starting to become a usual kind of challenge.

we are given a pcap file with the registered usb traffic of an unknown device which should lead to the drawing of a Flag.

draw me a ship

Question: Draw me a Flag

Resolution

 

for this kind of challenge, we usually start opening the pcap file with wireshark.

wireshark1

we can quicly validate that it is a usb traffic. it’s traffic between the host and the device connected to the usb controller 3, with adress 2. (well, i guess that’s what it means)

we can see that the datas are freely available. no encryption with usb mouse datas (yet ?) :

wireshark_datas

we then need to get thoses datas :

at that point you have 2 options :

  • either you send it to india/china and you pay in bitcoin to get the data extracted manually line by line
  • or you automate this with tshark :
tshark -r file -Y 'usb.capdata and usb.device_address==3' -T fields -e usb.capdata > raw

as we already used all our money on alcool, that’s the path we chose.

 

you now have a nicely ordered list of inputs, with each line looking like :

01:ff:00:20:00
01:00:00:21:00
00:01:00:21:00

with a quick look, you get that relevant datas are in colum 0,1 and 3

on the first look you can gess that column 0/1 are relevant to the way the mouse moves, and column 3 must be the state of a button (either it’s clicked or not clicked)
but if you really want to do things right you can check some stats about it :

def stats_my_raws(rawfile):
	# get the datas
	f = open(rawfile)
	filedatas = f.read()
	f.close()
	raw_datas = filedatas.split('\n')

	for column in range(5):
		stats = {}
		for index, line in enumerate(raw_datas[:-1]):
			line=line.split(':')
			if line[column] in stats:
				stats[line[column]] += 1
			else:
				stats[line[column]] = 1
		#Print result
		print "Column %i stats :"%column
		for i in sorted(stats, key=stats.__getitem__, reverse=True):
			print "%s : %.02f %% - [%i]" % (i, 100.0 * stats[i] / len(raw_datas), stats[i])

#output :
'''
Column 0 stats :
00 : 48.19 % - [2495]
ff : 31.52 % - [1632]
01 : 17.98 % - [931]
02 : 1.85 % - [96]
03 : 0.42 % - [22]

Column 1 stats :
00 : 46.30 % - [2397]
ff : 27.64 % - [1431]
01 : 24.45 % - [1266]
fe : 1.58 % - [82]

Column 3 stats :
21 : 54.36 % - [2814]
20 : 45.62 % - [2362]
'''

So, we know that column 3 is a button and only has 2 possible value. so one of them must be “pressed” and the other one … i’ll let you guess
collumn 0 and 1 seams to behave in the same way, it’s either 00,01,02 or -01, -02 (FF/FE would be -01/-02 on a 2 byte signed integer)

Now that we are sure, let’s go to the fun part .

The idea is to :

  • Create an image file. B/W setting it to full black.
  • follow the mouse movments
  • Draw each point of the mouse when the button is “clicked”

 

we just don’t know how big is the user screen and where it start from. so let’s create a pretty big picture and start at the center

 

def resolv(filepath):
	#get the datas 
	f=open(filepath)
	filedatas=f.read()
	f.close()
	raw_datas=filedatas.split('\n')
	
	#Create a Black/White image
	size=2000
	img = Image.new("L", (size,size), 0) #Yep, a big one just to be sure
	draw = ImageDraw.Draw(img)
	pos=[size/2,size/2] #We start at the center of it
	
	#Just to know the max size we really need
	min_pos=[size/2,size/2]
	max_pos=[size/2,size/2]

then we go threw every moves and eventually print it :

for index,line in enumerate(raw_datas[:-1]):#last value is '\n'. we don't need that
   datas=line.split(':')

   if len(datas)==5:#just to filter bad input
      mouse_click=int(datas[3],16)#Fourth row is our "right click button"
      #Get the movments. it's signed 2bytes integer, so minus 0x100 if over 0x7f
      x_movement=int(datas[0],16)
      if x_movement>0x7f : x_movement-=0x100
      y_movement=int(datas[1],16)
      if y_movement > 0x7f: y_movement -= 0x100
      #
      pos[0]-=x_movement
      pos[1]+=y_movement
      #registering min/max value
      if pos[0] > max_pos[0]:max_pos[0]=pos[0]
      if pos[1] > max_pos[1]: max_pos[1] = pos[1]
      if pos[0] < min_pos[0]: min_pos[0] = pos[0]
      if pos[1] < min_pos[1]: min_pos[1] = pos[1]
      print "%s - %i:%i - %i:%i"%(line,x_movement,y_movement,pos[0],pos[1])

      if mouse_click  == 0x21:#if button is held down, we are writing
         do_point(pos,draw,5)
   else :
      print "error on line :%i - %s"%(index,line)
#img.show()
img.save('im2.png')
print "Min max positions : ",min_pos,max_pos

printing would be done by adding a point in our image

def do_point(pos,draw,size=2):#Print a point in the picture
   for x in range(size):
      for y in range(size):
         draw.point([pos[0]+x,pos[1]+y], fill=255)

 

and … Voila :

im2

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *