def find_devices(ctx, buses): results = [] for bus in buses: log.note('Probing bus {:d}'.format(bus)) try: cmd = 'i2c dev {:d}'.format(bus) # Raise an exception on error via check=True resp = ctx.send_command(cmd, check=True) # This may fail for buses (or pinmux settings) that are configured # appropriately. Thus, we drop check=True and just look results resp = ctx.send_command('i2c probe') match = re.match(r'Valid chip addresses: ([0-9a-fA-F\t ]+)', resp) if not match: # A failing bus will spew failures for a while. Keep trying # to interrupt it (Ctrl-C) until we know we're back at a prompt. log.warning('No devices or bus failing. Waiting for prompt.') ctx.interrupt(timeout=120) continue for addr in match.group(1).split(): addr = int(addr, 16) log.info('Found device: Bus={:d}, Address=0x{:02x}'.format( bus, addr)) results.append((bus, addr)) except OperationFailed as error: log.error('Command failed: ' + cmd + os.linesep + str(error)) return results
def run_test(ctx, reader, writer, address, data, stratagem): # Just to avoid triggering our warning to users wr_data = data if stratagem is None else None if not isinstance(reader, DataAbortMemoryReader): ctx.write_memory(address, wr_data, impl=writer, stratagem=stratagem) else: _da_read_pre_info['writer'] = writer _da_read_pre_info['data'] = data _da_read_pre_info['address'] = address data_read = ctx.read_memory(address, len(data), impl=reader) if data != data_read: now = round(time.time()) wfile = '{}.{}.bin'.format(writer.name, now) rfile = '{}.{}.bin'.format(reader.name, now) msg = 'Test case failed. Saving written and readback data to:' + linesep msg += ' {} and {}'.format(wfile, rfile) log.error(msg) fail_dir = create_resource_dir('memory_test', 'failure') filename = os.path.join(fail_dir, wfile) with open(filename, 'wb') as outfile: outfile.write(data) filename = os.path.join(fail_dir, rfile) with open(filename, 'wb') as outfile: outfile.write(data_read) return 'Fail' return 'Pass'
def perform_unlock_bypass(ctx): if is_unlocked(ctx): log.info("Device is already using 'unlocked' command table.") return True if not is_vulnerable(ctx): log.error('Device does not appear to be vulnerable.') return False ctx.patch_memory(_patch_list, impl='i2c') success = is_unlocked(ctx) if success: log.info("Success! Device is now using 'unlocked' command table.") else: log.error("Failed to switch to 'unlocked' command table.") return success
def is_vulnerable(ctx): """ Attempt to check if target is vulnerable to i2c-based unlock bypass, based upon the Sonos-provided (i.e. not the U-Boot) version number. """ ver_regex = re.compile( r'U-Boot \d{4}\.\d{2}-Royale(-Strict)?-Rev(?P<rev>\d{1,}\.\d{1,})\s') for info in ctx.version(): log.debug('Checking version string: ' + info) m = ver_regex.match(info) if m is not None: ver = float(m.group('rev')) if ver == 0.2: log.info('Vulnerable version detected: ' + info) return True if ver <= 0.3: msg = 'Version may be vulnerable, but our memory patches are specific to v0.2' log.error(msg) else: log.error('Patched or unknown version detected: ' + info) return False log.error('Did not detect "U-Boot Royale" version string.') return False
#!/usr/bin/env python3 import traceback from depthcharge import Console, Depthcharge, log ctx = None try: console = Console('/dev/ttyUSB0', baudrate=115200) ctx = Depthcharge.load('my_device.cfg', console) # Comment out the above ctx creation and uncomment the following one in # order to possibly make more operations available to Depthcharge by allowing # it to deploy executable payloads to RAM and reboot/crash the platform. #ctx = Depthcharge(console, allow_deploy=True, allow_reboot=True) # Perform actions here except Exception as error: log.error(str(error)) # Shown if DEPTHCHARGE_LOG_LEVEL=debug in environment log.debug(traceback.format_exc()) finally: # Save any updates or new information to the device config if ctx: ctx.save('my_device.cfg')
sim_memory[dst_off:dst_off + 4] = state.to_bytes(4, sys.byteorder) # Remaining iterations are performed in-place on the intermediate # result located in the destination memory location for i in range(1, iterations): state = crc32(sim_memory[dst_off:dst_off + 4]) sim_memory[dst_off:dst_off + 4] = state.to_bytes(4, sys.byteorder) if __name__ == '__main__': hunter = ReverseCRC32Hunter(THE_RAVEN, 0x0000_0000, revlut_maxlen=1024) stratagem = hunter.build_stratagem(TARGET_PAYLOAD, max_iterations=16384) filename = 'raven-stratagem.json' stratagem.to_json_file(filename) log.info('Saved stratagem to ' + filename) # Here's a good spot to set a breakpoint and inspect `stratagem` # breakpoint() # Simulate a memory space to write into sim_memory = bytearray(len(TARGET_PAYLOAD)) execute_stratagem(stratagem, sim_memory) if sim_memory == TARGET_PAYLOAD: log.info('Result:\n' + sim_memory.decode('ascii')) else: log.error('Produced result does not match desired target payload!') # breakpoint()