Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of a config option to run analysis or other scripts upon completion of pwninit #300

Open
Exiled1 opened this issue Jan 4, 2024 · 0 comments

Comments

@Exiled1
Copy link

Exiled1 commented Jan 4, 2024

Problem

During a CTF you might have tools you want to run, such as cwe_checker, checksec, seccomp rules, find cryptographic constants, find vulnerable functions, etc. You might even want to run custom scripts with information about the binary.

Currently pwninit doesn't support any of this out of the box. Nor does pwninit currently support a configuration file, instead taking just command line arguments to configure it on run.

Proposed Approach

I propose we borrow the functionality of spwn which is a project meant to expand upon pwninit.

One solution could be to have pwninit generate a config file similar to that of spwns default configs to mimic the ability for individuals to set up a ctf toolchain without the added difficulty of implementing some of the other features spwn has built into it like automatically using cwe_checker (and without adding more dependencies to the pwninit project).

I propose the following:

  1. Create a new Rust file called pwn_config.rs, that would create the config files in ~/.config/pwninit or some other similar location.

  2. Create a new Rust file called command_runner.rs that does the following:

    • Provide functionality similar to solvepy.rs but instead of formatting it into pwntools' ELF({stuff}), it would attempt to execute the python script/shell command provided with a struct similar to the following python struct. source
     class FileManager:
         # Three `Binary` objects
         self.binary
         self.libc    # Can be None
         self.loader  # Can be None
         # libc and loader have their own type that are a subclasses of `Binary`
         self.other_binaries  # list of relative paths
    
    class Binary:
        self.name  # relative path to the original binary
        self.debug_name  # relative path to the debug binary, if there is none it is equal to `self.name`
        self.pwnfile  # pwn.ELF object
    • Has the following functions run_command, pre_analysis, post_analysis where:
      • run_command: simply exec's the given command to the shell
      • pre_analysis: Would be used before pwninit fetches and patches the binary, and could take commands that work on {binary}, but not commands that operate on {patched_binary}.
      • post_analysis: Would be used after pwninit has completed running, and would be ab.e to take commands that work on both {binary} and {patched_binary}. Post analysis commands should be used if you want to actually run the binary during your analysis.
      • The syntax for the command is up for debate, currently spwn uses the following format [command, timeout], however a tuple of (command, timeout) could be used in Rust or something similar.
    • Another usage for these commands could be to open your decompiler of choice using the given binary. spwn currently has dedicated decompiler commands for IDA free and others. This could be useful behavior to mimic, however it probably isn't necessary with commands implemented.
    • An example of what the analysis would look like would be something like this customanalyzer.
  3. Update pwninit.rs to use the pre_analysis and post_analysis functions with the given config commands. As an example of how this would be implemented:

/// Run `pwninit` with specified options
pub fn run(opts: Opts) -> Result {
    // .. snip config fetching stuff ..
   command_runner::pre_analysis(config); // <--------------------- #1

    // Detect unspecified files
    let opts = opts.find_if_unspec().context(FindSnafu)?;

    // Print detected files
    opts.print();
    println!();

    set_bin_exec(&opts).context(SetBinExecSnafu)?;
    maybe_visit_libc(&opts);

    // Redo detection in case the ld was downloaded
    let opts = opts.find_if_unspec().context(FindSnafu)?;

    set_ld_exec(&opts).context(SetLdExecSnafu)?;

    if !opts.no_patch_bin {
        patch_bin::patch_bin(&opts).context(PatchBinSnafu)?;
    }

    if !opts.no_template {
        solvepy::write_stub(&opts).context(SolvepySnafu)?;
    }

    command_runner::post_analysis(config); // <----------------- #2

    Ok(())
}

Alternatives

  • Using all of these utilities separately would achieve the same result, it would just be more time consuming.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant