Skip to content

Add detect_media_devices browser module#3565

Open
sethumadh wants to merge 1 commit into
beefproject:masterfrom
sethumadh:feature/3542-detect-media-devices
Open

Add detect_media_devices browser module#3565
sethumadh wants to merge 1 commit into
beefproject:masterfrom
sethumadh:feature/3542-detect-media-devices

Conversation

@sethumadh
Copy link
Copy Markdown

@sethumadh sethumadh commented May 14, 2026

Category

Module

Feature/Issue Description

Q: Please give a brief summary of your feature/fix
A: Adds a new browser-side recon module, Detect Media Devices, wrapping navigator.mediaDevices.enumerateDevices() to enumerate the hooked browser's microphones, cameras, and speakers. Fully passive — no permission prompt, no device opened, camera/mic indicator stays off. Returns counts unconditionally; labels appear post-permission. Closes #3542 (raised by @bcoles).

Q: Give a technical rundown of what you have changed (if applicable)
A: Three new files in the standard 3-file module pattern (command.js / module.rb / config.yaml), templated after modules/browser/detect_lastpass/. command.js calls enumerateDevices(), groups results by kind, and POSTs via beef.net.send. Missing-API and exception paths report via beef.status.error(). module.rb stores six form-body keys into @datastore and saves them. No new dependencies; rubocop clean.

Two design notes:

  1. Multi-key form body, not a single JSON value. BeEF's display layer (core/main/handlers/commands.rb:83) wraps every result body under a 'data': key. A URL-encoded JSON blob renders as %7B%22audioinput%22... — unreadable. Switched to audioinput_count=...&audioinput_labels=... (one key per data point), matching webcam_html5's multi-key pattern.

  2. Permission-state insight in the count. Pre-permission, enumerateDevices() returns one placeholder per kind that exists; post-permission, the full inventory. So the count alone is a permission-state signal, independent of labels — a 1 → many jump between executions indicates the origin gained media consent. There's also a vendor signal in the pre-permission shape: Chrome lists all 3 kinds, while Firefox 115+ and Safari 14+ list only 2 (no audiooutput), per Mozilla Bug #1528042. Both are spec-compliant under W3C Media Capture and Streams. See the first comment on this PR for the detailed cross-browser write-up (intended wiki content per CONTRIBUTING.md step 9).

Test Cases

Q: Describe your test cases, what you have covered and if there are any use cases that still need addressing.
A: Tested manually on macOS against BeEF's /demos/basic.html hooked demo page. Screenshots inline below.
chrome-post-permission
chrome-pre-permission
firefox-post-permission
firefox-pre-permission
safari-post-permission
safari-pre-permission

Browser Pre-permission Post-permission
Chrome (latest) 3 entries: 1/1/1, empty labels 10 entries: (Built-in) / (Virtual) / (Aggregate) suffixes
Firefox 115+ 2 entries: 1/0/1 (no audiooutput) 9 entries: plain labels, Default audiooutput deduped
Safari 14+ 2 entries: 1/0/1 (matches Firefox) 10 entries: Default - <device> audiooutput prefix; surfaces Continuity Camera Desk View

Manual reproduction (5 steps):

  1. Load http://<beef>:3000/demos/basic.html to hook a browser.
  2. Admin panel → hooked browser → Commands → Browser → Detect Media Devices → Execute. Observe the pre-permission result in Module Results History.
  3. In a DevTools console on the hooked tab, run navigator.mediaDevices.getUserMedia({audio:true, video:true}).then(s => s.getTracks().forEach(t => t.stop())) and click Allow. Tracks stop immediately; camera light does not persist.
  4. Re-Execute the module and observe the post-permission result.

Wiki Page

See the first comment on this PR for the wiki page draft — operator-facing cross-browser behavior reference with primary-source citations. Posted as a PR comment per CONTRIBUTING.md step 9, since external contributors don't have wiki edit rights.


Closes #3542

Implements navigator.mediaDevices.enumerateDevices() detection.
Groups results by kind (audioinput, audiooutput, videoinput) and
returns counts unconditionally + labels when permissions allow.
Handles the no-API case explicitly via beef.status.error().

Closes beefproject#3542
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

Successfully merging this pull request may close these issues.

Browser Details: Detect media devices

1 participant