{"id":13635109,"url":"https://github.com/entropic-security/xgadget","last_synced_at":"2025-04-19T03:34:22.838Z","repository":{"id":37992352,"uuid":"273932256","full_name":"entropic-security/xgadget","owner":"entropic-security","description":"Fast, parallel, cross-variant ROP/JOP gadget search for x86/x64 binaries.","archived":false,"fork":false,"pushed_at":"2023-11-24T15:16:42.000Z","size":405,"stargazers_count":84,"open_issues_count":3,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-11-09T02:18:27.263Z","etag":null,"topics":["binary","exploitation","gadget","jop","rop","rust","x64","x86"],"latest_commit_sha":null,"homepage":"https://docs.rs/xgadget","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/entropic-security.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-21T15:30:33.000Z","updated_at":"2024-10-21T16:59:22.000Z","dependencies_parsed_at":"2022-09-06T19:51:41.990Z","dependency_job_id":"813a31e2-e9a2-40eb-8dca-32e676dc260d","html_url":"https://github.com/entropic-security/xgadget","commit_stats":{"total_commits":84,"total_committers":2,"mean_commits":42.0,"dds":0.25,"last_synced_commit":"691e0ddd2d6f218267abbfab8c242ab41232fb7a"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entropic-security%2Fxgadget","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entropic-security%2Fxgadget/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entropic-security%2Fxgadget/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entropic-security%2Fxgadget/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/entropic-security","download_url":"https://codeload.github.com/entropic-security/xgadget/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223790238,"owners_count":17203353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary","exploitation","gadget","jop","rop","rust","x64","x86"],"created_at":"2024-08-02T00:00:40.833Z","updated_at":"2024-11-09T05:30:21.499Z","avatar_url":"https://github.com/entropic-security.png","language":"Rust","funding_links":[],"categories":["Applications"],"sub_categories":["Security tools"],"readme":"# xgadget\n\n[![crates.io](https://img.shields.io/crates/v/xgadget.svg)](https://crates.io/crates/xgadget)\n[![docs.rs](https://docs.rs/xgadget/badge.svg)](https://docs.rs/xgadget/)\n[![GitHub Actions](https://github.com/entropic-security/xgadget/workflows/test/badge.svg)](https://github.com/entropic-security/xgadget/actions)\n[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/entropic-security/xgadget/blob/main/LICENSE)\n\nFast, parallel, cross-{patch,compiler}-variant ROP/JOP gadget search for x86 (32-bit) and x64 (64-bit) binaries.\nUses the [iced-x86 disassembler library](https://github.com/icedland/iced).\n\nThis crate can be used as a **CLI binary** (Windows/Linux/MacOS) or a **library** (7 well-known dependencies, all Rust).\n\n### Quickstart\n\nInstall the CLI tool and show its help menu:\n\n```bash\ncargo install xgadget --features cli-bin    # Build on host (pre-req: https://www.rust-lang.org/tools/install)\nxgadget --help                              # List available command line options\n```\n\n### How do ROP and JOP code reuse attacks work?\n\n* **Return Oriented Programming (ROP)** introduced *code-reuse* attacks, after hardware mitigations (aka NX, DEP) made *code-injection* less probable (no simultaneous `WRITE` and `EXECUTE` memory permissions). An attacker with stack control chains together short, existing sequences of assembly (aka \"gadgets\") - should a leak enable computing gadget addresses in the face of ASLR. When contiguous ROP gadget addresses are written to a corrupted stack, each gadget's ending `ret` instruction pops the next gadget's address into the CPU's instruction pointer. The result? Turing-complete control over a victim process.\n\n\u003cp style=\"text-align: center;\" align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/tnballo/high-assurance-rust/main/src/chp4/exploit_rop_model.svg\" width=\"60%\" alt=\"rop model\"\u003e\n    \u003cfigure style=\"text-align:center;\"\u003e\n    \u003c/figure\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ci\u003e\u003cb\u003eROP\u003c/b\u003e Attack Model (recreated from:\u003ca href=\"https://www.comp.nus.edu.sg/~liangzk/papers/asiaccs11.pdf\"\u003e Bletsch et. al.\u003c/a\u003e)\u003c/i\u003e\n\u003c/p\u003e\n\n* **Jump Oriented Programming (JOP)** is a newer code reuse method which, unlike ROP, doesn't rely on stack control. The attack *bypasses* hardware-assisted shadow-stack implementations (e.g. Intel CET's shadow stack), and is *limited* but *not prevented* by prototype-insensitive indirect target checks (e.g. Intel CET's IBT). JOP allows storing a table of gadget addresses in any `READ`/`WRITE` memory location. Instead of piggy-backing on call-return semantics to execute a gadget list, a \"dispatch\" gadget (e.g. `add rax, 8; jmp [rax]`) controls table indexing. Chaining happens if each gadget ends with a `jmp` back to the dispatcher (instead of a `ret`).\n\n\u003cp style=\"text-align: center;\" align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/tnballo/high-assurance-rust/main/src/chp4/exploit_jop_model.svg\" width=\"100%\" alt=\"jop model\"\u003e\n    \u003cfigure style=\"text-align:center;\"\u003e\n    \u003c/figure\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ci\u003e\u003cb\u003eJOP\u003c/b\u003e Attack Model (recreated from:\u003ca href=\"https://www.comp.nus.edu.sg/~liangzk/papers/asiaccs11.pdf\"\u003e Bletsch et. al.\u003c/a\u003e)\u003c/i\u003e\n\u003c/p\u003e\n\n### About\n\n`xgadget` is a tool for **Return-Oriented Programming (ROP)** and **Jump-Oriented Programming (JOP)** exploit development.\nIt's a fast, multi-threaded alternative to awesome tools like [`ROPGadget`](https://github.com/JonathanSalwan/ROPgadget), [`Ropper`](https://github.com/sashs/Ropper), and [`rp`](https://github.com/0vercl0k/rp).\n\nThe goal is supporting practical usage while simultaneously exploring unique and experimental features.\nTo the best of our knowledge, `xgadget` is the first gadget search tool to be:\n\n* **Fast-register-sensitive**: Filters gadgets by register usage behavior, not just matches for a given regex, without SMT solving (more powerful, but often impractical).\n\n    * `--reg-overwrite [\u003cOPT_REG(S)\u003e...]` - control any reg (no args) or specific regs (args)\n\n    * `--reg-mem-write [\u003cOPT_REG(S)\u003e...]` - write mem indexed via any reg (no args) or specific regs (args)\n\n    * `--reg-no-write [\u003cOPT_REG(S)\u003e...]` - don't write any reg (no args) or specific regs (args)\n\n    * `--reg-read [\u003cOPT_REG(S)\u003e...]` - read any regs (no args) or specific regs (args)\n\n    * `--reg-mem-read [\u003cOPT_REG(S)\u003e...]` - read mem indexed via any reg (no args) or specific regs (args)\n\n    * `--reg-no-read [\u003cOPT_REG(S)\u003e...]` - don't read any regs (no args) or specific regs (args)\n\n* **JOP-efficient**: JOP search uses instruction semantics - not hardcoded regex for individual encodings.\n\n    * Optionally filter to JOP \"dispatcher\" gadgets with flag `--dispatcher`\n\n* **Cross-variant:** Finds gadgets that work across multiple variants of a binary (e.g. anti-diversification for different program or compiler versions). Two strategies:\n\n1. ***Full-match*** - Same instruction sequence, same program counter: gadget fully re-usable. Example:\n    * Gadget: `pop rdi; ret;`\n    * Address (in all binaries): `0xc748d`\n\n\u003cp style=\"text-align: center;\" align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/entropic-security/xgadget/main/img/xgadget_all_match.svg\" width=\"70%\" alt=\"full match\"\u003e\n    \u003cfigure style=\"text-align:center;\"\u003e\n    \u003c/figure\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ci\u003eCross-variant \u003cb\u003eFull Match\u003c/b\u003e\u003c/i\u003e\n\u003c/p\u003e\n\n2. ***Partial-match*** - Same instruction sequence, different program counter: gadget logic portable. Example:\n    * Gadget: `pop rdi; ret;`\n    * Address in `bin_v1.1`: `0xc748d`\n    * Address in `bin_v1.2`: `0xc9106`\n\n\u003cp style=\"text-align: center;\" align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/entropic-security/xgadget/main/img/xgadget_addr_match.svg\" width=\"70%\" alt=\"partial match\"\u003e\n    \u003cfigure style=\"text-align:center;\"\u003e\n    \u003c/figure\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ci\u003eCross-variant \u003cb\u003ePartial Match\u003c/b\u003e\u003c/i\u003e\n\u003c/p\u003e\n\n* This is entirely optional, you're free to run this tool on a single binary.\n\nOther features include:\n\n* Supports ELF32, ELF64, PE32, PE32+, Mach-O, and raw files\n* Parallel across available cores, whether searching a single binary or multiple variants\n* Currently 8086/x86/x64 only (uses a speed-optimized, arch-specific disassembler)\n\n### CLI Examples\n\nRun `xgadget --help` to enumerate available options.\n\n* **Example:** Search `/usr/bin/sudo` for reliable ways to control `rdi`:\n\n```bash\nxgadget /usr/bin/sudo --reg-only --reg-overwrite rdi\n```\n\n* **Example:** Search for ROP gadgets that control the value of `rdi`, never read `rsi` or `rdx`, and occur at addresses that don't contain bytes `0x32` or `0x0d`:\n\n```bash\nxgadget /usr/bin/sudo --rop --reg-overwrite rdi --reg-no-read rsi rdx --bad-bytes 0x32 0x0d\n```\n\n* **Example:** Search `/usr/bin/sudo` for \"pop, pop, {jmp,call}\" gadgets up to 10 instructions long, print results using AT\u0026T syntax:\n\n```bash\nxgadget /usr/bin/sudo --jop --reg-pop --att --max-len 10\n```\n\n* **Example:** Same as above, except using a regex filter to match \"pop, pop, {jmp,call}\" instruction strings (slower/less-accurate here, but regex enables flexible search in general):\n\n```bash\nxgadget /usr/bin/sudo --regex-filter \"^(?:pop)(?:.*(?:pop))*.*(?:call|jmp)\" --att --max-len 10\n```\n\n* **Example:** Examine the exploit mitigations binaries `sudo` and `lighttpd` have been compiled with:\n\n```bash\nxgadget /usr/bin/sudo /usr/sbin/lighttpd --check-sec\n```\n\n* **Example:** List imported and internal symbols for `lighttpd`:\n\n```bash\nxgadget /usr/sbin/lighttpd --symbols\n```\n\n### API Usage\n\nFind gadgets:\n\n```rust,no_run\nuse xgadget::{Binary, SearchConfig};\n\nlet max_gadget_len = 5;\n\n// Search single binary\nlet bin = \u0026[Binary::from_path(\"/path/to/bin_v1\").unwrap()];\nlet gadgets =\n    xgadget::find_gadgets(bin, max_gadget_len, SearchConfig::default()).unwrap();\nlet stack_pivot_gadgets = xgadget::filter_stack_pivot(gadgets);\n\n// Search for cross-variant gadgets, including partial matches\nlet search_config = SearchConfig::default() | SearchConfig::PART;\nlet bins = \u0026[\n    Binary::from_path(\"/path/to/bin_v1\").unwrap(),\n    Binary::from_path(\"/path/to/bin_v2\").unwrap(),\n];\nlet cross_gadgets =\n    xgadget::find_gadgets(bins, max_gadget_len, search_config).unwrap();\nlet cross_reg_pop_gadgets = xgadget::filter_reg_pop_only(cross_gadgets);\n```\n\nCustom filters can be created using the [`GadgetAnalysis`](crate::GadgetAnalysis) object and/or functions from the [`semantics`](crate::semantics) module.\nHow the above [`filter_stack_pivot`](crate::filters::filter_stack_pivot) function is implemented:\n\n```rust\nuse rayon::prelude::*;\nuse iced_x86;\nuse xgadget::{Gadget, GadgetAnalysis};\n\n/// Parallel filter to gadgets that write the stack pointer\npub fn filter_stack_pivot\u003c'a, P\u003e(gadgets: P) -\u003e P\nwhere\n    P: IntoParallelIterator\u003cItem = Gadget\u003c'a\u003e\u003e + FromParallelIterator\u003cGadget\u003c'a\u003e\u003e,\n{\n    gadgets\n        .into_par_iter()\n        .filter(|g| {\n            let regs_overwritten = g.analysis().regs_overwritten(true);\n            if regs_overwritten.contains(\u0026iced_x86::Register::RSP)\n                || regs_overwritten.contains(\u0026iced_x86::Register::ESP)\n                || regs_overwritten.contains(\u0026iced_x86::Register::SP)\n            {\n                return true;\n            }\n            false\n        })\n        .collect()\n}\n```\n\n\u003c!--- TODO: add back later\n### CLI Build and Install (Recommended)\n\nBuild a dynamically-linked binary from source and install it locally:\n\n```bash\ncargo install xgadget --features cli-bin    # Build on host (pre-req: https://www.rust-lang.org/tools/install)\n```\n\n### CLI Binary Releases for Linux\n\nCommits to this repo's `main` branch automatically run integration tests and build a statically-linked binary for 64-bit Linux.\nYou can [download it here](https://github.com/entropic-security/xgadget/releases) to try out the CLI immediately, instead of building from source.\nStatic binaries for Windows may also be supported in the future.\n\nUnfortunately the statically-linked binary is several times slower on an i7-9700K, likely due to the built-in memory allocator for target `x86_64-unknown-linux-musl`.\nSo building a dynamically-linked binary from source with the above `cargo install` command is *highly* recommended for performance (links against your system's allocator).\n\n---\u003e\n\n### Why No Chain Generation?\n\nTools that attempt to automate ROP/JOP chain generation require heavyweight analysis - typically symbolic execution of an intermediate representation.\nThis works well for small binaries and CTF problems, but tends to be error-prone and difficult to scale for large, real-world programs.\nAt present, `xgadget` has a different goal: enable an expert user to manually craft stable exploits by providing fast, accurate gadget discovery.\n\n### ~~Yeah, but can it do 10 OS kernels under 10 seconds?!~~ Repeatable Benchmark Harness\n\nTo build a Docker container and connect to it:\n\n```bash\nuser@host$ git clone git@github.com:entropic-security/xgadget.git\nuser@host$ cd xgadget\nuser@host$ docker build -t xgadget_bench_container .\nuser@host$ docker run -it xgadget_bench_container\nroot@container:/xgadget#\n```\n\nThe final build step runs `./benches/bench_setup_ubuntu.sh`.\nThis script downloads and builds 10 consecutive Linux kernels (versions `5.0.1` to `5.0.10` - with `x86_64_defconfig`).\nGrab a coffee, it can take a while.\n\nOnce it's done, run `cargo bench` to search all 10 kernels for common gadgets (among other benchmarks):\n\n```bash\nroot@container:/xgadget# cargo bench\n```\n\nOn an i7-9700K (8C/8T, 3.6GHz base, 4.9 GHz max) machine with `gcc` version 8.4.0: the average runtime, to process *all ten 54MB kernels simultaneously* with a max gadget length of 5 instructions and full-match search for all gadget types (ROP, JOP, and syscall gadgets), is *only 6.3 seconds*! Including partial matches as well takes *just 7.9 seconds*.\n\n### Fast Exploit Similarity Score (FESS)\n\nThe `--fess` flag uses cross-variant gadget matching as a metric of binary similarity.\nIt's an experiment in anti-diversification for exploitation.\nTo view similarity scores for kernel versions `5.0.1`, `5.0.5`, and `5.0.10` within the container:\n\n```bash\nroot@container# cd ./benches/kernels/\nroot@container# xgadget vmlinux-5.0.1 vmlinux-5.0.5 vmlinux-5.0.10 --fess\nTARGET 0 - [ name: 'vmlinux-5.0.1' | fmt-arch: ELF-X64 | entry: 0x00000001000000 | exec bytes/segments: 21,065,728/2 ]\nTARGET 1 - [ name: 'vmlinux-5.0.5' | fmt-arch: ELF-X64 | entry: 0x00000001000000 | exec bytes/segments: 21,069,824/2 ]\nTARGET 2 - [ name: 'vmlinux-5.0.10' | fmt-arch: ELF-X64 | entry: 0x00000001000000 | exec bytes/segments: 21,069,824/2 ]\n\n┌─────────────┬──────────────────────┬──────────────────────┬───────────────────────┐\n│ Gadget Type │ vmlinux-5.0.1 (base) │ vmlinux-5.0.5 (diff) │ vmlinux-5.0.10 (diff) │\n├─────────────┼──────────────────────┼──────────────────────┼───────────────────────┤\n│  ROP (full) │              108,380 │        7,351 (6.78%) │           556 (0.51%) │\n├─────────────┼──────────────────────┼──────────────────────┼───────────────────────┤\n│  ROP (part) │                    - │      80,783 (74.54%) │       78,053 (72.02%) │\n├─────────────┼──────────────────────┼──────────────────────┼───────────────────────┤\n│  JOP (full) │               79,685 │        1,007 (1.26%) │           276 (0.35%) │\n├─────────────┼──────────────────────┼──────────────────────┼───────────────────────┤\n│  JOP (part) │                    - │      16,458 (20.65%) │       12,461 (15.64%) │\n├─────────────┼──────────────────────┼──────────────────────┼───────────────────────┤\n│  SYS (full) │                8,276 │          422 (5.10%) │           119 (1.44%) │\n├─────────────┼──────────────────────┼──────────────────────┼───────────────────────┤\n│  SYS (part) │                    - │       4,317 (52.16%) │        3,864 (46.69%) │\n└─────────────┴──────────────────────┴──────────────────────┴───────────────────────┘\n```\n\nNote these totals exclude low-quality gadgets (use `--all` flag to include).\nIn the output table, we see that up to 72.02% of individual ROP gadgets, and 15.64% of JOP gadgets, are portable across all three versions (counting partial matches).\n\n### Acknowledgements\n\nThis project started as an optimized solution to Chapter 8, exercise 3 of [\"Practical Binary Analysis\" by Dennis Andreisse](https://amzn.to/3wvtCwa) (affiliate link), and builds on the design outlined therein.\n\n### Related Resource\n\n**Free book about software assurance: [https://highassurance.rs/](https://highassurance.rs/)**\n\n### License and Contributing\n\nLicensed under the [MIT license](https://github.com/entropic-security/xgadget/blob/main/LICENSE).\n[Contributions](https://github.com/entropic-security/xgadget/blob/main/CONTRIBUTING.md) are welcome!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentropic-security%2Fxgadget","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fentropic-security%2Fxgadget","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentropic-security%2Fxgadget/lists"}