From da0b3a7e404d47b64f2489af9c1b78c65cbf19b9 Mon Sep 17 00:00:00 2001 From: Or Yair Date: Mon, 12 Aug 2024 12:39:49 +0300 Subject: [PATCH] Fixed a bug in pack&parse and updated the docs --- README.md | 3 ++ docs/doc_pack_parse_packet_flows.md | 56 +++++++++++++++++++++++++++++ docs/doc_quick_fuzz.md | 13 +++++++ tools/pack_packet_flows.py | 6 ++-- tools/parse_packet_flows.py | 4 +-- 5 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 docs/doc_pack_parse_packet_flows.md diff --git a/README.md b/README.md index 3a15720..9ab60a4 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ This repository includes the tools we developed during our research: 5. [**force_wifi_connection**](./docs/doc_force_wifi_connection.md): Forces a device with Quick Share to connect to a given WiFi network. If performed against a Windows device with the vulnerable Quick Share version, then it also crashes its Quick Share app, creating a Wi-Fi connection to the given Wi-Fi network that lasts forever. 6. [**quick_fuzz**](./docs/doc_quick_fuzz.md): A fuzzer for Quick Share for Windows. Each fuzzing iteration sends a sequence of offline frames, simulating an entire transfer session. +### Supporting Tools +1. [**pack_packet_flows & parse_packet_flows**](./docs/doc_pack_parse_packet_flows.md) + ## Building Tools This repository uses Bazel for building. In order to build the tools you'll need to install Bazel - [Install Bazel on Windows](https://bazel.build/install/windows) diff --git a/docs/doc_pack_parse_packet_flows.md b/docs/doc_pack_parse_packet_flows.md new file mode 100644 index 0000000..c814d77 --- /dev/null +++ b/docs/doc_pack_parse_packet_flows.md @@ -0,0 +1,56 @@ +# pack_packet_flows & parse_packet_flows + +Tools for packing and parsing our custom binary format for representing sequences of packets (OfflineFrames). The format is simple: + +`[DWORD Length][Serialized Offline Frame][DWORD Length][Serialized Offline Frame]...` + +* [DWORD Length] - Four bytes that represent the size of a packet in little endian +* [Serialized Offline Frame] - A serialized protobuf packet (OfflineFrame) + +Three of the tools that we developed in this repo use these custom format: +* [**quick_fuzz**](/docs/doc_quick_fuzz.md) - Receives files in this format as corpus (fuzzing input files) +* [**send_packets**](/docs/doc_send_packets.md) - Receives files in this format as an input, and sends the contained packets +* [**quick_sniff**](/docs/doc_quick_sniff.md) - Outputs files in this format that hold the sequence of packets that each device that participated a sniffed session sent + + +## Build +Run: +```cmd +bazel build //tools:pack_packet_flows +bazel build //tools:parse_packet_flows +``` +The executables will be created in `./bazel-bin/tools` + +## Usage +pack_packet_flows: + +```cmd +usage: pack_packet_flows.py [-h] parsed_packet_flow_dir out_packet_flow_file + +Packs (serializes) Quick Share's (OfflineFrame) packets' pretty YAML files into their +protobuf serialized byte form + +positional arguments: + parsed_packet_flow_dir + A path to a directory containing all packets in YAML (as + parse_packet_flows parses outputs) + out_packet_flow_file A path to the packets file to be create +``` + +parse_packet_flows: + +```cmd +usage: parse_packet_flows.py [-h] packet_flow_file out_dir + +Parse Quick Share's (OfflineFrame) packets into textual readable YAML structures + +positional arguments: + packet_flow_file A path to a file with containing all packets in + |length|packet|length|packet| format + out_dir A path to a directory where the output file/s will be created +``` + +### Advanced Parameters +quick_sniff works by hooking the most basic Read & Write functions that are used by Quick Share to send and receive packets using any communication method. They don't have symbols inside the compiled binary, and so we must set their addresses (offsets) statically per the version of the Quick Share app. We set the addresses to the addresses of these functions in the vulnerable version of Quick Share that is present in this repository. If you want to sniff packets on a different version, you'll have to modify the addresses. Quick explanations for how to find these functions in a disassembler are written in comments in `quick_sniff.cc`. The names of these functions in Quick Share's source code are: +* BaseEndpointChannel::Read +* BaseEndpointChannel::Write \ No newline at end of file diff --git a/docs/doc_quick_fuzz.md b/docs/doc_quick_fuzz.md index 8891425..c3bbd31 100644 --- a/docs/doc_quick_fuzz.md +++ b/docs/doc_quick_fuzz.md @@ -26,6 +26,19 @@ Once you install one of them, make sure you disable updates. In addition to these DLLs, you'll need to have WinAFL as the fuzzing framework. We needed to perform a small patch in WinAFL's code in order for it to work with our harness and libprotobuf-mutator. You can either run the [`clone_and_patch_winafl.bat`](/quick_fuzz/winafl_clone_and_patch/clone_and_patch_winafl.bat) script that we created and then follow WinAFL's instructions for compilation yourself. Or you can use the precompiled version of WinAFL that we uploaded to this repo at [precompiled_patched_winafl.zip](/quick_fuzz/precompiled_patched_winafl.zip). Note that you'll have to download DynamoRIO version 10.92.19896, since `afl-fuzz.exe` needs it in order to run. You can download it from [here](https://github.com/DynamoRIO/dynamorio/releases/download/cronbuild-10.92.19896/DynamoRIO-Windows-10.92.19896.zip) +### Corpus (Input Files): +The input files are files in our custom binary format. Each file contains a sequence of packets (OfflineFrames) that should be sent in a fuzzing iteration. The fuzzing harness behaves as if the first packets in the sequence are: +1. Connection Request +2. Connection Response +3. Paired Key Encryption +4. Paired Key Result +5. Introduction +6. Introduction Done + +And then sends the rest of the packets (Usually Payload Transfer OfflineFrames with the content of the file to be sent) + +Corpus files can be created using the [**quick_sniff**](/docs/doc_quick_sniff.md) fuzzer (Would be best if you make sure that are no redundant packets up to the Introduction packet). To better understand the format of the corpus files, read the docs about [**pack_packet_flows & parse_packet_flows**](/docs/doc_pack_parse_packet_flows.md) + ### Usage of afl-fuzz with our harness: You should refer to WinAFL's documentation in order to fully understand `afl-fuzz.exe`'s parameters diff --git a/tools/pack_packet_flows.py b/tools/pack_packet_flows.py index a139727..95fe0cd 100644 --- a/tools/pack_packet_flows.py +++ b/tools/pack_packet_flows.py @@ -2,14 +2,14 @@ import os import yaml -from python_tool_helpers.offline_frames_utils import offline_frame_dict_to_offline_frame +from tools.python_tool_helpers.offline_frames_utils import offline_frame_dict_to_offline_frame def parse_args(): parser = argparse.ArgumentParser(description="Packs (serializes) Quick Share's (OfflineFrame) packets' pretty YAML files into their protobuf serialized byte form") - parser.add_argument("packets_dir", help="A path to a directory containing all YAML packets") - parser.add_argument("out_file", help="A path to the packets file to be created") + parser.add_argument("parsed_packet_flow_dir", help="A path to a directory containing all packets in YAML (as parse_packet_flows parses outputs)") + parser.add_argument("out_packet_flow_file", help="A path to the packets file to be created") return parser.parse_args() diff --git a/tools/parse_packet_flows.py b/tools/parse_packet_flows.py index 8723068..1a582f3 100644 --- a/tools/parse_packet_flows.py +++ b/tools/parse_packet_flows.py @@ -2,13 +2,13 @@ import os import yaml -from python_tool_helpers.offline_frames_utils import decode_offline_frame_protobuf_bytes +from tools.python_tool_helpers.offline_frames_utils import decode_offline_frame_protobuf_bytes def parse_args(): parser = argparse.ArgumentParser(description="Parse Quick Share's (OfflineFrame) packets into textual readable YAML structures") - parser.add_argument("packets_file", help="A path to a file with containing all packets in |length|packet|length|packet| format") + parser.add_argument("packet_flow_file", help="A path to a file with containing all packets in |length|packet|length|packet| format") parser.add_argument("out_dir", help="A path to a directory where the output file/s will be created") return parser.parse_args()