CAPTCHA bypass (2)
1. 들어가며
(1)번 글에서는 CAPTCHA가 무엇인지, 어떤 종류와 기술이 사용된 것인지 알아봤다.
그리고 우회 기술들을 소개했고 CaptchaCracker를 이용한 머신러닝 방식을 직접 실습해보았다.
저번 글 내용에 이어서 이번에는 나머지 우회 실습 2가지와 우회 방지 방법에 관한 내용이다.
2.2 실습 내용부터 시작한다.
2. CAPTCHA 우회
2.2 실습
2. 웹 크롤링 방식(Selenium 이용)
Selenium은 웹 브라우저를 이용하는 오픈 소스 라이브러리이다.
주로 웹 브라우저 기반의 작업을 자동화시키는 데 사용한다.
Google의 reCAPTCHA v2 버전을 Selenium을 사용한 자동화 프로그램을 이용하여 인증을 완료해
볼 것이다. 테스트를 진행할 reCAPTCHA는 아래 사이트에 있는 것으로 했다.
주로 reCAPTCHA 우회 테스트를 할 때 많이 쓰는 사이트이다.
https://patrickhlauke.github.io/recaptcha/
사이트에 들어가 보면 알 수 있듯이 reCAPTCHA v2는 사용자가 직접 체크 박스를 클릭해야 하고,
자동화 프로그램 사용이 의심되면 이미지 퍼즐을 해결해야 한다.
실습은 크게 나누어 4가지 과정이 있다.
- 자동으로 reCAPTCHA가 있는 웹 페이지에 접속한다.
- reCAPTCHA의 체크박스를 찾아내고 클릭한다.
- 바로 인증이 완료되지 않고 이미지 퍼즐이 나올 경우 확장 프로그램 Buster: Captcha Solver for Humans을 이용해 이미지 퍼즐을 음성 모드로 전환한다. 그리고 확장 프로그램이 음성을 분석하여 문자
데이터로 치환시켜 자동으로 인증을 진행한다. 성공할 때까지 위 과정을 반복한다. - 인증이 완료되면 사이트는 자동으로 닫힌다.
코드 분석
1 | import selenium.common |
- Selenium을 사용하여 웹 브라우저를 자동화하기 위한 기초 단계이다.
Selenium 라이브러리를 미리 설치해야 실습을 진행할 수 있다. 첫 번째로 불러온 selenium.common
모듈은 selenium에서 발생하는 각종 예외 처리에 사용된다. 브라우저의 자동화를 위해 webdriver를 가져온다. Webdriver의 경우 selenium이 Chrome을 제어하기 위해 사용하는 것으로 ChromeDriver.exe 파일을 다운받은 상태여야 한다.
By는 selenium에서 특정 HTML 요소를 찾을 때 사용한다. 특정 요소를 이름, ID, XPath 등으로 찾을 수 있다. WebDriverWait는 특정 조건을 만족할 때까지 일정 시간 동안 대기시키는 데 사용한다.
expected_conditions는 특정 조건을 기다릴 때 사용하는 조건이다. 줄여서 EC라고 하였다.
1 | # 확장 프로그램 폴더 경로 설정 |
- Chrome 브라우저에 확장 프로그램 Buster: Captcha Solver for Humans를 로드하고 실행하는 부분이다. extension_folder에 확장 프로그램이 위치한 폴더의 경로를 입력한다. Chrome 드라이버에
확장 프로그램을 추가하는 옵션을 적용하기 위해 옵션을 설정한다. 그리고 위에서 지정한 확장 프로그램의 경로를 Chrome 웹 드라이버를 실행할 때 자동으로 로드하도록 설정한다.
마지막으로 확장 프로그램과 함께 웹 드라이버를 실행한다.
1 | def bypass_recaptcha(url): |
- bypass_recaptcha 함수에 자동화된 브라우저에서 reCAPTCHA를 해결하는 과정을 나타낸 것이다.
우선 reCAPTCHA가 있는 사이트에 접속한다. 그리고 첫 번째 reCAPTCHA의 iframe이 나올 때까지 최대 10초를 대기한다. 웹 페이지에서 reCAPTCHA 부분은 개발자 모드로 확인을 해보면 iframe으로 감싸져 있는 모습을 볼 수 있다. Selenium을 이용해 내부 요소에 접근해 클릭을 하려면 이 iframe으로 전환을 해야 한다. 해당 iframe이 사용 가능할 때까지 기다린 다음 전환을 한다.
iframe[@title=’reCAPTCHA’]는 reCAPTCHA의 첫 번째 요소가 포함된 부분이다.
체크박스가 클릭이 가능한 상태로 나타날 때까지 최대 10초 동안 대기한다. 클릭이 가능한 상태면 바로 클릭을 한다. XPATH에는 체크박스 부분을 나타낸 것이다.
체크박스를 클릭한 다음 다시 iframe 내부에서 바깥으로 전환해야 한다. 클릭을 한 다음에는 원래 페이지로 돌아가야 하기 때문이다.
만약 이미지 퍼즐 인증 문제가 나온다면 두 번째 iframe이 나타난다. 두 번째 iframe이 사용 가능할 때까지 최대 10초 대기한다. iframe[@title=’recaptcha challenge expires in two minutes’]는 이미지 퍼즐 reCAPTCHA의 iframe이다. 이것을 해결하기 위해 이 iframe으로 전환한다.
1 | while True: |
- bypass_recaptcha 함수 내부이고, 이미지 퍼즐을 자동으로 해결하는 과정이다.
reCAPTCHA의 퍼즐 인증이 성공적으로 해결이 될 때까지 무한 반복하고 해결이 되면 반복문에서 탈출한다. Try 부분은 예외가 발생할 가능성이 있는 코드를 감싸서 문제가 발생했을 때 적절한 처리를 위해 준비하는 부분이다. 최대 3초 동안 클릭이 가능한 상태가 될 때까지 대기한다.
그리고 해당 요소가 클릭이 가능한 상태인지 확인한 다음 클릭한다. XPATH로 지정된 요소는 확장 프로그램에서 이미지를 음성으로 전환하여 문제를 자동으로 해결하기 위한 자동 풀이 버튼이다. Except 부분은 특정 요소를 클릭하려고 시도했지만 다른 요소나 상황으로 인해 클릭할 수 없는 경우 발생하는 예외 부분이다.
이 경우 iframe이 활성화되지 않아 비활성화될 가능성이 커 인증 과정이 끝났다(체크가 이미 되어서 클릭을 못 한다)고 여길 수 있다.
이 예외가 발생할 경우 reCAPTCHA가 성공적으로 해결되었다는 메시지 ‘bypassed’라는 메시지를 출력하고 반복문에서 탈출한다.
1 | def __main__(): |
- 메인 함수이다. 웹 페이지의 URL을 지정하고 bypass_recaptcha 함수를 호출하며 url 값을 전달한다.
그리고 실행한다.
실습에서 사용한 전체 소스 코드는 아래 사이트에 저장해 두었다.
https://github.com/hyemsnail/captcha_project/blob/main/recaptcha_bypass_script.py

