|
| 1 | +# AI Agent Instructions for Metasploit Framework |
| 2 | + |
| 3 | +## Project Overview |
| 4 | +Metasploit Framework is an open-source penetration testing and exploitation framework written in Ruby. It provides infrastructure for developing, testing, and executing exploit code against remote targets. |
| 5 | + |
| 6 | +## Project Structure |
| 7 | +- `modules/` — Metasploit modules (exploits, auxiliary, post, payloads, encoders, evasion, nops) |
| 8 | +- `lib/msf/` — Core framework library code |
| 9 | +- `lib/rex/` — Rex (Ruby Exploitation) library |
| 10 | +- `lib/metasploit/` — Metasploit namespace libraries |
| 11 | +- `data/` — Data files used by modules (wordlists, templates, binaries) |
| 12 | +- `spec/` — RSpec test suite |
| 13 | +- `tools/` — Developer and operational tools |
| 14 | +- `plugins/` — msfconsole plugins |
| 15 | +- `scripts/` — Example automation scripts |
| 16 | + |
| 17 | +## Coding Conventions |
| 18 | +- Ruby (see `.ruby-version` for the current version). Minimum supported: 3.1+ |
| 19 | +- Follow the project's `.rubocop.yml` configuration — run `rubocop` on changed files before submitting |
| 20 | +- Run `msftidy` to catch common module issues |
| 21 | +- Add `# frozen_string_literal: true` to new files (the RuboCop cop is disabled project-wide for legacy code, but new files should include it) |
| 22 | +- No enforced line length limit, but keep code readable |
| 23 | +- Use `%q{}` for long multi-line strings (curly braces preferred for module descriptions) |
| 24 | +- Multiline block comments are acceptable for embedded code snippets/payloads |
| 25 | +- Don't use `get_`/`set_` prefixes for accessor methods in new code |
| 26 | +- Method parameter names must be at least 2 characters (exception for well-known crypto abbreviations) |
| 27 | + |
| 28 | +### Module Development |
| 29 | +- Prefer writing modules in Ruby. Go and Python modules are accepted, but their external runtimes don't support the full framework API (e.g. network pivoting). Ruby modules do not have this limitation |
| 30 | +- Before writing a new module, check that there is not an existing module or open pull request that already covers the same functionality |
| 31 | +- Each module should be in its own file under the appropriate `modules/` subdirectory. In some scenarios adding module actions or targets is preferred. |
| 32 | +- Exploits require a `DisclosureDate` field |
| 33 | +- Exploits, auxiliary, and post modules require `Notes` with `SideEffects` |
| 34 | +- Use the module mixin APIs — don't reinvent the wheel |
| 35 | +- Use `create_process(executable, args: [], time_out: 15, opts: {})` instead of the deprecated `cmd_exec` with separate arguments |
| 36 | +- License new code with `MSF_LICENSE` (the project default, defined in `lib/msf/core/constants.rb`) |
| 37 | +- When overriding `cleanup`, always call `super` to ensure the parent mixin chain cleans up connections and sessions properly |
| 38 | +- When possible don't set a default payload (`DefaultOptions` with `'PAYLOAD'`) in modules — let the framework choose the most appropriate payload automatically |
| 39 | +- New modules require an associated markdown file in the `documentation/modules` folder with the same structure, including steps to set up the vulnerable environment for testing |
| 40 | +- Module descriptions or documentation should list the range of vulnerable versions and the fixed version of the affected software, when known |
| 41 | +- `report_service` method called when a service can be reported |
| 42 | +- `report_vuln` method called when a vuln can be reported |
| 43 | +- When creating a fake account / username use FAKER not `rand_test_alphanumeric` |
| 44 | +- Always use `res.get_json_document` to convert an HTTP response to a hash instead of calling `JSON.parse(res.body)` |
| 45 | +- If there's only one `ACTION` in the exploit, it can likely be omitted. |
| 46 | +- `Msf::Exploit::SQLi` should be used if it's exploiting an SQLi |
| 47 | +- All `print_*` calls should start with a capital |
| 48 | +- when opening a file, make sure the file exists first |
| 49 | +- when checking for a string in a response - will it always be in english? |
| 50 | +- Ensure hardcoded strings being regex'ed will be consistent across multiple versions |
| 51 | +- Use the TEST-NET-1 range for example / non-routeable IP address: `192.0.2.0` |
| 52 | +- Use fetch payload instead of command stagers when only options that request the stage are available (i.e. don’t use a cmd stager and only allow curl/wget). |
| 53 | +- Define bad characters instead of explicitly base-64 encoding payloads |
| 54 | +- Use `ARCH_CMD` payloads instead of command stagers when only curl/wget and other download mechanisms would be available |
| 55 | +- Don’t check the number of sessions at the end of an exploit and report success based on that, not all payloads open sessions |
| 56 | +- Don’t submit any kind of opaque binary blob, everything must include source code and build instructions |
| 57 | +- Don’t print host information like `#{ip}:#{port}` because it doesn’t handle IPv6 addresses, instead use `#{Rex::Socket.to_authority(ip, port)}` |
| 58 | +- Implement a `check` method when possible to allow users to verify vulnerability before exploitation |
| 59 | + |
| 60 | +### Check Methods |
| 61 | + |
| 62 | +- `check` methods must only return `CheckCode` values (e.g. `CheckCode::Vulnerable`, `CheckCode::Safe`) — never raise exceptions or call `fail_with` |
| 63 | +- When writing a `check` method, verify it does not produce false positives when run against unrelated software or services |
| 64 | +- Use `fail_with(Failure::UnexpectedReply, '...')` (and other `Failure::*` constants) to bail out of `exploit`/`run` methods — don't use `raise` or bare `return` for error conditions |
| 65 | +- `get_version` methods should return a REX version |
| 66 | +- `CheckCode::Vulnerable` is only used when the vulnerability has been exploited |
| 67 | +- `CheckCode::Appears` is only used when the application's versions has been checked` |
| 68 | +- Don't use a massive `<href .*` dot star to grab the version, to be more precise. |
| 69 | +- Do catch exceptions that may be raised and ensure a valid Check Code is returned |
| 70 | +- Do research and determine a minimum version where the application is vulnerable, mark prior versions as safe |
| 71 | +- Check helper methods that are used by both `#check` and `#exploit` (or `#run`) and make sure there is no condition (exception, return, etc) where `#check` could return something else than CheckCode. |
| 72 | +- Prefer `prepend Msf::Exploit::Remote::AutoCheck` over manually calling `check` inside `exploit` — this lets the framework handle check-before-exploit automatically |
| 73 | + |
| 74 | +### Library Code |
| 75 | +- When adding complex binary or protocol parsing (e.g. BinData, RASN1, Rex::Struct2), include a code comment linking to the specification or RFC that defines the format being implemented |
| 76 | +- Write RSpec tests for any library changes |
| 77 | +- Follow [Better Specs](http://www.betterspecs.org/) conventions |
| 78 | +- Write YARD documentation for public methods |
| 79 | +- Keep PRs focused — small fixes are easier to review |
| 80 | +- Any new hash cracking implementations require adding a test hash to `tools/dev/hash_cracker_validator.rb` and ensuring that passes without error |
| 81 | + |
| 82 | +### Testing |
| 83 | +- Tests live in `spec/` mirroring the `lib/` structure |
| 84 | +- Run tests with: `rspec spec/path/to/spec.rb` |
| 85 | +- Use `bundle exec rspec` to ensure correct gem versions |
| 86 | + |
| 87 | +### Preferred Libraries |
| 88 | +- Use the `RubySMB` library for SMB modules |
| 89 | +- Use `Rex::Stopwatch.elapsed_time` to track elapsed time |
| 90 | +- Use the `Rex::MIME::Message` class for MIME messages instead of hardcoding XML |
| 91 | +- When creating random variable names prefer `Rex::RandomIdentifier::Generator` and specify the runtime language used. This avoids generating langauge keywords that would break the script. |
| 92 | + |
| 93 | +## Common Patterns |
| 94 | +- Register options with `register_options` and `register_advanced_options` |
| 95 | +- Use `SCREAMING_SNAKE_CASE` option names and `CamelCase` advanced option names |
| 96 | +- Use `datastore['OPTION_NAME']` to access module options |
| 97 | +- Use `print_status`, `print_good`, `print_error`, `print_warning` for console output |
| 98 | +- Use `vprint_*` variants for verbose-only output |
| 99 | +- Use `send_request_cgi` for HTTP requests in modules |
| 100 | +- Use `connect` / `disconnect` for TCP socket operations |
| 101 | + |
| 102 | +## Before Submitting |
| 103 | +- Ensure `rubocop` and `msftidy` pass on any changed files with no new offenses |
| 104 | +- Ensure `msftidy_docs` passes on any changed documentation markdown docs with no new offenses |
| 105 | + |
| 106 | +## What NOT to Do |
| 107 | +- Don't submit untested code — all code must be manually verified |
| 108 | +- Don't include sensitive information (IPs, credentials, API keys, hashes of credentials) in code or docs |
| 109 | +- Don't include more than one module per pull request |
| 110 | +- Don't add new scripts to `scripts/` — use post modules instead |
| 111 | +- Don't use `pack`/`unpack` with invalid directives (enforced by linter) |
| 112 | + |
0 commit comments