Investigating the Selenium Chrome mode of Open Bullet 2

This is the fourth article of the series about Open Bullet 2. In the previous article, we studied the Puppeteer mode of Open Bullet. We showed that Open Bullet 2 relies on PuppeteerExtraSharp, which can be detected because of inconsistencies, such as device signals that are different in a web worker compared to the main JS execution context

In this article, we focus on the Selenium Chrome mode of Open Bullet 2. We create a simple bot based on it to study its fingerprint and see how it can be detected.

Creating a Selenium-Chrome-based bot in Open Bullet 2

First, we need to set the Chrome path for Selenium in the RuriLib Settings panel, cf the screenshot below.

Then, we create a new configuration and edit it using the Stacker panel. The configuration looks as follows:

Our Selenium-Chrome-based bot does the following:

  1. Create a browser instance using the Selenium function block;
  1. Navigate to https://deviceandbrowserinfo.com/are_you_a_bot;
  1. We wait 2s;
  1. Get the value of window.fingerprint using the Execute JS block;
  1. Get the value of the bot detection using the Execute JS block;
  1. Close the browser instance.

We see that by default, Open Bullet 2 used with Selenium Chrome (headless) is properly detected as a bot.

{
  "isBot": true,
  "details": {
    "hasBotUserAgent": true,
    "hasWebdriverTrue": true,
    "hasWebdriverInFrameTrue": true,
    "hasInconsistentChromeObject": false,
    "isPhantom": false,
    "isNightmare": false,
    "isSequentum": false,
    "isSeleniumChromeDefault": false,
    "isHeadlessChrome": false,
    "isWebGLInconsistent": false,
    "isAutomatedWithCDP": true,
    "isAutomatedWithCDPInWebWorker": false,
    "hasInconsistentClientHints": false,
    "hasInconsistentGPUFeatures": false,
    "isIframeOverridden": false,
    "hasInconsistentWorkerValues": false
  }
}

Open bullet is detected for several reasons:

  • By default, the user agent is the one of headless Chrome: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/127.0.6533.119 Safari/537.36 ;
  • We observe the presencenavigator.webdriver = true ;

Note that we could have made our Selenium Chrome bot non-headless, which would have avoid the user agent detection, but wouldn’t have impacted the other signals.

Can we make the bot stealthier?

In a previous article, we already discussed how we can adapt a vanilla Selenium Chrome to make it more difficult to detect. In particular, here we’d like to modify it to:

  • Get rid of the Headless Chrome user agent;
  • navigator.webdriver = true

The usual way to change the user agent is to provide the --user-agent= flag when starting Chrome. Regarding navigator.webdriver , we can disable it using the --disable-blink-features=AutomationControlled flag.

Open Bullet 2 provides two mechanisms to provide arguments to the browser:

  1. In the Config settings panel, cf screenshot below, where there is a Command line arguments option.
  1. In Extra Cmd Line Args of the Open Browser block.

None of these solutions worked. It seems that Open Bullet 2 doesn’t handle the command line arguments string properly, cf below where we see that the two flags are inserted into the user agent. Note that I tried with/without quotes, escaping characters, etc. None of the options worked.

{
	"userAgent":"testuseragent --disable-blink-features=AutomationControlled",
	"platform":"MacIntel",
	...
}

I think there might be a bug in the way Open Bullet 2 handles these additional command line arguments. If we look at the .NET code that handle the command line arguments, we see the following:

It passes the args string to chromeop.AddArgument . I’m not a .NET expert, but according to Claude Sonnet (LLM), “The AddArgument method is used to add a single command-line argument to the ChromeOptions object.”

However, here, we’re trying to add ≥ 2 arguments:

  1. The first to change the user agent;
  1. The second to remove navigator.webdriver = true .

Another possibility could be to change the user agent and remove navigator.webdriver from JavaScript. However, it may have detectable side effects, and I decided not to pursue in this direction. At some point, certain changes to avoid detection are to cumbersome to do from Open Bullet 2 and require access to the code of the underlying framework (here Selenium).

Similarly, it would have been difficult/cumbersome to lie about the CDP detection.

Conclusion

Contrary to the puppeteer mode of Open Bullet 2 that relies on PuppeteerExtraSharp, a modified version of Puppeteer, the Selenium mode uses the vanilla Selenium library, which doesn’t have any anti-detect feature.

Thus, when used in Headless mode with Selenium, Open Bullet 2 can be easily detected using a wide range of techniques, such as the detection of navigator.webdriver = true and the side effects of the CDP automation.

Other recommended articles

Investigating the Puppeteer mode of Open Bullet 2 (credential stuffing tool)

Third article of a series about Open Bullet 2, a credential stuffing tool. We analyze the the Puppeteer mode to better understand how it works, its browser fingerprint, and how it can be detected.

Read more

Published on: 08-08-2024

Privacy leak: detecting anti-canvas fingerprinting browser extensions

In this article, we present 2 approaches that can be used to detect anti-canvas fingerprinting countermeasures and we discuss the potential consequences in terms of privacy for their users.

Read more

Published on: 29-06-2024

Fraud detection: how to detect if a user lied about its OS and infer its real OS?

In this article, we explain how we explain how you can detect that a user lied about the real nature of its OS by modifying its user agent. We provide different techniques that enable you to retrieve the real nature of the OS using JavaScript APIs such as WebGL and getHighEntropyValues.

Read more

Published on: 11-06-2024