- 스크립트 파일, 크롬 드라이버를 저장한 폴더로 이동한 다음 위의 사진처럼 실행시킨다.
성공적으로 해결이 되면 ‘bypassed’라는 텍스트가 나온다.
실행 화면
가장 먼저 웹 페이지로 접속하면 이 모습이 나온다.

reCAPTCHA가 나타난다. 이미지 퍼즐 인증이 나타나지 않을 경우 위의 사진처럼 체크 박스가 뜨고 바로 그것을 클릭하면 인증이 완료된다.

이미지 퍼즐이 나오는 경우이다. 확장 프로그램이 자동으로 음성으로 바꾸는 버튼(헤드폰 모양)을 누른다.

확장 프로그램이 음성을 듣고 그것을 문자로 치환하여 인증을 시도한다.

인증이 완료된 모습이다.
결과 분석
생각보다 훨씬 쉽고 빠르게 reCAPTCHA를 우회하여 인증을 완료한다. 실행은 총 20번 해보았다.
| 테스트 순서 | 걸린 시간(초) | 이미지 퍼즐 여부 | 성공 여부 |
|---|---|---|---|
| 1 | 04.28 | X | O |
| 2 | 07.75 | O | O |
| 3 | 07.22 | O | O |
| 4 | 07.62 | O | O |
| 5 | 07.75 | O | O |
| 6 | 07.77 | O | O |
| 7 | 07.41 | O | O |
| 8 | 07.83 | O | O |
| 9 | 15.86 | O | O |
| 10 | 07.36 | O | O |
| 11 | 07.82 | O | O |
| 12 | 07.62 | O | O |
| 13 | 07.24 | O | O |
| 14 | 06.29 | O | O |
| 15 | 06.68 | O | O |
| 16 | 05.38 | O | O |
| 17 | 06.91 | O | O |
| 18 | 06.24 | O | O |
| 19 | 06.29 | O | O |
| 20 | 06.11 | O | O |
실행하면 대부분 7초 대로 모든 과정이 끝이 난다. 테스트에서 이미지 퍼즐의 등장 여부를 따진 이유는 실행할 때 이미지 퍼즐 과정을 애초에 거치지 않고 바로 인증 완료가 되는 경우도 있기 때문이다. (위 표의 결과들은 2024/11/08에 재실시한 실습을 기준으로 작성한 것이다. 이번 실습에서는 이미지 퍼즐 과정을 거치지 않는 경우는 거의 나타나지 않았다. 하지만 9/26 실습 때는 이미지 퍼즐 과정을 거치지 않고 바로 인증이 되는 경우도 빈번하게 일어났다.) 그리고 실행을 하고 인증을 완료하기까지 걸린 시간도 조금 흥미로운 부분이 있다. 처음에는 분명히 7초대 후반으로 나오던 것이 6초대까지 줄어든 것이다. 물론 서서히 줄어든 것은 아니지만 후반부에 6초대로 계속 나오는 것은 유의미한 차이라고 생각한다. 이런 현상이 일어나는 원인이 무엇인지 조사해 보았다. 가장 가능성이 있다고 생각한 것은 확장 프로그램이 처음 몇 번 실행하는 동안 CAPTCHA의 패턴이나 유형을 학습하여 최적화된 방법을 선택하는 것이다. 하지만 확장 프로그램 Buster: Captcha Solver for Humans는 프로그램은 특정 패턴을 학습하거나 캐싱하는 기능에 관한 언급을 찾아볼 수 없었다. 이 원인이 아니라면, 확장 프로그램이 처음 실행될 때 필요한 리소스나 모듈을 로드하는 과정에서 시간이 조금 더 걸린 것이 아닐까 추정된다.
결론적으로, 이 실습을 통해 reCAPTCHA v2는 보안의 기능으로써 전혀 안전하지 않은 대책이라는 것을 알 수 있었다.
3. 패킷 재전송 방식(Burp Suite 이용)
패킷 재전송 방식은 이미 캡처가 된 패킷을 재전송하여 동일한 요청을 처리하도록 하는 기법이다.
요청(Request), 응답(Response) 과정을 기록한 후, 반복적으로 전송하여 CAPTCHA를 우회한다.
하지만 이 방법은 머신러닝, 웹 크롤링, OCR 방식에 비하면 잘 언급되지도, 쓰지도 않는 방식이다. 왜냐하면 서버에서 동작 값을 요구하거나, 변동되는 데이터에는 유연하게 대응하기 어렵다. 그리고 우회하는 데 걸리는 시간도 다른 방식에 비하면 더 걸리는 편이라 별로 효율적인 방법도 아니다.
실습에서는 DVWA 환경에서 Burp Suite를 이용하여 패킷을 재전송해 CAPTCHA를 우회해 볼 것이다.

