From 229b60eb67e6f8811272a0311e9b23122715c0e6 Mon Sep 17 00:00:00 2001 From: Yunus AYDIN Date: Sun, 14 Jul 2024 16:29:33 +0300 Subject: [PATCH] add captcha bypass and requirements --- main.py | 295 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 43 +++++++ 2 files changed, 338 insertions(+) create mode 100644 main.py create mode 100644 requirements.txt diff --git a/main.py b/main.py new file mode 100644 index 0000000..0d0bade --- /dev/null +++ b/main.py @@ -0,0 +1,295 @@ +import argparse +import os +import time +import random +import requests +import re +from dotenv import load_dotenv +from selenium import webdriver +from selenium.webdriver import ActionChains +from selenium.webdriver.common.by import By +from selenium.webdriver.firefox.service import Service as FirefoxService +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from webdriver_manager.firefox import GeckoDriverManager +from openai import OpenAI + +load_dotenv() +def average_of_array(arr): + if not arr: + return 0 # Handle edge case of empty array + sum_elements = sum(arr) + average = sum_elements / len(arr) + return average - 5 + +def upload_image_to_imgur(image_path): + url = "https://api.imgur.com/3/image" + client_id = os.getenv("IMGUR_CLIENT_ID") + headers = { + "Authorization": f"Client-ID {client_id}" + } + + with open(image_path, "rb") as image_file: + payload = { + "image": image_file.read(), + "type": "file" + } + response = requests.post(url, headers=headers, files=payload) + + if response.status_code == 200: + data = response.json() + return data['data']['link'] + else: + print("Failed to upload image", response.text) + return None + +def ask_recaptcha_to_chatgpt(image_url): + client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) + short_prompt = ("You are an object detection assistant. Understand what is asked on the top instruction of the " + "image. For Example if instruction says select all squares with motorcycle. There are 16 squares " + "give number for each square 0 to 15. The numbers starts from top left to right. Then answer only " + "with the square numbers like 1-3-5-6." + "Understand the instruction and give me the highest probability squares as answer. Give only the correct square numbers.") + response = client.chat.completions.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": short_prompt}, + {"role": "user", "content": image_url} + ], + temperature=1, + max_tokens=256, + top_p=1, + frequency_penalty=0, + presence_penalty=0 + ) + return response.choices[0].message.content + +def ask_text_to_chatgpt(image_url): + client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) + short_prompt = ("Act as a blind person assistant. Read the text from the image and give me only the text answer.") + response = client.chat.completions.create( + model="gpt-4o", + messages=[ + { + "role": "system", + "content": [ + { + "type": "text", + "text": short_prompt + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": image_url + } + }, + { + "type": "text", + "text": "Understand what is asked on the top instruction of the image. Give me the only correct squares with highest probability" + } + ] + }, + ], + temperature=1, + max_tokens=256, + top_p=1, + frequency_penalty=0, + presence_penalty=0 + ) + return response.choices[0].message.content + +def ask_slide_to_chatgpt(image_url): + client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) + short_prompt = ("There is an slider button in the page and there is an empty gray space on puzzle. You should give " + "give me how many pixels should i slide to complete the puzzle. You can simulate the slider for " + "the exact fit before giving the answer.The total width is 210 pixels." + "Give me only number of pixels in integer 50 up to 210 pixels.") + response = client.chat.completions.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": short_prompt}, + {"role": "user", "content": image_url} + ], + temperature=1, + max_tokens=256, + top_p=1, + frequency_penalty=0, + presence_penalty=0 + ) + return response.choices[0].message.content + +def puzzle_test(driver): + driver.get("https://2captcha.com/demo/geetest") + time.sleep(5) + button = WebDriverWait(driver, 10).until( + EC.element_to_be_clickable((By.CLASS_NAME, "geetest_radar_tip")) + ) + button.click() + box = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "geetest_embed")) + ) + time.sleep(1) + box.screenshot('geetest_box.png') + file_url = upload_image_to_imgur('geetest_box.png') + time.sleep(1) + all_results = [] + while True: + slider = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "geetest_slider_button")) + ) + time.sleep(2) + action = ActionChains(driver) + input_string = ask_slide_to_chatgpt(file_url) + numbers = re.findall(r'\d+', input_string) + if numbers: + result = int(numbers[0]) + else: + result = None + if result < 110: + result = 90 + all_results.append(result) + action.click_and_hold(slider).perform() + time.sleep(random.uniform(0.8, 1.2)) + total_offset = average_of_array(all_results) + num_steps = 5 + step_offset = total_offset / num_steps + for _ in range(num_steps): + action.move_by_offset(step_offset, 0).perform() + time.sleep(random.uniform(0.05, 0.1)) + action.release().perform() + +def complicated_text_test(driver): + driver.get("https://2captcha.com/demo/mtcaptcha") + time.sleep(5) + iframe = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.ID, "mtcaptcha-iframe-1")) + ) + iframe.screenshot('captcha_image.png') + file_url = upload_image_to_imgur('captcha_image.png') + print(file_url) + response = ask_text_to_chatgpt(file_url) + + print(response) + driver.switch_to.frame(iframe) + input_field = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "mtcap-noborder.mtcap-inputtext.mtcap-inputtext-custom")) + ) + input_field.send_keys(response) + time.sleep(2) + driver.switch_to.default_content() + submit_button = WebDriverWait(driver, 10).until( + EC.presence_of_element_located( + (By.CLASS_NAME, "_actionsItem_1f3oo_41._buttonPrimary_d46vc_44._button_d46vc_1._buttonMd_d46vc_34")) + ) + submit_button.click() + +def text_test(driver): + driver.get("https://2captcha.com/demo/normal") + time.sleep(5) + captcha_image = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "_captchaImage_rrn3u_9")) + ) + + time.sleep(2) + captcha_image.screenshot('captcha_image.png') + file_url = upload_image_to_imgur('captcha_image.png') + print(file_url) + response = ask_text_to_chatgpt(file_url) + + print(response) + + input_field = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "_inputInner_ws73z_12")) + ) + input_field.send_keys(response) + submit_button = WebDriverWait(driver, 10).until( + EC.presence_of_element_located( + (By.CLASS_NAME, "_actionsItem_1f3oo_41._buttonPrimary_d46vc_44._button_d46vc_1._buttonMd_d46vc_34")) + ) + submit_button.click() + time.sleep(5) + driver.quit() + +def recaptcha_test(driver): + driver.get("https://patrickhlauke.github.io/recaptcha/") + def handle_recaptcha(): + number_of_challenges = 0 + recaptcha_frame = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.XPATH, "//iframe[@title='reCAPTCHA']")) + ) + recaptcha_frame.screenshot('recaptcha_checkbox.png') + driver.switch_to.frame(recaptcha_frame) + checkbox = WebDriverWait(driver, 10).until( + EC.element_to_be_clickable((By.CLASS_NAME, "recaptcha-checkbox-border")) + ) + checkbox.click() + driver.switch_to.default_content() + time.sleep(2) + array = [] + while True: + try: + challenge_iframe = WebDriverWait(driver, 10).until( + EC.presence_of_element_located( + (By.XPATH, "//iframe[contains(@title, 'recaptcha challenge expires in two minutes')]")) + ) + number_of_challenges += 1 + filename = 'recaptcha_challenge_' + str(number_of_challenges) + '.png' + challenge_iframe.screenshot(filename) + image_url = upload_image_to_imgur(filename) + if image_url: + answer = ask_recaptcha_to_chatgpt(image_url) + if "," in answer: + array = answer.split(", ") + elif "-" in answer: + array = answer.split("-") + else: + exit(-1) + driver.switch_to.frame(challenge_iframe) + table = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "rc-imageselect-table-33")) + ) + time.sleep(1) + all_images = table.find_elements(By.CLASS_NAME, "rc-image-tile-33") + for each_element in array: + all_images[int(each_element)].click() + submit_button = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.ID, "recaptcha-verify-button")) + ) + submit_button.click() + driver.switch_to.default_content() + time.sleep(5) + if len(driver.find_elements(By.CLASS_NAME, "recaptcha-checkbox-checkmark")) != 0: + break + except Exception as ex: + print(ex) + handle_recaptcha() + time.sleep(5) + driver.quit() + +def main(): + parser = argparse.ArgumentParser(description="Test various captcha types.") + parser.add_argument('captcha_type', choices=['puzzle', 'text', 'complicated_text', 'recaptcha'], + help="Specify the type of captcha to test") + args = parser.parse_args() + + service = FirefoxService(GeckoDriverManager().install()) + driver = webdriver.Firefox(service=service) + try: + if args.captcha_type == 'puzzle': + puzzle_test(driver) + elif args.captcha_type == 'text': + text_test(driver) + elif args.captcha_type == 'complicated_text': + complicated_text_test(driver) + elif args.captcha_type == 'recaptcha': + recaptcha_test(driver) + finally: + driver.quit() + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b3c4c42 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,43 @@ +annotated-types==0.7.0 +anyio==4.4.0 +attrs==23.2.0 +blinker==1.8.2 +Brotli==1.1.0 +certifi==2024.6.2 +cffi==1.16.0 +charset-normalizer==3.3.2 +cryptography==42.0.8 +distro==1.9.0 +h11==0.14.0 +h2==4.1.0 +hpack==4.0.0 +httpcore==1.0.5 +httpx==0.27.0 +hyperframe==6.0.1 +idna==3.7 +kaitaistruct==0.10 +openai==1.33.0 +outcome==1.3.0.post0 +packaging==24.0 +pillow==10.4.0 +pyasn1==0.6.0 +pycparser==2.22 +pydantic==2.7.3 +pydantic_core==2.18.4 +pyOpenSSL==24.1.0 +pyparsing==3.1.2 +PySocks==1.7.1 +python-dotenv==1.0.1 +requests==2.32.3 +selenium==4.21.0 +selenium-wire==5.1.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +tqdm==4.66.4 +trio==0.25.1 +trio-websocket==0.11.1 +typing_extensions==4.12.2 +urllib3==2.2.1 +webdriver-manager==4.0.1 +wsproto==1.2.0 +zstandard==0.22.0