앵하니의 더 나은 보안

Google reCAPTCHA selenium으로 무력화 시켜보기 본문

보안 기술/WEB

Google reCAPTCHA selenium으로 무력화 시켜보기

앵한 2024. 5. 10. 15:57

서론

특정 웹서비스에서 휴대폰 등록기능을 단순히 reCAPTCHA 봇 기능만으로 사람인지 아닌지 판단하는,
마치 손안대고 코푸려는 행태에 분노가 일어 reCAPTCHA에 대한 인증 우회를 진행하는 크롤러를 만들어보았다.

어떤원리로 reCAPTCHA 퍼즐을 풀 수 있고, 어떻게 selenium을 사용했는지 소개하겠다.

 

본론

우선 reCAPTCHA에 대한 퍼즐 검증은 크롬 확장프로그램 Buster: Captcha Solver for Humans를 통해 할 수 있다.

Buster: Captcha Solver for Humans를 통한 우회 원리는 다음과 같다.

  1. 그림을 선택하는 캡챠가 노출되면, 음성 캡챠로 모드를 전환
  2. 음성 데이터를 확인 후, 해당 데이터를 Buster: Captcha Solver for Humans 확장프로그램이 분석하여
    문자 데이터로 치환
  3. 치환한 문자를 입력, Captcha에 대한 인증을 자동으로 진행
  4. 만약 음성과 문자 값이 동일하지 않아 검증이 실패할 경우 다시 클릭하여 위 과정을 반복

Buster: Captcha Solver for Humans가 정상 동작했을 경우

 

실패할 경우 오른쪽아래 팝업표시 됨 그러면 그냥 사람 체크 버튼 다시 클릭하면 됨

 