- DVWA에서 Security Level을 Impossible에서 Low로 낮춰준다. 그리고 Insecure CAPTCHA로 들어가면 우선 패스워드를 변경하는 기능이 있고, 그러려면 reCAPTCHA를 거쳐야 한다는 사실을 알 수 있다. 새 패스워드 ’minmin’를 입력하고 reCAPTCHA v2로 인증을 한다. 패스워드를 바꿨을 때 전송된 패킷을 확인해 보기 위해 Change를 누르기 전 Burp Suite의 Proxy에서 설정을 Intercept on(off에서 on)으로 바꿔준다. 그다음에 Change 버튼을 누른다.

- Change 버튼을 눌렀을 때 서버로 전송된 패킷을 확인하였다. 패킷을 읽어보고 가장 중요하다고 여겨진 부분은 step으로 시작하는 줄이다.읽어보면 step은 패스워드를 minmin으로 변경 후 reCAPTCHA의 인증 정보와 함께 서버로 전송하는 부분인 것을 알 수 있다. 1은 파라미터로 쓰는 것 같다.
1
step=1&password_new=minmin&password_conf=minmin&g-recaptcha-response=
여기서는 reCAPTCHA 인증이 성공적으로 되었으므로 g-recaptcha-response로 서버에 전송되는 것이다. 그리고 g-recaptcha-response 뒤에 많은 값들이 있는데 이것들은 reCAPTCHA를 확인할 때 무작위로 만들어지는 난수이다.

- Forward를 눌러 바로 다음 과정으로 넘어가면 이 화면이 뜬다. CAPTCHA 인증이 완료되었다는 메시지가 나온다. 바꾼 패스워드를 저장하기 위해 Change 버튼을 누르면 패스워드 변경 과정이 끝이 난다.
요청(Change)이 한 번 더 나오는 관계로 Change 버튼을 누르고 서버로 전달되는 패킷을 확인해 보았다.

- 두 번째 Change 버튼을 눌렀을 때 서버로 전송되는 패킷을 확인해 보았다. 이번에도 가장 중요하게 여겨진 부분은 step으로 시작하는 부분이다.읽어보면 이 부분의 기능은 변경할 패스워드 minmin을 최종적으로 변경하는 역할이다. 앞에 step=1 부분과 다르게 파라미터가 2이다. 2는 CAPTCHA가 인증이 완료되었다는 것을 증명하는 역할로 추정된다.
1
step=2&password_new=minmin&password_conf=minmin&Change=Change
변경할 패스워드 minmin은 step=1 부분에서도, step=2 부분에서도 등장한다. 같은 패스워드로 요청을
2번 보낸다. step=2부분이 패스워드 변경 전 최종 단계이기도 하고 CAPTCHA를 통과했다는 인증도
가지고 있으니 더 중요도가 높아 보였다. 그래서 첫 번째 요청은 생략하고 두 번째 요청만 패스워드를 수정해서 다시 전송하면 CAPTCHA 기능을 우회하여 패스워드를 변경할 수 있겠다는 생각이 들었다.

- 패킷의 step=2부분에서 패스워드 부분만 수정해서 Repeater로 서버에 여러 번 재전송하였다.
패스워드는 minmin에서 minmin_hack으로 바꿨다. 그리고 Repeater 탭으로 전송했다.

- Forward를 눌러 다음 과정으로 진행했다. 패스워드가 변경되었다는 메시지가 뜬다. 이 화면만 봐서는 바뀐 패스워드가 minmin인지 아니면 minmin_hack인지 알 수 없다. 의도한 대로 minmin_hack으로 변경되었는지 확인하기 위해서는 다시 DVWA에 로그인을 해보면 알 수 있다.

- 패스워드가 minmin일 때는 Login Failed라는 결과가 나왔고, minmin_hack일 때는 로그인이 성공적으로 되었다.

