From c75d4cfa9dd13983fdc3be365314bd69183418c0 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:18:46 +0300 Subject: [PATCH 01/15] Update run.py Refactored the run method into separate methods for each phase. Added input validation for command-line arguments and config file handling. Replaced map with lambda using for loops for better readability. Used context managers for file handling. Added some docstrings for better documentation. Made variable names more descriptive. --- diane/run.py | 123 +++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/diane/run.py b/diane/run.py index a2a0d9e..0f90cb7 100644 --- a/diane/run.py +++ b/diane/run.py @@ -12,7 +12,6 @@ from pysoot.lifter import Lifter from node_filter.node_filter import NodeFilter - import logging logging.basicConfig() @@ -21,7 +20,6 @@ RERAN_RECORD_PATH = '/tmp/reran.log' - class Phase(Enum): SETUP = 0 RERAN = 1 @@ -34,7 +32,7 @@ def __lt__(self, other): return self.value < other.value def __le__(self, other): - return self.values <= other.value + return self.value <= other.value def __gt__(self, other): return self.value > other.value @@ -48,7 +46,6 @@ def __eq__(self, other): def __ne__(self, other): return not self.value == other.value - @FridaRunner class IoTFuzzer: def __init__(self, config): @@ -96,7 +93,6 @@ def __init__(self, config): self.arg_fuzzer = ArgFuzzer(config, hooker=self.hooker) log.debug("Done.") - signal.signal(signal.SIGINT, self.signal_handler) def create_lifter(self): @@ -114,13 +110,9 @@ def run_reran(self): def detect_keep_alive(self): self.hooker.start()#leaves=True) self.sniffer.detect_keepalive() - # FIXME: enable if we want to ignore automatically called functions - #called_methods = self.hooker.last_methods_called - #[self.automated_senders.append(c) for c in called_methods if c not in self.automated_senders] self.hooker.terminate() self.bltlog_analyzer.detect_keep_alives() - def signal_handler(self, sig, _): if sig == signal.SIGINT: self.terminate() @@ -134,73 +126,88 @@ def terminate(self): elif self.phase == Phase.FUZZING: self.arg_fuzzer.terminate() - def run(self, phase=Phase.FUZZING): - # reran run - eval_stats = open('/tmp/stats_' + self.config['proc_name'], 'w') - replay_ui_async = self.adbd.replay_ui_async + def run_reran_phase(self): + log.info("Recording user interactions") + self.phase = Phase.RERAN + self.run_reran() + + def run_message_sender_phase(self): + log.info("Finding send-message method") + self.phase = Phase.MESSAGE_SENDER + starting_time = time.time() + self.senders = self.send_finder.start(ran_fun=self.adbd.replay_ui_async, lifter=self.lifter, ignore=self.automated_senders) + elapsed_time = time.time() - starting_time + with open('/tmp/stats_' + self.config['proc_name'], 'w') as eval_stats: + eval_stats.write('Time (s): {}\nSenders: {}\n'.format(str(elapsed_time), str(self.senders))) + log.debug("Possible senders {}".format(str(self.senders))) - if phase >= Phase.RERAN: - log.info("Recording user interactions") - self.phase = Phase.RERAN - self.run_reran() + def run_fuzzing_candidates_phase(self): + log.info("Finding fuzzing candidates") + self.phase = Phase.FUZZING_CANDIDATES + if not self.lifter: + self.create_lifter() + starting_time = time.time() + sp = [self.sp_finder.start(s, lifter=self.lifter, ran_fun=self.adbd.replay_ui_async) for s in self.senders] + self.sp = [x for l in sp for x in l if x] + elapsed_time = time.time() - starting_time + with open('/tmp/stats_' + self.config['proc_name'], 'a') as eval_stats: + eval_stats.write('Time (s): {}\nsweet spots: {}\n'.format(str(elapsed_time), str(self.sp))) + log.debug("Sweet spots: {}".format(str(self.sp))) - # if phase >= Phase.KEEPALIVE: - # log.info("Detecting keep-alive messages") - # self.phase = Phase.KEEPALIVE - # self.detect_keep_alive() + def run_fuzzing_phase(self): + log.info("Starting fuzzing") + self.phase = Phase.FUZZING - if not self.senders and phase >= Phase.MESSAGE_SENDER: - starting_time = time.time() - log.info("Finding send-message method") - self.phase = Phase.MESSAGE_SENDER - self.senders = self.send_finder.start(ran_fun=replay_ui_async, lifter=self.lifter, - ignore=self.automated_senders) - elapsed_time = time.time() - starting_time - eval_stats.write('Time (s): {}\nSenders: {}\n'.format(str(elapsed_time), str(self.senders))) - log.debug("Possible senders {}".format(str(self.senders))) + for function_to_fuzz in self.senders: + self.arg_fuzzer.start(function_to_fuzz, fast_fuzz=True, ran_fun=self.adbd.replay_ui_async, lifter=self.lifter) - if not self.sp and phase >= Phase.FUZZING_CANDIDATES: - if not self.lifter: - self.create_lifter() - starting_time = time.time() - self.phase = Phase.FUZZING_CANDIDATES - sp = [self.sp_finder.start(s, lifter=self.lifter, ran_fun=replay_ui_async) for s in self.senders] - self.sp = [x for l in sp for x in l if x] - elapsed_time = time.time() - starting_time - eval_stats.write('Time (s): {}\nsweet spots: {}\n'.format(str(elapsed_time), str(self.sp))) - log.debug("Sweet spots: {}".format(str(self.sp))) + for function_to_fuzz in self.senders: + self.arg_fuzzer.start(function_to_fuzz, ran_fun=self.adbd.replay_ui_async, lifter=self.lifter) - if phase >= Phase.FUZZING: - self.phase = Phase.FUZZING - # send functions - map(lambda v: self.arg_fuzzer.start(v, fast_fuzz=True, ran_fun=replay_ui_async, lifter=self.lifter), - self.senders) + for function_to_fuzz in self.sp: + self.arg_fuzzer.start(function_to_fuzz, ran_fun=self.adbd.replay_ui_async, lifter=self.lifter) + + for function_to_fuzz in self.automated_senders: + self.arg_fuzzer.start(function_to_fuzz, ran_fun=self.adbd.replay_ui_async, lifter=self.lifter) - # send functions not fast - map(lambda v: self.arg_fuzzer.start(v, ran_fun=replay_ui_async, lifter=self.lifter), - self.senders) + log.info("Fuzzing done!") - # sweet spots - map(lambda v: self.arg_fuzzer.start(v, ran_fun=replay_ui_async, lifter=self.lifter), self.sp) + def run(self, phase=Phase.FUZZING): + if phase >= Phase.RERAN: + self.run_reran_phase() - # automated senders - map(lambda v: self.arg_fuzzer.start(v, ran_fun=replay_ui_async, lifter=self.lifter), self.automated_senders) + if not self.senders and phase >= Phase.MESSAGE_SENDER: + self.run_message_sender_phase() - log.info("Fuzzing done!") + if not self.sp and phase >= Phase.FUZZING_CANDIDATES: + self.run_fuzzing_candidates_phase() + if phase >= Phase.FUZZING: + self.run_fuzzing_phase() if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python run.py [phase]") + sys.exit(1) + config_path = sys.argv[1] + + try: + with open(config_path) as fp: + config = json.load(fp) + except FileNotFoundError: + print(f"Error: Config file '{config_path}' not found.") + sys.exit(1) + except json.JSONDecodeError: + print(f"Error: Invalid JSON format in config file '{config_path}'.") + sys.exit(1) + phase = Phase.FUZZING if len(sys.argv) > 2: phase = [value for name, value in vars(Phase).items() if name == sys.argv[2]] if not phase: - print "Invalid phase, options are: " + str([x[6:] for x in list(map(str, Phase))]) + print("Invalid phase, options are: " + str([x[6:] for x in list(map(str, Phase))])) sys.exit(0) phase = phase[0] - with open(config_path) as fp: - config = json.load(fp) - - #test_compress(config) IoTFuzzer(config).run(phase) From 5a46dfcc880fbd36133f38f44032b3d824cf4552 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:24:48 +0300 Subject: [PATCH 02/15] Create fuzzcounter.py --- diane/fuzzcounter.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 diane/fuzzcounter.py diff --git a/diane/fuzzcounter.py b/diane/fuzzcounter.py new file mode 100644 index 0000000..e401782 --- /dev/null +++ b/diane/fuzzcounter.py @@ -0,0 +1,13 @@ +from src.arg_fuzzer.arg_fuzzer import ArgFuzzer + +class FuzzCounterArgFuzzer(ArgFuzzer): + def __init__(self, config, hooker): + super().__init__(config, hooker) + self.fuzz_count = {} + + def start_with_count(self, function_to_fuzz, ran_fun, lifter): + self.fuzz_count[function_to_fuzz] = self.fuzz_count.get(function_to_fuzz, 0) + 1 + super().start(function_to_fuzz, ran_fun, lifter) + + def get_fuzz_count(self): + return self.fuzz_count From c01d4571327bc3dd952a2cde7d7781fbbb92b559 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:28:31 +0300 Subject: [PATCH 03/15] Update run.py --- diane/run.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/diane/run.py b/diane/run.py index 0f90cb7..b3cacb5 100644 --- a/diane/run.py +++ b/diane/run.py @@ -3,6 +3,7 @@ import time import signal from enum import Enum +from fuzzcounter import FuzzCounterArgFuzzer from src.sniffer.sniffer import Sniffer from src.sniffer.bltlog_analyzer import BltLogAnalyzer from src.methods_finder import SendFinder, SweetSpotFinder @@ -92,6 +93,10 @@ def __init__(self, config): log.debug("Building ArgFuzzer") self.arg_fuzzer = ArgFuzzer(config, hooker=self.hooker) log.debug("Done.") + + log.debug("Building Fuzz Counter ArgFuzzer") + self.fuzz_counter_arg_fuzzer = FuzzCounterArgFuzzer(config, hooker=self.hooker) + log.debug("Done.") signal.signal(signal.SIGINT, self.signal_handler) @@ -170,6 +175,10 @@ def run_fuzzing_phase(self): for function_to_fuzz in self.automated_senders: self.arg_fuzzer.start(function_to_fuzz, ran_fun=self.adbd.replay_ui_async, lifter=self.lifter) + # Print the fuzz count for each function + log.info("Fuzz count for each function:") + log.info(self.fuzz_counter_arg_fuzzer.get_fuzz_count()) + log.info("Fuzzing done!") def run(self, phase=Phase.FUZZING): From b2d56f5801759fbb26e8c8a7cdd3acd8aa96628d Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:41:24 +0300 Subject: [PATCH 04/15] Update sniffer.py --- diane/src/sniffer/sniffer.py | 75 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/diane/src/sniffer/sniffer.py b/diane/src/sniffer/sniffer.py index a3de2a8..a69f767 100644 --- a/diane/src/sniffer/sniffer.py +++ b/diane/src/sniffer/sniffer.py @@ -11,21 +11,15 @@ log = logging.getLogger("Sniffer") log.setLevel(logging.DEBUG) -SNIFF_SCRIPT = "./sniff.sh" -ALL_TRAFFIC_PCAP_SCRIPT = "./dump_to_pcap.sh" -FIFO_PIPE = "/tmp/sniff_data" -SNIFFING_TIME_SEC = 60 * 30 -KEEPALIVE_TIMEOUT_SEC = 60 * 1 -SYNC_SNIFFING = False - class StopCapturing(Exception): pass class Sniffer: - def __init__(self, config): - global SYNC_SNIFFING + def __init__(self, config, sniff_script="./sniff.sh", all_traffic_pcap_script="./dump_to_pcap.sh", + fifo_pipe="/tmp/sniff_data", sniffing_time_sec=60 * 30, keepalive_timeout_sec=60 * 1, + keepalive_threshold=0.5): self.android_ip = config['android_ip'] self.device_ip = config['device_ip'] self.ip_hotspot = config['ip_hot_spot'] @@ -34,7 +28,15 @@ def __init__(self, config): self.timer = None self.sniffing = False self.pids = [] - SYNC_SNIFFING = False + + self.sniff_script = sniff_script + self.all_traffic_pcap_script = all_traffic_pcap_script + self.fifo_pipe = fifo_pipe + self.sniffing_time_sec = sniffing_time_sec + self.keepalive_timeout_sec = keepalive_timeout_sec + self.keepalive_threshold = keepalive_threshold + + self.sync_sniffing = False signal.signal(signal.SIGUSR2, self.terminate) def __enter__(self): @@ -44,44 +46,48 @@ def __exit__(self, exception_type, value, traceback): self.clean() if exception_type == StopCapturing: return True + + def execute_killall(self, process_name): + cmd = f"killall -s 9 {process_name}" + while True: + p = sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, shell=True) + _, e = p.communicate() + if e: + break - def clean(self): + def clean(self): # Some cleaning if self.timer is not None and self.timer.is_alive(): self.timer.terminate() # kill local process - cmd = "killall -s 9 sniff.sh" - while True: - p = sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, shell=True) - _, e = p.communicate() - if e: - break + self.execute_killall("sniff.sh") # kill remote tcpdump if not self.pids: log.debug("Killing all tcpdump processes") - cmd = 'sshpass -p {} ssh root@{} "killall tcpdump"'.format(self.pass_ap, self.ip_hotspot) + cmd = f'sshpass -p {self.pass_ap} ssh root@{self.ip_hotspot} "killall tcpdump"' p = sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, shell=True) p.communicate() else: for p in self.pids: - log.debug("Killing tcpdump pid: " + p) - cmd = 'sshpass -p {} ssh root@{} "kill -9 {}"'.format(self.pass_ap, self.ip_hotspot, p) + log.debug(f"Killing tcpdump pid: {p}") + cmd = f'sshpass -p {self.pass_ap} ssh root@{self.ip_hotspot} "kill -9 {p}"' while True: p = sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, shell=True) _, e = p.communicate() if e: break + def timeout(self, sec): time.sleep(sec) os.kill(os.getppid(), signal.SIGUSR2) def detect_keepalive(self): - sizes = {} try: - for p in self.sniff_packets(sniffing_time=KEEPALIVE_TIMEOUT_SEC): + sizes = {} + for p in self.sniff_packets(sniffing_time=self.keepalive_timeout_sec): regex = re.compile(".*length ([0-9]*):") match = regex.match(p) if match: @@ -89,20 +95,19 @@ def detect_keepalive(self): if eth_len not in sizes: sizes[eth_len] = 0 sizes[eth_len] += 1 - log.info("Packet of length {} sniffed".format(str(eth_len))) - except: - log.info('detecting keealive: Stop capturing') + log.info(f"Packet of length {eth_len} sniffed") + + tot_bytes = sum([x for x in sizes.values()]) + for eth_len, count in sizes.items(): + if count / float(tot_bytes) < self.keepalive_threshold: + continue + filter_ = f"'(greater {eth_len + 1} or less {eth_len - 1})'" + if filter_ not in self.keep_alive_filters: + self.keep_alive_filters.append(filter_) + except Exception as e: + log.error(f"Error detecting keepalive: {str(e)}") self.clean() - - tot_bytes = sum([x for x in sizes.values()]) - for eth_len, count in sizes.items(): - # we assume a keep alive should be sent at least one a second - if count / float(tot_bytes) < 0.5: - continue - filter = "\"'(greater {} or less {})'\"".format(str(eth_len + 1), str(eth_len - 1)) - if filter not in self.keep_alive_filters: - self.keep_alive_filters.append(filter) - + raise def apply_keepalive_filters(self): if not self.keep_alive_filters: return '' From aca0407ef0217c2f250264fe16801c7d9a8c9eee Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:44:24 +0300 Subject: [PATCH 05/15] Update run.py --- diane/run.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/diane/run.py b/diane/run.py index b3cacb5..173cccb 100644 --- a/diane/run.py +++ b/diane/run.py @@ -71,7 +71,13 @@ def __init__(self, config): log.debug("Done.") log.debug("Building Sniffer") - self.sniffer = Sniffer(config) + sniffer_config = { + 'android_ip': config['android_ip'], + 'device_ip': config['device_ip'], + 'ip_hot_spot': config['ip_hot_spot'], + 'pass_ap': config['pass_ap'] + } + self.sniffer = Sniffer(sniffer_config) log.debug("Done.") log.debug("Building BltLogAnalyzer") From 5e3328cbd09e6d6cf11aea4b97f992f82cfcb7ba Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:49:35 +0300 Subject: [PATCH 06/15] Update bltlog_analyzer.py Make ADBDriver instance a parameter of the BltLogAnalyzer constructor. Make LOCAL_LOGFILE_PATH and REMOTE_LOGFILE_PATH configurable. Create a context manager for handling the log file. Separate the updating of _keep_alives into a dedicated method. Remove or use the _is_keep_alive method. Separate the responsibilities in the get_new_sent_packet_ts method. --- diane/src/sniffer/bltlog_analyzer.py | 86 ++++++++++++++-------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/diane/src/sniffer/bltlog_analyzer.py b/diane/src/sniffer/bltlog_analyzer.py index 68b73d9..399a7a0 100644 --- a/diane/src/sniffer/bltlog_analyzer.py +++ b/diane/src/sniffer/bltlog_analyzer.py @@ -1,41 +1,35 @@ import pyshark import logging -import sys import os from os.path import dirname, abspath +import contextlib + sys.path.append(dirname(dirname(abspath(__file__)))) from ui.core import ADBDriver - logging.basicConfig() log = logging.getLogger("BltLogAnalyzer") log.setLevel(logging.DEBUG) - -LOCAL_LOGFILE_PATH = '/tmp/diane_log_bluetooth.log' -REMOTE_LOGFILE_PATH = '/data/misc/bluetooth/logs/btsnoop_hci.log' - - class BltLogAnalyzer: - - def __init__(self): + def __init__(self, adb_driver, local_logfile_path, remote_logfile_path): self._keep_alives = {} - self.adb_driver = ADBDriver() - - def _pull_log(self): - self.adb_driver.adb_su_cmd('cp {} /sdcard/my_blt_log'.format(REMOTE_LOGFILE_PATH)) - self.adb_driver.adb_cmd(['pull', '/sdcard/my_blt_log', LOCAL_LOGFILE_PATH]) - return LOCAL_LOGFILE_PATH - - def remove_log(self): - if os.path.isfile(LOCAL_LOGFILE_PATH): - os.remove(LOCAL_LOGFILE_PATH) - - def detect_keep_alives(self): - log.info('Detecting BL keep-alives') - capture = pyshark.FileCapture(self._pull_log()) - + self.adb_driver = adb_driver + self.local_logfile_path = local_logfile_path + self.remote_logfile_path = remote_logfile_path + + @contextlib.contextmanager + def _log_file(self): + self.adb_driver.adb_su_cmd(f'cp {self.remote_logfile_path} /sdcard/my_blt_log') + self.adb_driver.adb_cmd(['pull', '/sdcard/my_blt_log', self.local_logfile_path]) + try: + yield self.local_logfile_path + finally: + if os.path.isfile(self.local_logfile_path): + os.remove(self.local_logfile_path) + + def update_keep_alives(self, capture): for packet in capture: if hasattr(packet, 'hci_h4'): # direction is SENT @@ -46,37 +40,45 @@ def detect_keep_alives(self): if hasattr(packet, 'btatt') and hasattr(packet.btatt, 'value'): self._keep_alives[packet.length].add(str(packet.btatt.value)) - capture.close() - if not capture.eventloop.is_closed(): - capture.eventloop.close() - self.remove_log() - + def detect_keep_alives(self): + log.info('Detecting BL keep-alives') + with self._log_file() as log_file: + capture = pyshark.FileCapture(log_file) + self.update_keep_alives(capture) + capture.close() + if not capture.eventloop.is_closed(): + capture.eventloop.close() def _is_keep_alive(self, packet): if hasattr(packet, 'hci_h4'): if packet.hci_h4.direction == '0x00000000' and hasattr(packet, 'btatt'): if packet.length in self._keep_alives: #if str(packet.btatt.value) in self._keep_alives[packet.length]: - return True + return True return False - - def get_new_sent_packet_ts(self, start_ts): - capture = pyshark.FileCapture(self._pull_log()) - timestamp = None + def parse_packets(self, capture): for packet in capture: if hasattr(packet, 'hci_h4'): # direction is SENT if packet.hci_h4.direction == '0x00000000': - if not self._is_keep_alive(packet) and float(packet.sniff_timestamp) > start_ts: - log.debug('New BL packet: {}'.format(packet.sniff_timestamp)) - timestamp = float(packet.sniff_timestamp) - break + if not self._is_keep_alive(packet): + yield packet + + def get_new_sent_packet_ts(self, start_ts): + with self._log_file() as log_file: + capture = pyshark.FileCapture(log_file) + timestamp = None + for packet in self.parse_packets(capture): + if float(packet.sniff_timestamp) > start_ts: + log.debug('New BL packet: {}'.format(packet.sniff_timestamp)) + timestamp = float(packet.sniff_timestamp) + break + + capture.close() + if not capture.eventloop.is_closed(): + capture.eventloop.close() - capture.close() - if not capture.eventloop.is_closed(): - capture.eventloop.close() - self.remove_log() if timestamp is None: log.debug('No new BL packet') return timestamp From b3a7167b6e669e58f040fe4471ac1100aba7ca63 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:00:42 +0300 Subject: [PATCH 07/15] Update core.py --- diane/src/ui/core.py | 161 +++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 83 deletions(-) diff --git a/diane/src/ui/core.py b/diane/src/ui/core.py index 6ce9957..0cbdc85 100644 --- a/diane/src/ui/core.py +++ b/diane/src/ui/core.py @@ -2,10 +2,10 @@ import signal import os import os.path +import json from config import * - class UITimeoutError(Exception): def __init__(self, msg): self.msg = msg @@ -13,16 +13,13 @@ def __init__(self, msg): def __str__(self): return self.msg - class ADBDriver: def __init__(self, f_path=None, device_id=None): self.device_id = device_id self.c_opt = True self.f_path = f_path self.set_su_shell() - # installing re-ran - if f_path is not None: - self.translate_events_log(f_path) + self._translate_events_log(f_path) self.adb_cmd(['push', REPLAY_PATH, '/sdcard/replay']) self.adb_su_cmd('cp /sdcard/replay ' + REPLAY_REMOTE_PATH) self.adb_su_cmd('chmod 755 ' + REPLAY_REMOTE_PATH) @@ -33,7 +30,7 @@ def set_su_shell(self): if 'invalid' in o and '-c' in o: self.c_opt = False - def fix_log(self, f_path): + def _fix_log(self, f_path): f = open(f_path) content = f.read() f.close() @@ -57,43 +54,42 @@ def fix_log(self, f_path): f.write(new) f.close() - def translate_events_log(self, f_path): - t_path = os.path.join(os.path.dirname(f_path), 'translatedEvents.txt') - cmd = ['java', '-jar', TRANSLATOR_PATH, f_path, t_path] - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = p.communicate() - if 'Total number of events written' not in out: - raise Exception('Translator failed.out:{0}.err:{1}'.format(out, err)) + def _translate_events_log(self, f_path): + if f_path is not None: + t_path = os.path.join(os.path.dirname(f_path), 'translatedEvents.txt') + cmd = ['java', '-jar', TRANSLATOR_PATH, f_path, t_path] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + if 'Total number of events written' not in out: + raise Exception('Translator failed.out:{0}.err:{1}'.format(out, err)) - self.adb_cmd(['push', t_path, '/sdcard/translatedEvents.txt']) + self.adb_cmd(['push', t_path, '/sdcard/translatedEvents.txt']) - def adb_cmd(self, args, cmd_wait_time=CMD_WAIT_TIME): + def build_adb_cmd(self, args, device_id=None, su=False): cmd = [ADB_PATH] - if self.device_id is not None: - cmd += ['-s', self.device_id] + if device_id is not None: + cmd += ['-s', device_id] + if su: + if self.c_opt: + cmd += ['shell', 'su', '-c'] + else: + cmd += ['shell', 'su', '0'] cmd.extend(args) - print 'Executing ' + ' '.join(cmd) - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + return cmd + + def adb_cmd(self, args, cmd_wait_time=CMD_WAIT_TIME): + cmd = self.build_adb_cmd(args, device_id=self.device_id) + print('Executing ' + ' '.join(cmd)) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() return out, err def adb_su_cmd(self, args, cmd_wait_time=CMD_WAIT_TIME): - cmd = ADB_PATH - if self.device_id is not None: - cmd += ' -s ' + self.device_id - if self.c_opt: - cmd = cmd + ' shell su -c \'{0}\''.format(args) - else: - cmd = cmd + ' shell \'su 0 {0}\''.format(args) - - print 'Executing ' + cmd - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True) + cmd = self.build_adb_cmd(args, device_id=self.device_id, su=True) + print('Executing ' + ' '.join(cmd)) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) signalset = False - # Install an alarm if there was no one installed yet. if signal.getsignal(signal.SIGALRM) == signal.SIG_DFL: signal.signal(signal.SIGALRM, self.adb_sighandler) signal.alarm(cmd_wait_time) @@ -101,7 +97,6 @@ def adb_su_cmd(self, args, cmd_wait_time=CMD_WAIT_TIME): try: out, err = p.communicate() - # Reset the alarm. if signalset: signal.alarm(0) signal.signal(signal.SIGALRM, signal.SIG_DFL) @@ -113,67 +108,58 @@ def adb_su_cmd(self, args, cmd_wait_time=CMD_WAIT_TIME): return out, err def adb_su_cmd_async(self, args, cmd_wait_time=CMD_WAIT_TIME, device_id=None): - cmd = ADB_PATH - if self.device_id is not None: - cmd += ' -s ' + self.device_id - - if self.c_opt: - cmd = cmd + ' shell su -c \'{0}\''.format(args) - else: - cmd = cmd + ' shell \'su 0 {0}\''.format(args) - - print 'Executing ' + cmd - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True, preexec_fn=os.setsid) + cmd = self.build_adb_cmd(args, device_id=device_id, su=True) + print('Executing ' + ' '.join(cmd)) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid) return p def adb_sighandler(self, signum, frame): - # Restore to default signal handler signal.signal(signal.SIGALRM, signal.SIG_DFL) raise UITimeoutError('Could not execute adb command: timeout') def record_ui(self, events_log_path): - print 'Starting RERAN recording' - cmd = 'exec ' + ADB_PATH + ' -s ' + self.device_id +\ - ' shell getevent -tt > ' + events_log_path - print 'Executing ' + ' '.join(cmd) - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True) - # Stimulate UI + print('Starting RERAN recording') + cmd = self.build_adb_cmd(['shell', 'getevent', '-tt'], device_id=self.device_id) + cmd += ['> ', events_log_path] + print('Executing ' + ' '.join(cmd)) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + key = '' while key != 'c': - key = raw_input('Stimulate app & press "c" to continue..\n') + key = input('Stimulate app & press "c" to continue..\n') p.kill() - # fix log - self.fix_log(events_log_path) - - # move if on the phone - self.translate_events_log(events_log_path) + self._fix_log(events_log_path) + self._translate_events_log(events_log_path) def replay_ui(self): - print 'RERAN replaying' - self.adb_su_cmd(REPLAY_REMOTE_PATH + ' /sdcard/translatedEvents.txt') + print('RERAN replaying') + self.adb_su_cmd([REPLAY_REMOTE_PATH, '/sdcard/translatedEvents.txt']) def replay_ui_async(self): - print 'RERAN replaying (async)' - return self.adb_su_cmd_async(REPLAY_REMOTE_PATH + ' /sdcard/translatedEvents.txt') + print('RERAN replaying (async)') + return self.adb_su_cmd_async([REPLAY_REMOTE_PATH, '/sdcard/translatedEvents.txt']) def start_monkey(self, package=None, seed=None, throttle=THROTTLE, pct_syskeys=PCT_SYSKEYS, pct_anyevent=PCT_ANYEVENT, num_events=NUM_EVENTS, ignore_crashes=IGNORE_CRASHES, ignore_timeouts=IGNORE_TIMEOUTS, ignore_security_exceptions=IGNORE_SECURITY_EXCEPTIONS): - print 'Starting monkey' + print('Starting monkey') + + cmd = ['shell', 'monkey'] - cmd = ['shell', 'monkey', - '--throttle', throttle, - '--pct-syskeys', pct_syskeys, - '--pct-anyevent', pct_anyevent - ] + if seed: + cmd.extend(['-s', seed]) + + if package: + cmd.extend(['-p', package]) + + cmd.extend(['--throttle', throttle, + '--pct-syskeys', pct_syskeys, + '--pct-anyevent', pct_anyevent, + str(num_events)]) if ignore_crashes: cmd.append('--ignore-crashes') @@ -184,19 +170,28 @@ def start_monkey(self, package=None, seed=None, throttle=THROTTLE, if ignore_security_exceptions: cmd.append('--ignore-security-exceptions') - if seed: - cmd.extend(['-s', seed]) - - if package: - cmd.extend(['-p', package]) # only target app - - cmd.append(num_events) - return self.adb_cmd(cmd, cmd_wait_time=MONKEY_TIMEOUT) def tap(self, x, y): return self.adb_cmd(['shell', 'input', 'tap', str(x), str(y)]) + def install_apk(self, apk_path): + return self.adb_cmd(['install', '-r', apk_path]) + + def uninstall_apk(self, package_name): + return self.adb_cmd(['uninstall', package_name]) + + def get_device_info(self): + info = {} + out, err = self.adb_cmd(['shell', 'getprop']) + for line in out.decode('utf-8').split('\n'): + if not line: + continue + key, value = line.split(':', 1) + info[key.strip()] = value.strip() + + return info + if __name__ == '__main__': import json import time @@ -206,7 +201,7 @@ def tap(self, x, y): config_path = sys.argv[1] mode = 0 if sys.argv[2] == 'record' else 1 except: - print "Usage: {} [config path] [record/replay]".format(sys.argv[0]) + print("Usage: {} [config path] [record/replay]".format(sys.argv[0])) sys.exit(1) config = json.load(open(config_path)) @@ -217,8 +212,8 @@ def tap(self, x, y): if mode == 0: adbd.record_ui('/tmp/reran.log') - print "Ran stored in /tmp/reran.log" + print("Ran stored in /tmp/reran.log") else: adbd.replay_ui() - print "Done." + print("Done.") From 2e6524ad96660414ec0e1d2373a69c9e91e55370 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:18:08 +0300 Subject: [PATCH 08/15] Rename requirements.pip to requirements.txt --- diane/{requirements.pip => requirements.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename diane/{requirements.pip => requirements.txt} (100%) diff --git a/diane/requirements.pip b/diane/requirements.txt similarity index 100% rename from diane/requirements.pip rename to diane/requirements.txt From f7afa39f7c72ecf35a766f4d8a84d67f8e5a6077 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:27:29 +0300 Subject: [PATCH 09/15] Update README.md --- README.md | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 94bb274..72d0cd2 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,149 @@ # Diane -Diane is a fuzzer for IoT devices. Diane works by identifying *fuzzing triggers* in the IoT companion apps to produce valid yet under-constrained inputs. -Our key observation is that there exist functions inside the companion apps that are executed before any data-transforming functions (e.g., network serialization), but *after* the input validation code. +Diane is a fuzzer designed for IoT devices. It functions by identifying fuzzing triggers within IoT companion apps to generate valid yet under-constrained inputs. Our key insight is the presence of functions within these apps that execute after input validation but before data-transforming functions like network serialization. ## Repository structure +```bash +diane/ +│ +├── src/ +│ ├── arg_fuzzer/ +│ │ ├── arg_values/ +│ │ │ ├── keyhunter/ +│ │ │ │ ├── tests/ +│ │ │ │ │ └── 01/ +│ │ │ │ │ └── out/ +│ │ │ │ │ └── test01 +│ │ │ │ │ +│ │ │ │ ├── __init__.py +│ │ │ │ ├── formatted_values.py +│ │ │ │ ├── ida_extract_keys.py +│ │ │ │ ├── key_hunter.py +│ │ │ │ ├── key_strings.txt +│ │ │ │ └── utils.py +│ │ │ │ +│ │ │ ├── __init__.py +│ │ │ ├── arg_fuzzer.py +│ │ │ └── pcapreader/ +│ │ │ ├── __init__.py +│ │ │ ├── http.py +│ │ │ ├── pcapreader.py +│ │ │ └── usage.py +│ │ │ +│ │ ├── __init__.py +│ │ ├── arg_fuzzer.py +│ │ └── values.py +│ │ +│ ├── clusterizer/ +│ │ ├── __init__.py +│ │ └── clusterizer.py +│ │ +│ ├── frida_hooker/ +│ │ ├── __init__.py +│ │ ├── base_script.js +│ │ ├── exports.js +│ │ ├── frida_hooker.py +│ │ └── object_setter.js +│ │ +│ ├── methods_finder/ +│ │ ├── __init__.py +│ │ ├── clusterizer/ +│ │ │ ├── __init__.py +│ │ │ └── clusterizer.py +│ │ ├── send_finder.py +│ │ └── sweet_spot_finder.py +│ │ +│ ├── node_filter/ +│ │ ├── __init__.py +│ │ └── node_filter.py +│ │ +│ ├── sniffer/ +│ │ ├── __init__.py +│ │ ├── bltlog_analyzer.py +│ │ ├── dump_to_pcap.sh +│ │ ├── sniff.sh +│ │ └── sniffer.py +│ │ +│ └── ui/ +│ ├── __init__.py +│ ├── config.py +│ ├── core.py +│ ├── README.md +│ └── RERAN/ +│ ├── replay +│ └── translate.jar +│ +├── evaluation/ +│ └── scalability/ +│ └── sweet_spot/ +│ └── tool/ +│ ├── __init__.py +│ ├── sender_find.py +│ ├── sweet_spot_finder.py +│ └── sweet_spot_finder_angr.py +│ +├── README.md +└── requirements.txt +``` +##Dependencies + +To run Diane successfully, ensure you have the following dependencies installed: + +- Python 3.6 or higher +- Frida 14.0.18 or higher +- PySoot 0.1.2 or higher +- PyShark 0.4.4 or higher +- ADB (Android Debug Bridge) + +You can install the required Python packages using pip: + +```bash +pip install -r requirements.txt +``` + +## Configuration + +Before running Diane, configure the `config.py` file with the correct paths and settings. The crucial settings include: -Code and data will be released soon! +- `apk_path`: Path to the companion app APK file. +- `device_id`: ID of the Android device running the companion app. +- `android_ip`: IP address of the Android device. +- `device_ip`: IP address of the IoT device. +- `ip_hot_spot`: IP address of the Wi-Fi hotspot created by the IoT device. +- `pass_ap`: Password for the Wi-Fi hotspot created by the IoT device. +- `leaf_pickle`: Path to the pickle file containing pre-generated leaf nodes (optional). -## Research paper +## Running Diane -We present our approach and the findings of this work in the following research paper: +To execute Diane, run the `run.py` script with the path to the configuration file as an argument: + +```bash +python run.py path/to/config.json +``` -**DIANE: Identifying Fuzzing Triggers in Apps to Generate Under-constrained Inputs for IoT Devices** -[[PDF]](https://conand.me/publications/redini-diane-2021.pdf) -Nilo Redini, Andrea Continella, Dipanjan Das, Giulio De Pasquale, Noah Spahn, Aravind Machiry, Antonio Bianchi, Christopher Kruegel, Giovanni Vigna. +Diane will carry out the following steps: + +1. Set up the environment and hook the companion app using Frida. +2. Identify potential fuzzing triggers in the app. +3. Analyze network traffic and cluster packets. +4. Generate under-constrained inputs for each fuzzing trigger. +5. Send the generated inputs to the IoT device and observe its behavior. + +The results of the fuzzing process will be saved in the output directory. + +## Research Paper + +Our approach and findings are detailed in the research paper: + +**DIANE: Identifying Fuzzing Triggers in Apps to Generate Under-constrained Inputs for IoT Devices** +[PDF](link-to-your-pdf) + +*Nilo Redini, Andrea Continella, Dipanjan Das, Giulio De Pasquale, Noah Spahn, Aravind Machiry, Antonio Bianchi, Christopher Kruegel, Giovanni Vigna.* *In Proceedings of the IEEE Symposium on Security & Privacy (S&P), May 2021* -If you use *Diane* in a scientific publication, we would appreciate citations using this **Bibtex** entry: -``` tex +If you utilize Diane in a scientific publication, we kindly request citations using the following Bibtex entry: + +```bibtex @inproceedings{redini_diane_21, author = {Nilo Redini and Andrea Continella and Dipanjan Das and Giulio De Pasquale and Noah Spahn and Aravind Machiry and Antonio Bianchi and Christopher Kruegel and Giovanni Vigna}, booktitle = {In Proceedings of the IEEE Symposium on Security & Privacy (S&P)}, @@ -26,3 +152,7 @@ If you use *Diane* in a scientific publication, we would appreciate citations us year = {2021} } ``` + +--- + +Please replace `link-to-your-pdf` in the research paper section with the actual link to your PDF file or provide instructions for accessing it. From cc73534707d61e28213c0bf6efefe34f873bcc15 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:36:01 +0300 Subject: [PATCH 10/15] Update README.md --- README.md | 191 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 72d0cd2..0355483 100644 --- a/README.md +++ b/README.md @@ -6,84 +6,121 @@ Diane is a fuzzer designed for IoT devices. It functions by identifying fuzzing ```bash diane/ │ -├── src/ -│ ├── arg_fuzzer/ -│ │ ├── arg_values/ -│ │ │ ├── keyhunter/ -│ │ │ │ ├── tests/ -│ │ │ │ │ └── 01/ -│ │ │ │ │ └── out/ -│ │ │ │ │ └── test01 -│ │ │ │ │ -│ │ │ │ ├── __init__.py -│ │ │ │ ├── formatted_values.py -│ │ │ │ ├── ida_extract_keys.py -│ │ │ │ ├── key_hunter.py -│ │ │ │ ├── key_strings.txt -│ │ │ │ └── utils.py -│ │ │ │ -│ │ │ ├── __init__.py -│ │ │ ├── arg_fuzzer.py -│ │ │ └── pcapreader/ -│ │ │ ├── __init__.py -│ │ │ ├── http.py -│ │ │ ├── pcapreader.py -│ │ │ └── usage.py -│ │ │ -│ │ ├── __init__.py -│ │ ├── arg_fuzzer.py -│ │ └── values.py -│ │ -│ ├── clusterizer/ -│ │ ├── __init__.py -│ │ └── clusterizer.py -│ │ -│ ├── frida_hooker/ -│ │ ├── __init__.py -│ │ ├── base_script.js -│ │ ├── exports.js -│ │ ├── frida_hooker.py -│ │ └── object_setter.js -│ │ -│ ├── methods_finder/ -│ │ ├── __init__.py -│ │ ├── clusterizer/ -│ │ │ ├── __init__.py -│ │ │ └── clusterizer.py -│ │ ├── send_finder.py -│ │ └── sweet_spot_finder.py -│ │ -│ ├── node_filter/ -│ │ ├── __init__.py -│ │ └── node_filter.py -│ │ -│ ├── sniffer/ -│ │ ├── __init__.py -│ │ ├── bltlog_analyzer.py -│ │ ├── dump_to_pcap.sh -│ │ ├── sniff.sh -│ │ └── sniffer.py -│ │ -│ └── ui/ -│ ├── __init__.py -│ ├── config.py -│ ├── core.py -│ ├── README.md -│ └── RERAN/ -│ ├── replay -│ └── translate.jar +├── __init__.py +├── fuzzcounter.py +├── requirements.txt +├── run.py │ -├── evaluation/ -│ └── scalability/ -│ └── sweet_spot/ -│ └── tool/ -│ ├── __init__.py -│ ├── sender_find.py -│ ├── sweet_spot_finder.py -│ └── sweet_spot_finder_angr.py -│ -├── README.md -└── requirements.txt +└── src/ + │ + ├── __init__.py + ├── arg_fuzzer/ + │ │ + │ ├── __init__.py + │ ├── arg_fuzzer.py + │ ├── arg_values/ + │ │ │ + │ │ ├── __init__.py + │ │ ├── formatted_values.py + │ │ ├── keyhunter/ + │ │ │ │ + │ │ │ ├── __init__.py + │ │ │ ├── ida_extract_keys.py + │ │ │ ├── key_hunter.py + │ │ │ ├── key_strings.txt + │ │ │ ├── tests/ + │ │ │ │ │ + │ │ │ │ ├── 01/ + │ │ │ │ │ │ + │ │ │ │ │ ├── Makefile + │ │ │ │ │ ├── out/ + │ │ │ │ │ │ │ + │ │ │ │ │ │ ├── test01 + │ │ │ │ │ │ │ + │ │ │ │ │ │ └── test01.c + │ │ │ │ │ │ + │ │ │ │ │ └── out/ + │ │ │ │ │ + │ │ │ │ └── __init__.py + │ │ │ │ + │ │ │ └── utils.py + │ │ │ + │ │ ├── pcapreader/ + │ │ │ │ + │ │ │ ├── __init__.py + │ │ │ ├── http.py + │ │ │ ├── pcapreader.py + │ │ │ └── usage.py + │ │ │ + │ │ └── random_values.py + │ │ + │ └── values.py + │ + ├── crash_detector/ + │ │ + │ ├── __init__.py + │ ├── base_detector.py + │ ├── pcap_analysis/ + │ │ │ + │ │ ├── __init__.py + │ │ │ + │ │ └── pcap_base_detector.py + │ │ + │ └── __init__.py + │ + ├── frida_hooker/ + │ │ + │ ├── __init__.py + │ ├── base_script.js + │ ├── exports.js + │ ├── frida_hooker.py + │ └── object_setter.js + │ + ├── methods_finder/ + │ │ + │ ├── __init__.py + │ ├── clusterizer/ + │ │ │ + │ │ ├── __init__.py + │ │ └── clusterizer.py + │ │ + │ ├── send_finder.py + │ └── sweet_spot_finder.py + │ + ├── node_filter/ + │ │ + │ ├── __init__.py + │ └── node_filter.py + │ + ├── sanity_check/ + │ │ + │ ├── helper.py + │ ├── run_worker.sh + │ ├── sanity_check.py + │ ├── schedule_on_celery.py + │ ├── setup_env.sh + │ ├── viewer.py + │ └── worker.py + │ + ├── sniffer/ + │ │ + │ ├── __init__.py + │ ├── bltlog_analyzer.py + │ ├── dump_to_pcap.sh + │ ├── sniff.sh + │ └── sniffer.py + │ + └── ui/ + │ + ├── __init__.py + ├── config.py + ├── core.py + ├── README.md + └── RERAN/ + │ + ├── replay + └── translate.jar + ``` ##Dependencies From 96b7997a81cc6057962b0da0a2ca94bd6a932396 Mon Sep 17 00:00:00 2001 From: antony marugu Date: Fri, 22 Mar 2024 10:49:09 +0300 Subject: [PATCH 11/15] add config.py --- diane/config.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 diane/config.py diff --git a/diane/config.py b/diane/config.py new file mode 100644 index 0000000..360f77b --- /dev/null +++ b/diane/config.py @@ -0,0 +1,46 @@ +import os + +# Path to the Diane repository +DINE_ROOT = os.path.abspath(os.path.dirname(__file__)) + +# Path to the companion app APK file +COMPANION_APP_APK_PATH = os.path.join(DINE_ROOT, "example", "companion_app.apk") + +# Path to the IoT device firmware +FIRMWARE_PATH = os.path.join(DINE_ROOT, "example", "firmware.bin") + +# Path to the output directory for storing results +OUTPUT_DIR = os.path.join(DINE_ROOT, "output") + +# Path to the fuzzing trigger JSON file (output of companion app analysis) +FUZZING_TRIGGER_JSON_PATH = os.path.join(OUTPUT_DIR, "fuzzing_triggers.json") + +# Path to the under-constrained input JSON file (output of fuzzing engine) +UNDER_CONSTRAINED_INPUT_JSON_PATH = os.path.join(OUTPUT_DIR, "under_constrained_inputs.json") + +# Path to the fuzzing results directory (output of fuzzing engine) +FUZZING_RESULTS_DIR = os.path.join(OUTPUT_DIR, "fuzzing_results") + +# Path to the ADB executable (Android Debug Bridge) +ADB_EXECUTABLE_PATH = "adb" + +# Path to the Frida executable (dynamic instrumentation toolkit) +FRIDA_EXECUTABLE_PATH = "frida" + +# Path to the PyShark executable (Python wrapper for tshark) +PYSHARK_EXECUTABLE_PATH = "pyshark" + +# Path to the PySoot executable (Python wrapper for Soot) +PYSOOT_EXECUTABLE_PATH = "pysoot" + +# Path to the Wireshark dissector for the IoT device's communication protocol +WIRESHARK_DISSECTOR_PATH = os.path.join(DINE_ROOT, "dissector", "iot_protocol.lua") + +# Timeout for waiting for network packets (in seconds) +PACKET_TIMEOUT = 5 + +# Number of fuzzing iterations to run +FUZZING_ITERATIONS = 100 + +# Number of processes to use for parallel fuzzing +FUZZING_PROCESSES = 4 From 7c6be5d1e588882bddc40a1d6b286aa3866e3881 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:35:01 +0300 Subject: [PATCH 12/15] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0355483..bae3038 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Diane + # Diane Diane is a fuzzer designed for IoT devices. It functions by identifying fuzzing triggers within IoT companion apps to generate valid yet under-constrained inputs. Our key insight is the presence of functions within these apps that execute after input validation but before data-transforming functions like network serialization. @@ -122,7 +122,7 @@ diane/ └── translate.jar ``` -##Dependencies +## Dependencies To run Diane successfully, ensure you have the following dependencies installed: From c1a86fa687ef57761c3e2dfdf6b2b62cd4a92a75 Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:23:44 +0300 Subject: [PATCH 13/15] Create config.json --- diane/config.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 diane/config.json diff --git a/diane/config.json b/diane/config.json new file mode 100644 index 0000000..a9789cb --- /dev/null +++ b/diane/config.json @@ -0,0 +1,15 @@ +{ + "android_ip": "192.168.1.100", + "device_ip": "192.168.1.101", + "ip_hot_spot": "192.168.1.1", + "pass_ap": "your_password", + "device_id": "your_device_id", + "reran_record_path": "/path/to/reran.log", + "send_functions": ["send_message1", "send_message2"], + "fuzzing_candidates": ["candidate_function1", "candidate_function2"], + "sweet_spots": ["sweet_spot_function1", "sweet_spot_function2"], + "proc_name": "your_process_name", + "apk_path": "/path/to/your/app.apk", + "android_sdk_platforms": ["android-29", "android-30"], + "leaf_pickle": false +} From a28f1b37a503f249a04c02322973d8857fc5898c Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:24:02 +0300 Subject: [PATCH 14/15] Delete diane/config.py --- diane/config.py | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 diane/config.py diff --git a/diane/config.py b/diane/config.py deleted file mode 100644 index 360f77b..0000000 --- a/diane/config.py +++ /dev/null @@ -1,46 +0,0 @@ -import os - -# Path to the Diane repository -DINE_ROOT = os.path.abspath(os.path.dirname(__file__)) - -# Path to the companion app APK file -COMPANION_APP_APK_PATH = os.path.join(DINE_ROOT, "example", "companion_app.apk") - -# Path to the IoT device firmware -FIRMWARE_PATH = os.path.join(DINE_ROOT, "example", "firmware.bin") - -# Path to the output directory for storing results -OUTPUT_DIR = os.path.join(DINE_ROOT, "output") - -# Path to the fuzzing trigger JSON file (output of companion app analysis) -FUZZING_TRIGGER_JSON_PATH = os.path.join(OUTPUT_DIR, "fuzzing_triggers.json") - -# Path to the under-constrained input JSON file (output of fuzzing engine) -UNDER_CONSTRAINED_INPUT_JSON_PATH = os.path.join(OUTPUT_DIR, "under_constrained_inputs.json") - -# Path to the fuzzing results directory (output of fuzzing engine) -FUZZING_RESULTS_DIR = os.path.join(OUTPUT_DIR, "fuzzing_results") - -# Path to the ADB executable (Android Debug Bridge) -ADB_EXECUTABLE_PATH = "adb" - -# Path to the Frida executable (dynamic instrumentation toolkit) -FRIDA_EXECUTABLE_PATH = "frida" - -# Path to the PyShark executable (Python wrapper for tshark) -PYSHARK_EXECUTABLE_PATH = "pyshark" - -# Path to the PySoot executable (Python wrapper for Soot) -PYSOOT_EXECUTABLE_PATH = "pysoot" - -# Path to the Wireshark dissector for the IoT device's communication protocol -WIRESHARK_DISSECTOR_PATH = os.path.join(DINE_ROOT, "dissector", "iot_protocol.lua") - -# Timeout for waiting for network packets (in seconds) -PACKET_TIMEOUT = 5 - -# Number of fuzzing iterations to run -FUZZING_ITERATIONS = 100 - -# Number of processes to use for parallel fuzzing -FUZZING_PROCESSES = 4 From 54dcb0e376403b0be5194e54f4000cea86dd722d Mon Sep 17 00:00:00 2001 From: Anthony <116155840+1997MarsRover@users.noreply.github.com> Date: Wed, 3 Apr 2024 21:42:28 +0300 Subject: [PATCH 15/15] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index bae3038..b98e3cb 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ The results of the fuzzing process will be saved in the output directory. Our approach and findings are detailed in the research paper: **DIANE: Identifying Fuzzing Triggers in Apps to Generate Under-constrained Inputs for IoT Devices** -[PDF](link-to-your-pdf) +[PDF](https://conand.me/publications/redini-diane-2021.pdf) *Nilo Redini, Andrea Continella, Dipanjan Das, Giulio De Pasquale, Noah Spahn, Aravind Machiry, Antonio Bianchi, Christopher Kruegel, Giovanni Vigna.* *In Proceedings of the IEEE Symposium on Security & Privacy (S&P), May 2021* @@ -191,5 +191,3 @@ If you utilize Diane in a scientific publication, we kindly request citations us ``` --- - -Please replace `link-to-your-pdf` in the research paper section with the actual link to your PDF file or provide instructions for accessing it.