그래서 이 훌륭한 확장프로그램을 잘 쓰기만 하면되는데 왜 그렇게 오래걸렸냐?

  1. selenium 크롬 드라이버에 Buster: Captcha Solver for Humans 확장프로그램을 실어야함
    근데 확장프로그램을 selenium 크롬 드라이버에 실으려니 인터넷에 흔하게 나와있는대로는 안돼서
    결국 셀레니움 공식 문서까지 뒤져봄

    chrome driver에 Buster: Captcha Solver for Humans를 싣는 방법이 궁금하다면?
    더보기
    1. 확장 프로그램 다운로드 후, 확장프로그램 관리탭으로 들어가(chrome://extensions/) 개발자모드 체크,
    압축하고자 하는 확장 프로그램의 ID 확인 후 확장 프로그램 압축 클릭

    2. 확장 프로그램 압축 클릭 시 표시되는 팝업에서 ‘찾아보기’ 클릭 후 압축하고자 하는
    확장프로그램의 루트 경로 선택 확장프로그램의 루트 경로는 통상적으로
    C:\Users\[사용자명]\AppData\Local\Google\Chrome\User Data\Default\Extensions\[확장프로그램 ID]

    3. 압축한 확장 프로그램 파일(crx) 확인

    4. 해당 확장프로그램 압축파일(crx)을 ChromeOptions로 탑재
    (파이썬 파일 실행 경로와 동일한 경로로 두어, os로 상대경로로 호출)
    import os

    folderPath = os.path.dirname(os.path.realpath(__file__))
    packed_extension_path = folderPath + '/2.0.1_0.crx'
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_extension(packed_extension_path)
    driver = webdriver.Chrome(options=chrome_options)

    이러면 크롬 드라이버에 확장프로그램 세팅 완.
  2. 과거 사용했던 selenium이랑 너무 많이 바뀌어서 적응기가 필요했음(element가 로드될때까지 기다리는 함수가 바뀌었다던지, element를 찾을때 사용하는 함수가 바꼈다던지… 등등)

  3. selenium에서 특정 버튼을 클릭하려면 chrome driver DOM에서 해당 버튼을 가리키는 요소(element)를 찾아야되는데, 이 요소는 XPATH나 CSS Selector같은 애들로 찾을 수 있도록 만들어짐. 그래 내가 작성한 XPATH 경로가 내가 원하는 element를 정확히 찾는지 판단하기 어려웠음
    과거에는 그냥 크롬 개발자도구 소스탭에서 특정 버튼 가리키는 소스에 마우스올려 “xpath 카피 딸깍”
    하면 됐는데, 이건 그런 구조로 찾게하려니, 그렇게 만든 코드는 범용적으로 사용할 수 없었음.
    그래서 어떤 사이트에서도 reCAPTCHA 요소를 찾아주는 XPATH를 작성하는법을 배워야했음
    그래서 XPATH 작성법을 대략적으로 파악하고, 내가 원하는 요소를 제대로 가리키는 XPATH를 작성한게 맞는지
    https://www.toolnb.com/tools-lang-ko/xpath.html  사이트에서 테스트를 진행

  4. driver에서 클릭하고자 하는 element를 찾은 뒤 해당 element를 클릭하는 동작을 수행해야 하는데,
    클릭 버튼이 iframe 태그 내에 위치하는 경우 driver 객체를 해당 iframe에 focus한 뒤
    클릭 버튼 element를 찾아 클릭 동작을 수행해줘야 함
  5. 만약 iframe에 대한 클릭 수행이 끝나고, 그 후 동작을 또 다시 진행하려면
    focus됐던 iframe의 밖, 본래의 영역으로 돌아와줘야 함

위 4번 5번을 몰라서 chrome driver가 iframe위에 있는 element를 찾게하는데에만 이틀이 걸림

그러니까 저 체크박스를 클릭하려면 chrome driver에서 저 iframe으로 switch 해 준후, 체크박스 element를 찾고, 찾은 element를 click 시켜야했던것.

 

그래서 위 시행착오를 겪어서 나온 결과물은 아래 코드다.
각 코드에 주석을 달아놨으니 이해에 도움이 되길바란다..☆

import selenium.common
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os

folderPath = os.path.dirname(os.path.realpath(__file__))
packed_extension_path = folderPath + '/2.0.1_0.crx'
chrome_options = webdriver.ChromeOptions()
chrome_options.add_extension(packed_extension_path)
driver = webdriver.Chrome(options=chrome_options)
#여기 까지가 확장프로그램 및 chrome driver 세팅

def bypass_recaptcha(url):
    driver.get(url)
    #bypass_recaptcha 함수 호출하며 전달된 url 값을 get으로 chrome driver에 로드

    WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[@title='reCAPTCHA']")))
    #chrome driver에서 reCAPTCHA iframe 확인 후 해당 iframe으로 switch

    WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//span[@class='recaptcha-checkbox goog-inline-block recaptcha-checkbox-unchecked rc-anchor-checkbox']/div[@class='recaptcha-checkbox-border']"))).click()
    #체크박스 클릭 가능할때까지 최대 10초까지 대기 한 후 체크박스 클릭

    driver.switch_to.default_content()
    #클릭 후 원래 iframe 밖의 요소로 switch

    WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[@title='recaptcha challenge expires in two minutes']")))
    #다시 그림 인증 캡챠 iframe으로 switch

    while True:
    #Burst:Captcha Solver for Humans 인증 실패했을때를 대비해 반복적인 클릭을 위해 무한반복문 사용
        try:
            WebDriverWait(driver,3).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='button-holder help-button-holder']"))).click()
            #captcha 퍼즐 자동 풀이 버튼 클릭
        except selenium.common.exceptions.StaleElementReferenceException:
            #만약 StaleElementReferenceException에러 즉, 찾을 수 없다면
            pass
            #이미 클릭 중인 상태인 것이니 pass
        except selenium.common.exceptions.ElementClickInterceptedException:
            #만약 ElementClickInterceptedException에러 즉, 모종의 이유로 클릭할 수 없는 상태라면 해당 iframe이 비활성화 된 것이니 체크 완료된 것.
            print("bypassed")
            break
            #그러므로 reCAPTCHA 퍼즐인증이 수행완료됐고, 완료 됐으니 무한반복문 탈출

def __main__():
    url = 'https://patrickhlauke.github.io/recaptcha/'
    bypass_recaptcha(url)

__main__()

 

참고 첨부파일

recaptcha_bypass.zip
0.59MB

'보안 기술 > WEB' 카테고리의 다른 글

Content-Type : application/json에서의 XSS  (0) 2024.05.10
HttpOnly와 XST(Cross-Site Tracing)  (0) 2024.05.10
CSRF 취약점의 현태  (0) 2024.05.10
REST API 환경 웹 서버에서의 기존 취약점 탐구  (1) 2024.02.06
TLS 1.3  (0) 2023.11.05
Comments