Bypass Clawptcha - a captcha that verifies you're not a human
// ==UserScript== // @name Clawptcha bypasser // @name:zh-CN Clawptcha 验证绕过 // @name:zh-TW Clawptcha 驗證繞過 // @namespace https://greasyfork.org/users/667968-pyudng // @version 1.1 // @description Bypass Clawptcha - a captcha that verifies you're not a human // @description:zh-CN 绕过 Clawptcha - 一种验证您不是人类的验证码 // @description:zh-TW 繞過 Clawptcha - 一種驗證您不是人類的驗證碼 // @author PY-DNG // @license MIT // @homepageURL https://greasyfork.org/scripts/565015 // @supportURL https://greasyfork.org/scripts/565015/feedback // @match https://clawptcha.com/* // @require https://update.greasyfork.org/scripts/456034/1651347/Basic%20Functions%20%28For%20userscripts%29.js // @require https://cdn.jsdelivr.net/npm/[email protected]/src/sha256.min.js // @icon https://clawptcha.com/favicon.svg // @grant none // ==/UserScript== !async function() { detectDom({ selector: '#challenge-popup > #challenge-content, .clawptcha-challenge-popup .clawptcha-challenge-content', /** * @param {HTMLDivElement} container */ callback(container) { // 验证类型:Hash Computation detectDom({ root: container, selector: '#hash-submit', /** * @param {HTMLButtonElement} btnSubmit 提交答案的按钮 */ async callback(btnSubmit) { // 当存在"Generate"按钮时自动点击 $(container, '#hash-start')?.click(); /** @type {HTMLDivElement} 包含了需计算Hash的原始文本的div */ const divHash = await detectDom(container, '.hash-display, .clawptcha-hash-display'); await detectElement(divHash, divHash => divHash.innerText.includes('Hash this:') || divHash.innerText.includes('Hash:'), { childList: true }); /** @type {HTMLDivElement} */ const text = divHash.innerText.replace('Hash this:', '').replace('Hash:', '').trim(); /** @type {string} */ const hash = sha256(text).substring(0, 16); $(container, '#hash-answer').value = hash; btnSubmit.click(); } }); // 验证类型:Reaction Time detectDom({ root: container, selector: '#reaction-target, #reaction-start', /** * @param {HTMLButtonElement} button 需尽快点击的按钮 */ callback(button) { button.click(); } }); // 验证类型:Precision Timing // 注:这种类型验证可能失败 —— 因为即使是bot,也难以在±1ms的精度上完成点击 // **这是设计的不合理而不是我们的能力不达标** detectDom({ root: container, selector: '#timing-start', /** * @param {HTMLButtonElement} btnStart 开始按钮 */ callback(btnStart) { const btnTiming = $(container, '#timing-click'); btnStart.click(); setTimeout(() => btnTiming.click(), 5000); } }); // 验证类型:Crypto Chain detectDom({ root: container, selector: '#crypto-input', /** * @param {HTMLDivElement} divHash 包含了需计算Hash的原始文本的div */ async callback(divHash) { // 当存在"Start"按钮时自动点击 $(container, '#crypto-start')?.click(); await detectElement(divHash, divHash => divHash.innerText.includes('Hash:'), { childList: true }); // 连续完成3次哈希计算 let counter = 0; const observer = new MutationObserver(submit); observer.observe(divHash, { childList: true, }); submit(); function submit() { if (++counter >= 3) observer.disconnect(); /** @type {HTMLDivElement} */ const text = divHash.innerText.replace('Hash:', '').trim(); /** @type {string} */ const hash = sha256(text); $(container, '#crypto-answer').value = hash; $(container, '#crypto-submit').click(); } } }); // 验证类型:Prime Factorization detectDom({ root: container, selector: '#prime-submit', /** * @param {HTMLButtonElement} btnSubmit 提交答案的按钮 */ async callback(btnSubmit) { /** @type {HTMLDivElement} 包含了需分解质因数的数值的div */ const divHash = $(container, '.hash-display, .clawptcha-prime-display'); // 当从API加载验证码时,需要等待验证码加载完毕 if (!/\d+/.test(divHash.innerText)) { const { promise, resolve } = Promise.withResolvers(); const observer = new MutationObserver(() => { if (/\d+/.test(divHash.innerText)) { resolve(); observer.disconnect(); } }); observer.observe(divHash, { childList: true }); await promise; } // 分解质因数 /** @type {HTMLDivElement} */ const text = divHash.innerText.replace('Find the prime factors of', '').trim(); /** @type {number} 需分解质因数的数值 */ const number = parseInt(text, 10); const { prime1, prime2 } = primeFactorization(number); // 提交结果 $(container, '#prime-answer').value = `${prime1},${prime2}`; btnSubmit.click(); /** * 简单分解质因数 * @param {number} number 一个由两个质数相乘得到的合数 * @returns {{prime1: number, prime2: number}} 分解结果 */ function primeFactorization(number) { for (let i = 2; i <= Math.sqrt(number); i++) { if (number % i === 0) { return { prime1: i, prime2: number / i }; } } return { prime1: 1, prime2: number }; } } }); } }); /** * 类似{@link detectDom},监听元素变化并在给定条件符合时resolve * @template {HTMLElement} T * @param {T} element 需要监听的HTML元素 * @param {(element: T) => boolean} condition 判断元素当前是否符合条件的无副作用的方法 * @param {MutationObserverInit} options * @returns {Promise<T>} */ function detectElement(element, condition, options) { const { promise, resolve } = Promise.withResolvers(); const verify = () => { if (condition(element)) { resolve(element); observer.disconnect(); } }; const observer = new MutationObserver(verify); observer.observe(element, options); verify(); return promise; } } ();