Last active
October 22, 2018 18:23
-
-
Save aadityapurani/b2d10b9c3acb54214023cb8517cb056c to your computer and use it in GitHub Desktop.
[HITCON CTF 2018] EV3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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