본문 바로가기

프로젝트/DVWA 실습

DVWA 실습 #7-3 - Insecure CAPTCHA(high)

2021/01/14 - [프로젝트/DVWA 실습] - DVWA 실습 #7 - Insecure CAPTCHA

 

DVWA 실습 #7 - Insecure CAPTCHA

DVWA의 여섯 번째 실습 대상인 Insecure CAPTCHA다. 현재 문제에서는 CAPTCHA를 이용하여 비밀번호 변경 기능을 다른 프로그램이 공격하지 못하도록 방어하고 있다. 이 잘못 적용된 CAPTCHA 시스템을 악용

haruhiism.tistory.com

문제 해결 방법

이번 단계부터는 비밀번호 변경 과정이 하나로 통합되고 CSRF 토큰 같은 user_token 파라미터가 전달된다. 불필요하게 분할된 과정을 하나로 합치고 CAPTCHA 뿐 아니라 CSRF 토큰을 이용하여 추가적으로 인증하고 있는 것이다.

그래서 이전처럼 step 항목 값을 바꾸거나 심지어 삭제해도 비밀번호 변경에는 아무런 영향이 없다. CAPTCHA를 수행하지 않으면 "The CAPTCHA was incorrect. Please try again." 이라는 메시지와 함께 요청이 거부된다. 그렇다면 이를 어떻게 우회할 수 있을까? 소스 코드를 살펴보니 다음처럼 DEV_NOTE라는 개발자가 작성한 듯한 주석 문이 남아있는 것을 볼 수 있었다.

Response 값이 'hidd3n_valu3'이며 User-Agent 값이 'reCAPTCHA'인 상황을 적어두었는데 이는 무슨 의미일까? 개발자가 이렇게 숨겨진 값을 작성해두는 것은 애플리케이션 개발 중에 디버깅용으로 일종의 프리패스를 만들어둔 것일 것이다. 비밀번호 변경 로직을 테스트할 때마다 CAPTCHA를 통과해야 한다면 워낙 귀찮은 일이 아닐 수 없다. 그래서 개발 시에만 CAPTCHA를 우회해서 애플리케이션을 개발하고 개발이 끝난 후에는 지울 예정이었던 값일 것이다.

 

그런 값이 지워지지 않고 소스 코드에 남아 있다는 것은 이 '프리패스' 역시 지워지지 않고 그대로 구현되어 있다고 추측할 수 있다. 그럼 User-Agent는 요청 헤더에 전달되는 값이라 치고 Response는 무엇을 의미하는 것일까? 지금 이 요청에서 이 단어와 가장 근접한 값은 CAPTCHA의 결괏값인 g-recaptcha-response다. 확인을 위해 Burp Suite를 이용해 요청을 수정해 보기로 했다(어차피 User-Agent를 수정해야 하기 때문).

POST /dvwa/vulnerabilities/captcha/ HTTP/1.1
Host: 192.168.26.201
Content-Length: 131
Cache-Control: max-age=0
Origin: http://192.168.26.201
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: reCAPTCHA
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.26.201/dvwa/vulnerabilities/captcha/
Accept-Encoding: gzip, deflate
Accept-Language: ko,en;q=0.9,en-US;q=0.8
Cookie: security=high; PHPSESSID=1uhh7s47eqg2dtha71c57t22s6
Connection: close

step=1&password_new=password&password_conf=password&g-recaptcha-response=hidd3n_valu3&user_token=a473dcff7be5d0c5e85b98becebe10e5&Change=Change

수정한 요청은 위와 같다. User-Agent 헤더가 'reCAPTCHA'로 수정되어 있으며 g-recaptcha-response 값은 'hidd3n_valu3'로 입력되어 있다. 이 요청은 CAPTCHA를 수행하지 않고 전송된 요청이기 때문에 해당 값은 비어있다. 이 요청을 전송하면 아래처럼 비밀번호가 변경된 것을 볼 수 있다.

이 실습은 개발자의 디버깅 정보가 노출되거나 디버그 코드가 실제 제품 코드에 남아있을 때 발생할 수 있는 취약점을 일깨워주고 있다. 추가적으로 확인할 수 있는건 현재 폼에서 입력하고 있는 CSRF 토큰은 검증 로직이 없기 때문에 토큰 값을 바꾸거나 아예 삭제해도 아무런 문제가 없다는 것이다.

그래서 실질적으로 필요한 것은 위조된 User-Agent와 CAPTCHA의 response가 담긴 요청이다. 이는 역시 개발자의 코딩 실수에 해당할 것이다.

 

이렇게 수동으로 비밀번호를 변경하면 무슨 의미가 있나 싶겠지만 이번 실습의 목적은 CAPTCHA가 적용된 시스템에서 CAPTCHA를 우회하고 아무런 방해 없이 반복적인 요청을 보내는 것이다. 꼭 로그인한 사용자가 피해자인 것은 아니며 비밀번호 변경이 아니라 게시판에 글을 쓰는 기능이라면 이 CAPTCHA를 우회하고 스팸 게시글을 반복적으로 작성하는 방식으로 악용할 수도 있을 것이다.