Add Ignition gateway fingerprint scanner (auxiliary/scanner/scada/ignition_statusping) - #21603
Conversation
…ition_statusping) Fingerprints Inductive Automation Ignition gateways across all major versions by probing version-specific unauthenticated info endpoints. Tested against: - Ignition 7.9.21 (/main/system/gwinfo, key=value) - Ignition 8.1.15 (/system/StatusPing, JSON) - Ignition 8.1.17 (/system/StatusPing, JSON) - Ignition 8.3.4 (/system/gwinfo, key=value) Reference: https://ethomason.com/posts/fingerprinting-ignition-gateways/
- Add frozen_string_literal magic comment - Track found state to avoid spurious 'no endpoint' message - Remove references to modules not yet in codebase - Replace regex JSON parsing with JSON.parse + ParserError rescue - Use Rex::Socket.to_authority for IPv6-safe output - report_host now uses actual OS value; Ignition data in report_note - SSL-aware service name (https vs http) - Parse runtimeVersion from JSON StatusPing response - Replace public IP in docs with RFC 5737 test address (192.0.2.32)
There was a problem hiding this comment.
Pull request overview
Adds a new Metasploit auxiliary scanner module to fingerprint Inductive Automation Ignition gateways by probing unauthenticated version/info endpoints across major Ignition versions, with accompanying user documentation.
Changes:
- Introduces
auxiliary/scanner/scada/ignition_statuspingto probe/system/gwinfo,/system/StatusPing, and/main/system/gwinfoand report discovered gateway details. - Adds module documentation with verification steps and example scan scenarios.
Impact Analysis: isolated change; no meaningful downstream impact identified from diff.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| modules/auxiliary/scanner/scada/ignition_statusping.rb | New auxiliary scanner that probes Ignition info endpoints, parses responses, and reports results to the MSF database. |
| documentation/modules/auxiliary/scanner/scada/ignition_statusping.md | New module documentation describing affected versions/endpoints, usage, and example output. |
- Replace JSON.parse with framework res.get_json_document helper (AGENTS.md:51) - Pass response object to parse_statusping instead of body string - Replace non-ASCII em dashes in description with ASCII hyphens (AGENTS.md:47)
|
Addressed in faf31b7 - switched to get_json_document and ASCII hyphens.
…On Thu, Jun 25, 2026 at 6:40 AM Copilot ***@***.***> wrote:
***@***.**** commented on this pull request.
Pull request overview
Adds a new Metasploit auxiliary scanner module to fingerprint Inductive
Automation Ignition gateways by probing unauthenticated version/info
endpoints across major Ignition versions, with accompanying user
documentation.
*Changes:*
- Introduces auxiliary/scanner/scada/ignition_statusping to probe
/system/gwinfo, /system/StatusPing, and /main/system/gwinfo and report
discovered gateway details.
- Adds module documentation with verification steps and example scan
scenarios.
*Impact Analysis:* isolated change; no meaningful downstream impact
identified from diff.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and
generated 3 comments.
File Description
modules/auxiliary/scanner/scada/ignition_statusping.rb New auxiliary
scanner that probes Ignition info endpoints, parses responses, and reports
results to the MSF database.
documentation/modules/auxiliary/scanner/scada/ignition_statusping.md New
module documentation describing affected versions/endpoints, usage, and
example output.
------------------------------
In modules/auxiliary/scanner/scada/ignition_statusping.rb
<#21603 (comment)>
:
> + # Parse JSON format used by 8.1.x StatusPing
+ def parse_statusping(body)
+ document = JSON.parse(body)
+ return {} unless document.is_a?(Hash)
+
+ %w[version state role peerAddress os runtimeVersion].each_with_object({}) do |key, info|
+ info[key] = document[key] if document[key]
+ end
+ rescue JSON::ParserError
+ {}
+ end
*Important:* Problem: This parses JSON via JSON.parse instead of the
framework helper res.get_json_document (see AGENTS.md:51). Impact:
inconsistent JSON parsing/logging behavior vs other HTTP modules and misses
the standard error logging path. Fix: accept the HTTP response and use
get_json_document with document.key?/nil checks.
------------------------------
In modules/auxiliary/scanner/scada/ignition_statusping.rb
<#21603 (comment)>
:
> + next if res.body.strip.empty?
+
+ version = state = os = runtime = role = peer = nil
+
+ if probe[:format] == :kvp
+ d = parse_gwinfo(res.body)
+ version = d['Version']
+ state = d['ContextStatus']
+ os = d['OS']
+ runtime = d['RuntimeVersion']
+ role = d['RedundancyStatus']
+ elsif probe[:format] == :json
+ # Skip the minimal 8.3.x StatusPing stub which returns only state
+ next if res.body.strip == '{"state":"RUNNING"}'
+
+ d = parse_statusping(res.body)
*Important:* Problem: parse_statusping is called with res.body, but the
parser should operate on the HTTP response to use res.get_json_document
(AGENTS.md:51). Impact: forces manual parsing and diverges from the
framework’s standard response helpers. Fix: pass res to parse_statusping.
------------------------------
In modules/auxiliary/scanner/scada/ignition_statusping.rb
<#21603 (comment)>
:
> + Endpoint and response format by version:
+ 7.9.x — /main/system/gwinfo (semicolon-delimited key=value)
+ 8.0.x — /system/gwinfo (semicolon-delimited key=value)
+ 8.1.x — /system/StatusPing (JSON)
+ 8.3.x — /system/gwinfo (semicolon-delimited key=value, additional fields)
*Suggestion:* Problem: The module description contains non-ASCII em
dashes (—), which conflicts with the project guidance that module
descriptions should be ASCII-only (AGENTS.md:47). Impact: can cause
display/encoding issues in some terminals and tooling. Fix: replace —
with an ASCII hyphen sequence.
—
Reply to this email directly, view it on GitHub
<#21603?email_source=notifications&email_token=BERDKBPHW45KVHKTZ2X4VYT5BUTUDA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTINJXGE2DKNRWG42KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#pullrequestreview-4571456674>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BERDKBLZV32OS2H4OPUL4Z35BUTUDAVCNFSNUABDKJSXA33TNF2G64TZHMZDEOJTGE2TQO2JONZXKZJ3GQ3TGOJYHAZDKMZUUF3AE>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/BERDKBLYS6W5FBUC7AUWTH35BUTUDA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTINJXGE2DKNRWG42KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KUZTPN52GK4S7NFXXG>
and Android
<https://github.com/notifications/mobile/android/BERDKBOOLBBTGAIDLVFEKM35BUTUDA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTINJXGE2DKNRWG42KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2K4ZTPN52GK4S7MFXGI4TPNFSA>.
Download it today!
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Test Results
Module OutputResultPass: The module correctly identified the Ignition version, state, operating system, Java version, and GAN role. |
…ing.md Co-authored-by: Brendan <bwatters@rapid7.com>
bwatters-r7
left a comment
There was a problem hiding this comment.
We updated rubocop rules, and it looks like this got caught. Scanners already print out the ip and port when you call print, so adding them again creates duplicates.
Co-authored-by: Brendan <bwatters@rapid7.com>
Co-authored-by: Brendan <bwatters@rapid7.com>
Applied both, thanks. Good to know the scanner mixin handles the prefix. I'd assumed HttpClient-based scanners needed it manually. Checked opcua_enum on #21612 and it's already clean. |
Test Environment
Session OutputResultThe module successfully detected and reported the Ignition version, state, operating system, Java runtime, and GAN role. |
| } | ||
| ) | ||
| ) | ||
| register_options([Opt::RPORT(8088)]) |
There was a problem hiding this comment.
Same comment/ the HttpClient mixin will register RPORT: #21612 (comment)
There was a problem hiding this comment.
Done - applied the same DefaultOptions pattern here, removed the register_options call. Confirmed RPORT still defaults to 8088.
|
For what it is worth, Github's CI testing is not having a great day. The failing tests are not because of this code, but because of dependency and test setup failures. |
Release NotesAdds an auxiliary scanner module that fingerprints Inductive Automation Ignition |
Resubmission of #21273 with all Copilot review feedback addressed:
Tested against Ignition 7.9.21, 8.1.15, 8.1.17, and 8.3.4 on Linux.