Skip to content

Instantly share code, notes, and snippets.

@aadityapurani
Last active October 22, 2018 18:23
Show Gist options
  • Save aadityapurani/b2d10b9c3acb54214023cb8517cb056c to your computer and use it in GitHub Desktop.
Save aadityapurani/b2d10b9c3acb54214023cb8517cb056c to your computer and use it in GitHub Desktop.
[HITCON CTF 2018] EV3
import json
import operator
'''
Have to read documentation and see how opUI_DRAW worked
840501xxxxyyyyff
opcode text black xcord ycord char
Communication happens from localhost ethernet -> ev3
'''
# Taken from https://stackoverflow.com/questions/10664856/make-dictionary-with-duplicate-keys-in-python
class DictList(dict):
def __setitem__(self, key, value):
try:
# Assumes there is a list on the key
self[key].append(value)
except KeyError: # if fails because there is no key
super(DictList, self).__setitem__(key, value)
except AttributeError: # if fails because it is not a list
super(DictList, self).__setitem__(key, [self[key], value])
blk1=""
blk2=""
blk3=""
blk4=""
dict1 = DictList()
dict2 = DictList()
dict3 = DictList()
dict4 = DictList()
# btrfcomm && packetlogger.type==0x02 && data
with open('data_ev3_1.1') as f:
data = json.load(f)
for j in xrange(0, 4):
data_dump=""
stack=""
for i in xrange(0, len(data)):
tmp = "".join(data[i]["_source"]["layers"]["data"]["data.data"].split(":"))
if j ==0:
#print "[+] Retrieving block 1"
if '2884' in tmp:
meh = tmp.find('2884')
beep = tmp[meh+4:][:2]
xcord = tmp[meh-4:][:4]
if '00' in xcord[:2]:
xcord = tmp[meh-6:][:6]
xcord_int = int(xcord, 16)
beep_nice = beep.decode('hex')
if beep_nice in stack:
beep_nice = beep_nice+"#"
stack +=beep_nice
dict1[beep_nice] = xcord_int
#blk1 += beep_nice
#print data_dump
elif j == 1:
#print "[+] Retrieving block 2"
if '3684' in tmp:
meh = tmp.find('3684')
beep = tmp[meh+4:][:2]
xcord = tmp[meh-4:][:4]
if '00' in xcord[:2]:
xcord = tmp[meh-6:][:6]
xcord_int = int(xcord, 16)
beep_nice = beep.decode('hex')
if beep_nice in stack:
beep_nice = beep_nice+"#"
stack +=beep_nice
dict2[beep_nice] = xcord_int
#print data_dump
elif j == 2:
#print "[+] Retrieving block 3"
if '4484' in tmp:
meh = tmp.find('4484')
beep = tmp[meh+4:][:2]
xcord = tmp[meh-4:][:4]
if '00' in xcord[:2]:
xcord = tmp[meh-6:][:6]
xcord_int = int(xcord, 16)
beep_nice = beep.decode('hex')
if beep_nice in stack:
beep_nice = beep_nice+"#"
count +=1
stack +=beep_nice
dict3[beep_nice] = xcord_int
#print data_dump
elif j == 3:
#print "[+] Retrieving block 4"
if '5284' in tmp:
meh = tmp.find('5284')
beep = tmp[meh+4:][:2]
xcord = tmp[meh-4:][:4]
if '00' in xcord[:2]:
xcord = tmp[meh-6:][:6]
xcord_int = int(xcord, 16)
beep_nice = beep.decode('hex')
if beep_nice in stack:
beep_nice = beep_nice+"#"
stack +=beep_nice
dict4[beep_nice] = xcord_int
#print data_dump
print dict1
sorted_dict1 = sorted(dict1.items(), key=operator.itemgetter(1))
for i in xrange(0, len(sorted_dict1)):
blk1 += sorted_dict1[i][0]
sorted_dict2 = sorted(dict2.items(), key=operator.itemgetter(1))
for i in xrange(0, len(sorted_dict2)):
blk2 += sorted_dict2[i][0]
sorted_dict3 = sorted(dict3.items(), key=operator.itemgetter(1))
for i in xrange(0, len(sorted_dict3)):
blk3 += sorted_dict3[i][0]
sorted_dict4 = sorted(dict4.items(), key=operator.itemgetter(1))
for i in xrange(0, len(sorted_dict4)):
blk4 += sorted_dict4[i][0]
x = blk1.replace("#", '')
y = blk2.replace("#", '')
z = blk3.replace("#", '')
zz = blk4.replace("#", '')
print x+y+z+zz
#hitcon{m1nd5t0rm_communication_and_firmware_developer_kit}
#Human interaction was to include 'e' in firmwar due to 3 duplication issue. Didn't have time during CTF to optimize solver
import json
'''
Instruction opInput_Device (CMD, …)
Opcode 0x99
Now here we are looking at the read values from the sensor sent from ev3 to localhost ethernet
It seems like # for black and <space> for white will recreate the image
Example payload: 99 1d 00 02 00 02 01 60
length = 8 Bytes
99 = Opcode
1d = READY_SI
00 = Layer number 0
02 = Port Number of Sensor
00 = Type (default)
02 = Mode (default)
01 = Returned values (eh?)
Seems this payload is send as a request to read the values from sensor I think and the ev3 will respond it.
For reading response we can load the pklg into wireshark and use the following filter:
btrfcomm && packetlogger.type==0x03 && data
Select all packets (CTRL+SHIFT+M) and dump it using 'Export Packet Dissection -> As JSON -> ev3-scanner.json'
Hence, the communication weill be from LegoSyst -> localhost ethernet this case as values taken from robot will be sent of.
The response data variantions are minute :
00 c0 80
00 80 3f
+ + 45 (1st + is faster, 2nd is increment)
00 c0 80
00 80 3f
- - 45
00 c0 40
00 80 3f
+ + 45 (1st + is faster, 2nd is increment)
This looks like the ++45 means robot is making 180 degree U-Turn towards Right hand side
- - 45 is to nullify I think, making 180 degree U-Turn towards Left hand side
and c0 80 , c0 40 means White color read
80 3f means black color read
>>> int('c0', 16), int('80',16)
(192, 128)
>>> int('80', 16), int('3f',16)
(128, 63)
So, if the color is black then seems sensor value will be down, where intensity of reflected light will be higher on white surface.
----> 1
<----- 2
-------> 3
............
--------> 11
So, robot will traverse 11 times on the mattress.
'''
with open('ev3-scanner.json') as f:
data = json.load(f)
alert = 0
total_turn = 0
first_round = ""
second_round = ""
third_round = ""
fourth_round =""
fifth_round = ""
six_round =""
seven_round=""
eight_round = ""
nine_round = ""
ten_round = ""
eleven_round = ""
for i in xrange(0, len(data)):
tmp = "".join(data[i]["_source"]["layers"]["data"]["data.data"].split(":"))
if len(tmp) == 18:
i = 1
identifier1 = tmp[12:][0:2]
identifier2 = tmp[12:][2:4]
identifier3 = tmp[12:][4:6]
if identifier3 == '45': # Likely 180 U Turn
alert = 1
# break # start of the fucking turn
continue
elif identifier2 == 'c0' or identifier3 == '40' and identifier1 == '00': # Likely white
if alert == 1: # Turn has been taken
print "[+] Turn was taken"
alert = 0
total_turn += 1
if total_turn == 0:
first_round += " "
elif total_turn == 1:
second_round += " "
elif total_turn == 2:
third_round += " "
elif total_turn == 3:
fourth_round += " "
elif total_turn == 4:
fifth_round += " "
elif total_turn == 5:
six_round += " "
elif total_turn == 6:
seven_round += " "
elif total_turn == 7:
eight_round += " "
elif total_turn == 8:
nine_round += " "
elif total_turn == 9:
ten_round += " "
elif total_turn == 10:
eleven_round += " "
if total_turn == 0:
first_round += " "
elif total_turn == 1:
second_round += " "
elif total_turn == 2:
third_round += " "
elif total_turn == 3:
fourth_round += " "
elif total_turn == 4:
fifth_round += " "
elif total_turn == 5:
six_round += " "
elif total_turn == 6:
seven_round += " "
elif total_turn == 7:
eight_round += " "
elif total_turn == 8:
nine_round += " "
elif total_turn == 9:
ten_round += " "
elif total_turn == 10:
eleven_round += " "
elif identifier2 == '80' and identifier1 == '00': # Likely black
if alert == 1:
print "[+] Turn was taken"
alert = 0
total_turn += 1
if total_turn == 0:
first_round += "#"
elif total_turn == 1:
second_round += "#"
elif total_turn == 2:
third_round += "#"
elif total_turn == 3:
fourth_round += "#"
elif total_turn == 4:
fifth_round += "#"
elif total_turn == 5:
six_round += "#"
elif total_turn == 6:
seven_round += "#"
elif total_turn == 7:
eight_round += "#"
elif total_turn == 8:
nine_round += "#"
elif total_turn == 9:
ten_round += "#"
elif total_turn == 10:
eleven_round += " "
if total_turn == 0:
first_round += "#"
elif total_turn == 1:
second_round += "#"
elif total_turn == 2:
third_round += "#"
elif total_turn == 3:
fourth_round += "#"
elif total_turn == 4:
fifth_round += "#"
elif total_turn == 5:
six_round += "#"
elif total_turn == 6:
seven_round += "#"
elif total_turn == 7:
eight_round += "#"
elif total_turn == 8:
nine_round += "#"
elif total_turn == 9:
ten_round += "#"
elif total_turn == 10:
eleven_round +="#"
print "[+] Total turn taken was "+str(total_turn)
print first_round
print second_round[::-1]
print third_round
print fourth_round[::-1]
print fifth_round
print six_round[::-1]
print seven_round
print eight_round[::-1]
print nine_round
print ten_round[::-1]
print eleven_round
print "*************************************************************************************"
print len(first_round)
print len(second_round)
print len(third_round)
print len(fourth_round)
print len(fifth_round)
print len(six_round)
print len(seven_round)
print len(eight_round)
print len(nine_round)
print len(ten_round)
print len(eleven_round)
#hitcon{EV3GYROSUCKS}
#The ascii art isn't that proper but readable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment