feat : attempt to bypass bot detection

This commit is contained in:
martin legrand
2025-05-14 21:43:13 +02:00
parent 4739a1377c
commit 201b3de15c
3 changed files with 266 additions and 15 deletions
+71 -12
View File
@@ -62,9 +62,9 @@ def get_chrome_path() -> str:
def get_random_user_agent() -> str: def get_random_user_agent() -> str:
"""Get a random user agent string with associated vendor.""" """Get a random user agent string with associated vendor."""
user_agents = [ user_agents = [
{"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36", "vendor": "Google Inc."}, {"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "vendor": "Google Inc."},
{"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", "vendor": "Apple Inc."}, {"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "vendor": "Apple Inc."},
{"ua": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0", "vendor": ""}, {"ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "vendor": "Google Inc."},
] ]
return random.choice(user_agents) return random.choice(user_agents)
@@ -91,7 +91,7 @@ def bypass_ssl() -> str:
""" """
This is a fallback for stealth mode to bypass SSL verification. Which can fail on some setup. This is a fallback for stealth mode to bypass SSL verification. Which can fail on some setup.
""" """
pretty_print("This is a workaround for SSL issues but upsafe we strongly advice you update your certifi SSL certificate.", color="warning") pretty_print("Bypassing SSL verification issues, we strongly advice you update your certifi SSL certificate.", color="warning")
ssl._create_default_https_context = ssl._create_unverified_context ssl._create_default_https_context = ssl._create_unverified_context
def create_undetected_chromedriver(service, chrome_options) -> webdriver.Chrome: def create_undetected_chromedriver(service, chrome_options) -> webdriver.Chrome:
@@ -107,7 +107,6 @@ def create_undetected_chromedriver(service, chrome_options) -> webdriver.Chrome:
pretty_print(f"Failed to create Chrome driver, fallback failed:\n{str(e)}.", color="failure") pretty_print(f"Failed to create Chrome driver, fallback failed:\n{str(e)}.", color="failure")
raise e raise e
raise e raise e
# hide webdriver flag
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
return driver return driver
@@ -122,16 +121,28 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx
if headless: if headless:
chrome_options.add_argument("--headless") chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--use-gl=swiftshader")
chrome_options.add_argument("--disable-webgl") #chrome_options.add_argument("--disable-gpu")
#chrome_options.add_argument("--disable-webgl") # prevent some website from working, commented for now
user_data_dir = tempfile.mkdtemp() user_data_dir = tempfile.mkdtemp()
user_agent = get_random_user_agent() user_agent = get_random_user_agent()
chrome_options.add_argument(f"--user-data-dir={user_data_dir}") chrome_options.add_argument(f"--user-data-dir={user_data_dir}")
chrome_options.add_argument("--use-gl=egl")
chrome_options.add_argument("--enable-webgl")
chrome_options.add_argument("--enable-3d-apis")
chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--mute-audio") chrome_options.add_argument("--mute-audio")
chrome_options.add_argument("--disable-notifications") chrome_options.add_argument("--disable-notifications")
chrome_options.add_argument("--autoplay-policy=user-gesture-required") chrome_options.add_argument("--autoplay-policy=user-gesture-required")
# Essential WebGL arguments
chrome_options.add_argument("--ignore-gpu-blocklist")
chrome_options.add_argument("--enable-webgl")
chrome_options.add_argument("--enable-webgl-developer-extensions")
chrome_options.add_argument("--enable-webgl-draft-extensions")
chrome_options.add_argument("--disable-webgl-anti-fingerprinting")
chrome_options.add_argument("--allow-webgl-developer-extensions")
chrome_options.add_argument("--font-render-hinting=none")
chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument(f'user-agent={user_agent["ua"]}') chrome_options.add_argument(f'user-agent={user_agent["ua"]}')
resolutions = [(1920, 1080), (1366, 768), (1440, 900)] resolutions = [(1920, 1080), (1366, 768), (1440, 900)]
@@ -154,7 +165,7 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx
stealth(driver, stealth(driver,
languages=["en-US", "en"], languages=["en-US", "en"],
vendor=user_agent["vendor"], vendor=user_agent["vendor"],
platform="Win64" if "Windows" in user_agent["ua"] else "MacIntel" if "Macintosh" in user_agent["ua"] else "Linux x86_64", platform="Win64" if "windows" in user_agent["ua"].lower() else "MacIntel" if "mac" in user_agent["ua"].lower() else "Linux x86_64",
webgl_vendor="Intel Inc.", webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine", renderer="Intel Iris OpenGL Engine",
fix_hairline=True, fix_hairline=True,
@@ -163,7 +174,14 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx
security_prefs = { security_prefs = {
"profile.default_content_setting_values.media_stream": 2, "profile.default_content_setting_values.media_stream": 2,
"profile.default_content_setting_values.geolocation": 2, "profile.default_content_setting_values.geolocation": 2,
"profile.default_content_setting_values.notifications": 2,
"profile.default_content_setting_values.camera": 2,
"profile.default_content_setting_values.microphone": 2,
"safebrowsing.enabled": True, "safebrowsing.enabled": True,
"webkit.webprefs.accelerated_2d_canvas_enabled": True,
"webkit.webprefs.force_dark_mode_enabled": False,
"webkit.webprefs.accelerated_2d_canvas_enabled": True,
"webkit.webprefs.accelerated_2d_canvas_msaa_sample_count": 4,
} }
chrome_options.add_experimental_option("prefs", security_prefs) chrome_options.add_experimental_option("prefs", security_prefs)
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
@@ -184,6 +202,7 @@ class Browser:
except Exception as e: except Exception as e:
raise Exception(f"Failed to initialize browser: {str(e)}") raise Exception(f"Failed to initialize browser: {str(e)}")
self.setup_tabs() self.setup_tabs()
self.patch_browser_fingerprint()
if anticaptcha_manual_install: if anticaptcha_manual_install:
self.load_anticatpcha_manually() self.load_anticatpcha_manually()
@@ -200,6 +219,30 @@ class Browser:
pretty_print("You might want to install the AntiCaptcha extension for captchas.", color="warning") pretty_print("You might want to install the AntiCaptcha extension for captchas.", color="warning")
self.driver.get(self.anticaptcha) self.driver.get(self.anticaptcha)
def human_move(element):
actions = ActionChains(driver)
x_offset = random.randint(-5,5)
for _ in range(random.randint(2,5)):
actions.move_by_offset(x_offset, random.randint(-2,2))
actions.pause(random.uniform(0.1,0.3))
actions.click().perform()
def human_scroll(self):
scroll_pixels = random.randint(200, 800)
scroll_time = random.uniform(0.5, 2.0)
self.driver.execute_script(f"""
window.scrollBy({{
top: {scroll_pixels},
behavior: 'smooth',
duration: {scroll_time}
}});
""")
time.sleep(scroll_time + random.uniform(0.2, 0.5))
def patch_browser_fingerprint(self) -> None:
script = self.load_js("spoofing.js")
self.driver.execute_script(script)
def go_to(self, url:str) -> bool: def go_to(self, url:str) -> bool:
"""Navigate to a specified URL.""" """Navigate to a specified URL."""
time.sleep(random.uniform(0.4, 2.5)) # more human behavior time.sleep(random.uniform(0.4, 2.5)) # more human behavior
@@ -216,7 +259,8 @@ class Browser:
) )
except TimeoutException: except TimeoutException:
self.logger.warning("Timeout while waiting for page to bypass 'checking your browser'") self.logger.warning("Timeout while waiting for page to bypass 'checking your browser'")
self.apply_web_safety() #self.apply_web_safety()
self.human_scroll()
self.logger.log(f"Navigated to: {url}") self.logger.log(f"Navigated to: {url}")
return True return True
except TimeoutException as e: except TimeoutException as e:
@@ -644,12 +688,17 @@ class Browser:
input_elements = self.driver.execute_script(script) input_elements = self.driver.execute_script(script)
if __name__ == "__main__": if __name__ == "__main__":
driver = create_driver(headless=False, stealth_mode=True) driver = create_driver(headless=False, stealth_mode=False)
browser = Browser(driver, anticaptcha_manual_install=True) browser = Browser(driver, anticaptcha_manual_install=False)
input("press enter to continue") input("press enter to continue")
print("AntiCaptcha / Form Test") print("AntiCaptcha / Form Test")
#browser.go_to("https://www.browserscan.net/bot-detection") browser.go_to("https://browserleaks.com/webgl")
time.sleep(20)
browser.go_to("https://bot.sannysoft.com/")
time.sleep(5)
browser.go_to("https://antoinevastel.com/bots/")
time.sleep(5)
#txt = browser.get_text() #txt = browser.get_text()
#browser.go_to("https://www.google.com/recaptcha/api2/demo") #browser.go_to("https://www.google.com/recaptcha/api2/demo")
browser.go_to("https://home.openweathermap.org/users/sign_up") browser.go_to("https://home.openweathermap.org/users/sign_up")
@@ -658,3 +707,13 @@ if __name__ == "__main__":
#inputs_fill = ['[q](checked)', '[q](checked)', '[user[username]](mlg)', '[user[email]](mlg.fcu@gmail.com)', '[user[password]](placeholder_P@ssw0rd123)', '[user[password_confirmation]](placeholder_P@ssw0rd123)'] #inputs_fill = ['[q](checked)', '[q](checked)', '[user[username]](mlg)', '[user[email]](mlg.fcu@gmail.com)', '[user[password]](placeholder_P@ssw0rd123)', '[user[password_confirmation]](placeholder_P@ssw0rd123)']
#browser.fill_form(inputs_fill) #browser.fill_form(inputs_fill)
input("press enter to exit") input("press enter to exit")
# Test sites for browser fingerprinting and captcha
"""
https://nowsecure.nl/ (thanks to user Michael Mintz)
https://bot.sannysoft.com
https://browserleaks.com/
https://bot.incolumitas.com/
https://fingerprintjs.github.io/fingerprintjs/
https://antoinevastel.com/bots/
"""
+1 -3
View File
@@ -21,7 +21,5 @@ window.fetch = function() {
console.log('Blocked fetch request'); console.log('Blocked fetch request');
return Promise.reject('Blocked'); return Promise.reject('Blocked');
}; };
// Block annoying dialogs
window.alert = function() {};
window.confirm = function() { return false; };
window.prompt = function() { return null; }; window.prompt = function() { return null; };
+194
View File
@@ -0,0 +1,194 @@
// Core automation masking
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
Object.keys(window).forEach((key) => {
if (key.includes("webdriver") || key.includes("selenium") || key.includes("driver")) {
delete window[key];
}
});
// Forceful chrome object spoofing
try {
Object.defineProperty(window, 'chrome', {
writable: true,
configurable: true,
value: {
app: {isInstalled: false},
webstore: {onInstallStageChanged: {}, onDownloadProgress: {}},
runtime: {
PlatformOs: {MAC: 'mac', WIN: 'win', ANDROID: 'android'},
PlatformArch: {ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64'},
PlatformNaclArch: {ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64'},
RequestUpdateCheckStatus: {
THROTTLED: 'throttled',
NO_UPDATE: 'no_update',
UPDATE_AVAILABLE: 'update_available'
},
OnInstalledReason: {
INSTALL: 'install',
UPDATE: 'update',
SHARED_MODULE_UPDATE: 'shared_module_update'
},
OnRestartRequiredReason: {
APP_UPDATE: 'app_update',
OS_UPDATE: 'os_update',
PERIODIC: 'periodic'
}
}
}
});
} catch (e) {
console.log("Error in defining window.chrome: ", e);
// Fallback: direct assignment
window.chrome = window.chrome || {};
window.chrome.app = {isInstalled: false};
window.chrome.webstore = {onInstallStageChanged: {}, onDownloadProgress: {}};
}
// Randomize plugins
const pluginsList = [
{type: 'application/x-google-chrome-pdf', description: 'Portable Document Format', filename: 'internal-pdf-viewer', name: 'Chrome PDF Plugin'},
{type: 'application/x-nacl', description: 'Native Client Executable', filename: 'internal-nacl-plugin', name: 'Native Client'},
{type: 'application/x-ppapi-widevine-cdm', description: 'Widevine Content Decryption Module', filename: 'widevinecdm', name: 'Widevine CDM'}
];
Object.defineProperty(navigator, 'plugins', {
get: () => pluginsList.slice(0, Math.floor(Math.random() * pluginsList.length) + 1)
});
// Font spoofing with randomized font list
const fontList = ['Arial', 'Helvetica', 'Times New Roman', 'Courier New', 'Verdana'];
Object.defineProperty(document, 'fonts', {
value: {
add: function() {},
check: function(font) { return fontList.includes(font.split(' ').slice(-1)[0]); },
delete: function() {},
forEach: function(cb) { fontList.forEach(f => cb(f)); },
has: function(font) { return fontList.includes(font.split(' ').slice(-1)[0]); },
keys: function() { return fontList; },
size: fontList.length
}
});
// Canvas fingerprint spoofing
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function() {
const ctx = this.getContext('2d');
ctx.fillStyle = `rgba(${Math.random() * 10},${Math.random() * 10},${Math.random() * 10},0.01)`;
ctx.fillRect(0, 0, 1, 1);
return originalToDataURL.apply(this, arguments);
};
// Screen resolution spoofing
const resolutions = [[1920, 1080], [1366, 768], [1440, 900]];
const [w, h] = resolutions[Math.floor(Math.random() * resolutions.length)];
Object.defineProperty(window, 'screen', {
value: {
width: w,
height: h,
availWidth: w,
availHeight: h - 50,
colorDepth: 24,
pixelDepth: 24
}
});
// Timezone and language spoofing
Object.defineProperty(navigator, 'language', {get: () => 'en-US'});
Intl.DateTimeFormat = function() {
return {resolvedOptions: () => ({timeZone: 'America/New_York'})};
};
// AudioContext spoofing
const originalCreate = window.AudioContext || window.webkitAudioContext;
window.AudioContext = window.webkitAudioContext = function() {
const context = new originalCreate();
const dest = context.createAnalyser();
dest.fake = true;
return context;
};
// WebRTC spoofing
Object.defineProperty(navigator, 'mediaDevices', {
get: () => undefined
});
Object.defineProperty(navigator, 'getUserMedia', {
get: () => undefined
});
// web gl spoofing
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(parameter) {
// Common WebGL parameters
const params = {
37445: 'Intel Open Source Technology Center', // VENDOR
37446: 'Mesa DRI Intel® HD Graphics 4000', // RENDERER
34076: 'WebKit WebGL', // SHADING_LANGUAGE_VERSION
35661: '2.1 INTEL-16.4.5', // VERSION
36349: 'Intel Inc.' // UNMASKED_VENDOR_WEBGL
};
return params[parameter] || getParameter.call(this, parameter);
};
// Performance API spoofing
if ('performance' in window) {
Object.defineProperty(performance, 'memory', {
value: {
jsHeapSizeLimit: 4294705152,
totalJSHeapSize: 78365432,
usedJSHeapSize: 46543210
},
configurable: true
});
}
// Battery API spoofing
if ('getBattery' in navigator) {
Object.defineProperty(navigator, 'getBattery', {
value: () => Promise.resolve({
level: 0.85,
charging: true,
chargingTime: 1800,
dischargingTime: Infinity,
onchargingchange: null,
onchargingtimechange: null,
ondischargingtimechange: null,
onlevelchange: null
}),
configurable: true
});
}
window.RTCPeerConnection = undefined;
window.webkitRTCPeerConnection = undefined;
window.mozRTCPeerConnection = undefined;
Object.defineProperty(navigator, 'permissions', {
value: {
query: () => Promise.resolve({ state: 'denied' })
}
});
Object.defineProperty(navigator, 'languages', {
get: () => ['en-US', 'en'],
});
try {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
Object.defineProperty(WebGLRenderingContext.prototype, 'getParameter', {
value: function(parameter) {
if (parameter === 37445) { // UNMASKED_VENDOR_WEBGL
return 'Intel Inc.';
}
if (parameter === 37446) { // UNMASKED_RENDERER_WEBGL
return 'Intel Iris OpenGL Engine';
}
return this.__proto__.getParameter(parameter);
}
});
}
} catch(e) {}