Defeating DevTools Detection

Bypassing anti-debugging detection techniques when analysing potentially malicious websites, no matter the site.

Defeating DevTools Detection
Photo by Felix Mittermeier / Unsplash

⚠️ LibreWolf currently doesn't have devtools-bypass.patch enabled (the patch required for this to work) ⚠️

I have PR'ed a fix, and hopefully will get merged ASAP. In the meantime you can compile from my LibreWolf fork:

source
LibreWolf - Source Archive

Or alternatively use this patcher I wrote which will modify your existing LibreWolf installation:

librewolf-hotpatcher.py
GitHub Gist: instantly share code, notes, and snippets.

(slightly dangerous)

TL;DR

You can't have a lot of features if you want a catch-all solution, DevTools are inherently pretty detectable, you need a patched browser to bypass.

  1. Download LibreWolf which comes pre-patched.
  2. In the search bar type about:config
  3. Change the following settings:
  • librewolf.console.logging_disabled to true
    • LibreWolf patch which detaches console API
  • librewolf.debugger.force_detach to true
    • LibreWolf patch which force detaches debuggers
  • devtools.toolbox.host to window
    • Defeats common resize detection vector
  • devtools.source-map.client-service.enabled to false
    • Defeats common source mapping detection
  • webgl.disabled to false
    • Optional: Some extra evil sites detect this
  • privacy.resistFingerprinting to false
    • Optional: Some extra evil sites detect this

You should have a fully undetectable browser (although primitive, its a good initial analysis environment). 🎉


Scenario

You're browsing a website, and something is seriously irritating you.

Maybe there's an annoying popup that takes you to a shady site when you click close?

Could be a big annoying window saying "Agree to sell us your soul" (accept cookies).

If you're more technical you probably figure you can just open up DevTools and delete whatever element is annoying you.

You go to open up DevTools and immediately get redirected or even worse your entire page, browser, or even computer crashes. "What? How?" You ask yourself, and go searching for an answer.

Example of a callback which can crash a computer. (don't look at my system time ;-;)


Googling "bypass devtools detection" And How These Solutions Are Still Detected

So you go to search for an answer, and are greeted with thousands of results. Lets take a look at the top 4 search results, each of these, while many good; are still vulnerable to a number of detection vectors due to the nature of how they're designed.

Here's a simple check I made for this article which will detect all of these scripts. This detection follows a similar principle to timing-based detection's when logging a large amount of data using console.table:

function checkTimingDelay() {
  const error = new Error("Error for timing test");
  const start = performance.now();
  for (let i = 0; i < 35000; i++) {
    console.error(i, error.stack);
    // "i" prevents some browsers from folding errors causing it to have to render each time,
    // when devtools are open or "error" is tampered with, it will cause a significant difference in timing
  }
  const end = performance.now();
  return end - start;
}
Default state of our detection

1) Bypass disable-devtool Github Gist

Bypass disable-devtool
Bypass disable-devtool. GitHub Gist: instantly share code, notes, and snippets.

This is often your first search result result. However, if you're being detected by anything other than theajack's disable-devtool this probably wont help.

It is still very good for the specific script it targets, utilizing a clever solution with javascript url's: javascript:DisableDevtool.isSuspend = true

2) Bypass DevTools Detection UserScript

Bypass DevTools Detection
Prevent websites from detecting DevTools (Inspect Element) is open

This is a more recent UserScript, it should bypass most detection's you'll run into. However it will still immediately be detected by our check due to this offending snippet:

// Override console methods to disable traps and weird behaviors
['log', 'debug', 'error', 'info', 'warn'].forEach(method => {
    const originalMethod = console[method];
    console[method] = function(...args) {
        // Skip logging if args include certain trap images or weird data (optional)
        for (const arg of args) {
            if (arg instanceof Image) return;
        }
        return originalMethod.apply(console, args);
    };
});

The modification of the error method leads to a significant delay clearly signifying tampering has occurred.

Tampering detected.
Site functions normally when targeted function isn't being tampered with.

It has a few more detection vectors and mistakes, such as attempting to no-op non existent properties:

// --- Override debugger to noop ---
window.debugger = function() {};

debugger is a reserved keyword; not a property or method of the window object, a typeof check would flag this.

3) Anti-anti debug extension

Anti Anti Debug - Chrome Web Store
Be able to use developer tools again

This popular extension is good, but quite outdated and very vulnerable to a number of modern detection vectors.

Not flagged immediately with install.
Flagged on DevTools open due to significant delay rendering 35k errors.

4) How to prevent websites from detecting the dev console? - Reddit

You may even see Reddit posts, claiming its impossible!

"Conclusion: It is NOT possible. This question has been asked for many years and no solution has yet been found that is not specific to the website." - u/coomerpile (😭)

This isn't true, but a lot of the replies are unhelpful.


A True Solution To Becoming Undetected

You may think its hopeless, how are you even supposed to manually patch a malicious script if you're crashing before you can even add the override? What if its obfuscated and you can't easily override it?

The problem is, we've been fighting on the wrong battlefield. All the solutions we've looked at; extensions and scripts, are trying to patch the problem from the inside. Like trying to stop a leak from inside a submarine with duct tape. The browser itself is telling on you.