- 패스워드 minmin_hack으로 로그인 후 정상적으로 접속이 된 모습이다.
3. CAPTCHA 우회를 방지하려면
1. OTP(One-Time-Password) 사용
CAPTCHA를 포함하여 그 외에 추가적인 인증을 거치도록 한다. 흔히 ‘2단계 인증’이라고도 부른다. 추가적인 인증의 경우 일회성인 OTP(One-Time-Password)가 가장 유용하다. 한번 생성되면 새로운 OTP가 나올 때까지 유효기간이 짧아 이를 해결하는 자동화 프로그램을 개발하기 매우 까다롭다.
그리고 OTP는 주로 사용자의 신뢰할 수 있을 만한 기기로 전달되는 특징이 있다. (ex. SMS, 이메일, 인증 앱 등). 자동화 프로그램이 이 과정을 넘어가기는 매우 어렵고 만약 방법을 개발했다고 하더라도 사용자가 직접 인증하는 것과 비교해서 비효율적이다.
현실적으로 CAPTCHA 우회를 시도하는 행위 자체를 막는 것은 불가능하다. 이런 상황에서 OTP는 CAPTCHA의 앞 또는 뒤에 붙어 자동화 프로그램이 CAPTCHA를 혹시나 통과하더라도 추가 인증에서 실패하게 하거나, 애초에 OTP 인증에서부터 실패하여 CAPTCHA에 진입하지도 못하게 막을 수 있어 가장 효율적인 방법이다. 굳이 단점을 찾자면 사용자 입장에서 조금 번거롭고 귀찮다고 느낄 수 있다.
2. CAPTCHA 유형 변경
한 사이트에서 사용하는 CAPTCHA의 종류를 한가지로 국한하지 않고, 텍스트, 이미지, 오디오 등
다양한 종류의 CAPTCHA를 랜덤하게 번갈아 가면서 사용하는 것이다. 이런 경우 공격자 입장에서 모든 경우를 고려해야 하므로 자동화 프로그램을 이용하기 까다로워진다. 하지만 이후에 공격자가 이를 모두 고려한 프로그램을 만들 수 있기 때문에 새로운 CAPTCHA 버전이나 종류가 나온다면 빠르게 반영하는 것이 좋다.
3. 코드 난독화
난독화로 코드의 가독성을 떨어뜨려 자동화 프로그램이 CAPTCHA를 우회하는 것을 막는 방법이다.
이 방법은 공격자가 코드를 분석하고 그것을 조작하는 것을 어렵게 만든다. 예를 들어 의미가 있는 변수나 함수 이름을 무작위의 다른 문자들로 대체한다.
또, 중요한 문자열을 XOR 등의 방법으로 암호화하고 실행 시에 복호화한다. 이 외에도 CSS를 통해 CAPTCHA를 숨겨진 상태로 로드시켜 봇이 CAPTCHA를 인식하기 어렵게 만들거나, 서버와의 통신을 난독화해 자동화 프로그램이 API 요청을 분석하기 어렵게 만드는 것 등 방법은 여러 가지이다.
4. 참고 문헌
- Cloudflare.(n.d.).캡챠 작동 원리 | 캡챠란?.Cloudflare.https://www.cloudflare.com/ko-kr/learning/bots/how-captchas-work/
- ITWorld.(2016, October 20).ITWorld 용어풀이 | 캡챠(Captcha).ITWorld.https://www.itworld.co.kr/news/99826
- 조금환, 최주섭, & 김형식. (2017). 보안성 및 사용성 측면에서의 CAPTCHA 동향. 정보보호학회지, 27(1), 47-56.
- Gao, H., Wang, W., Fan, Y., Qi, J., & Liu, X. (2014). The robustness of “connecting characters together” CAPTCHAs. Journal of Information Science and Engineering, 30(2), 347–369.
- Gao, H., Wang, W., Qi, J., Wang, X., Liu, X., & Yan, J. (2013, November). The robustness of hollow CAPTCHAs. In Proceedings of the 20th ACM Conference on Computer and Communications Security (CCS ’13) (pp. 1075–1086). ACM. https://doi.org/10.1145/2508859.2516732
- 염지현.(2016, September 20).’사람이 아니무니다’ 캡차(CAPTCHA) 못 읽는 내가 문제?.동아사이언스.https://m.dongascience.com/news.php?idx=16668
- Google 검색 센터. (2018, October 29).reCAPTCHA v3 소개: 봇을 차단하는 새로운 방법.Google.https://developers.google.com/search/blog/2018/10/introducing-recaptcha-v3-new-way-to?hl=ko
- Authme.(2022, March 16).OCR(광학 문자 인식)이란? OCR 인식 기술의 장점과 적용 사례 탐구.Authme.https://authme.com/ko/blog/what-is-ocr/
- 김재환, 김수아, & 김형중. (2015). 특징 분리를 통한 자연 배경을 지닌 글자 기반 CAPTCHA 공격. 정보보호학회논문지, 25(5), 1011–1019
- 정우일.(2021, July 13). CaptchaCracker 보안문자 인식 모델 만들기.정우일 블로그.https://wooiljeong.github.io/python/captcha-cracker/
- WooilJeong.(2021).CaptchaCracker.GitHub.https://github.com/WooilJeong/CaptchaCracker/blob/main/README-ko.md
- BizSpring 블로그.(n.d.). 자동화툴 ‘Selenium’을 이용한 크롤러 구현 및 3사 데이터 획득 방법 안내.BizSpring.https://blog.bizspring.co.kr/%ED%85%8C%ED%81%AC/selenium-%ED%81%AC%EB%A1%A4%EB%9F%AC-%EA%B5%AC%ED%98%84-3%EC%82%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0/
- 앵한.(2024, May 10). Google reCAPTCHA selenium으로 무력화 시켜보기.앵하니의 더 나은 보안.https://aeng-is-young.tistory.com/entry/Google-reCAPTCHA-selenium%EC%9C%BC%EB%A1%9C-%EB%AC%B4%EB%A0%A5%ED%99%94-%EC%8B%9C%EC%BC%9C%EB%B3%B4%EA%B8%B0
- TGGG23.(2020,April 4). [DVWA] insecure CAPTCHA.Two Greedy Guys’ Garage 23.https://tggg23.tistory.com/57
- Wadhwa, M., Prasad, B. K., Ranjan, S., & Kathuria, M. (2020). CAPTCHA bypass and prevention mechanisms: A review. IOSR Journal of Computer Engineering, 22(3, Ser. IV), 23–29.