Every standard browser (Chrome, Firefox, Safari, ect) is built with developers in mind. APIs such as console are a deeply integrated property of the window object. There's honestly too much to consider when attempting to perfectly mirror the behavior of closed DevTools.

For example, in recent history, a malicious script could define properties on certain objects, and if you opened DevTools, you would be detected.

const err = new Error();
Object.defineProperty(err, 'stack', {
  get() {
    console.log("You're detection. :( ")
  }
});
console.log(err);

https://datadome.co/threat-research/how-new-headless-chrome-the-cdp-signal-are-impacting-bot-detection/

This was finally fixed in d435f290e382f0296f647016cb5d70d54eca3fd8 (April 4, 2024)

However this doesn't by any means mean that this form of attack is closed, this specifically has been solved, but there are still a number of properties that are accessed in such a way that they provide a reliable detection vector.

The only real solution is to use a browser where these "features" are either fundamentally broken or completely ripped out. We need a browser that has been patched before it was even compiled.


LibreWolf Enters

For those unfamiliar, LibreWolf is a fork of Firefox which is hyper-focused on privacy and security. It comes pre-packaged with a bunch of modifications and patches designed to prevent tracking and fingerprinting.

First, go and download it here:

LibreWolf Browser
A custom version of Firefox, focused on privacy, security and freedom.

Configuration

We need to tweak some of LibreWolf's settings. To do this, we'll use Firefox's configuration editor.

In the search bar, type about:config and press Enter. You'll see a warning page. Click "Accept the Risk and Continue"

You're going to want to use the search bar at the top of this page to find and change the following settings.

1) Stop Handling Console API

  • Setting: librewolf.console.logging_disabled
  • Change to: true

This is a custom patch included in LibreWolf that guts the console. It modifies onConsoleAPILogEvent in resource://devtools/server/actors/webconsole/listeners/console-api.js adding this check:

Internally this will act as if there is no handler for a received object from the ConsoleAPIStorage service. In the eyes of the console API this should perfectly mimic the behavior of not having DevTools open at all.

2) Force-Detach Debuggers

  • Setting: librewolf.debugger.force_detach
  • Change to: true

Another LibreWolf-specific patch. It modifies attach in resource://devtools/server/actors/thread.js adding this check:

Internally, this will hit the same early return condition that this.alreadyAttached triggers, blocking all detection vectors from the Debugger tab (another surface for a timing-based side-channel attack) and preventing the debugger keyword from being handled, avoiding all debugger traps.

const start = performance.now();
debugger;
const end = performance.now();
if (end - start > 100) { 
  triggerAntiTamper();
}

Example of a debugger trap.

Phishing webpage malware sample which abuses debugger traps as an anti-analysis technique, redirecting on detection. Credit: https://www.esentire.com/blog/phish-chips-serving-up-tycoon-2fas-secrets

3) Defeat Resize Detection

  • Setting: devtools.toolbox.host
  • Change to: window

One of the oldest tricks in the book. When you open DevTools, it's typically docked to the side or bottom of your browser, which changes the size of the main viewport. Scripts can have a listener that just waits for the window to be resized. If it resizes past a certain threshold instantly, it’s a dead giveaway that DevTools are open.

By changing this setting from side to window, you tell the browser to open DevTools in a completely separate window. This way, the original webpage's viewport size never changes.

4) Defeat Source Mapper

  • Setting: devtools.source-map.client-service.enabled
  • Change to: false

Source maps are supposed to help developers debug minified or transpiled code by mapping it back to the original source. Some anti-devtools scripts work by requesting a non-existent source map file. When you open DevTools, the browser automatically tries to fetch this file, and the website's server logs the request, flagging you instantly. By disabling this, your browser won't try to fetch those files.

Javascript Anti Debugging - Abusing SourceMappingURL
Abusing SourceMappingURL feature can allow attackers to create one of the strongest Cross Browsers Javascript Anti Debugging techniques

Optional Tweaks for Extra Evil Sites

The settings above will get you past anti-DevTools scripts. However, some particularly nasty sites use broad fingerprinting techniques which can cause LibreWolf itself to become detected. Some of LibreWolf's defaults can sometimes be a bit too unique. If you're still having trouble, consider relaxing these two settings.

  • Setting: webgl.disabled
  • Change to: false
    • Why: LibreWolf disables WebGL by default for privacy. However, so few users have it disabled that its absence can be a fingerprint. Enabling it makes you look more like a standard user.
  • Setting: privacy.resistFingerprinting
  • Change to: false
    • Why: This is Firefox's built-in "Tor-Uplift" mode. It standardises many things to make you blend in with other privacy-conscious users. Ironically resisting fingerprinting has become a fingerprint itself. Disabling this can, paradoxically, make you less conspicuous.

Celebrate Being Undetected! 🎉

Test your detection here:

devtools-detector demo

Even our demo cant catch us! 🎉


Contact

If you find a site which manages to avoid all this and still detects your DevTools, I'd love to hear about it, reach out to me at: [email protected]