본문 바로가기
정보보안/WebGoat

OWASP Top 10 항목 진단 - Broken Authentication

by IT매니절 2025. 1. 13.

무작정 따라하며 원리를 깨우치는 웹 해킹 : WebGoat 편

https://www.inflearn.com/course/%EC%9B%B9-%ED%95%B4%ED%82%B9-%EB%B3%B4%EC%95%88-webgoat


취약한 인증

2. Broken Authentication
- Authentication Bypasses
- JWT tokens
- Password reset
- Secure Passwords

 

 

Authentication Bypasses

2 Fator Password Reset (2단계 인증)

시나리오 : 2차인증으로 어떠한 질문에 대답해야 하는데, 그에 대한 2Fator 인증 우회

실제 사례 : 2016년 페이팔 2차인증에서 파라미터를 완전히 제거한 뒤 인증우회 성공

 

정상결과

 

파라미터 삭제의 경우 인증실패

파라미터 변조를 통해 인증 우회 성공

 

url을 보면 POST /WebGoat/auth-bypass/verify-account HTTP/1.1 이고

https://github.com/WebGoat/WebGoat
경로 : WebGoat/src/main/java/org/owasp/webgoat/lessons/authbypass/VerifyAccount.java


파일 내에서 path = "/auth-bypass/verify-account" 인 메소드를 찾는다

 

//주요 인증 부분
    if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) {
      userSessionData.setValue("account-verified-id", userId);
      return success(this).feedback("verify-account.success").build();
    } else {
      return failed(this).feedback("verify-account.failed").build();
    }
    
//verifyAccount메소드의 내용은 AccountVerificationHelper.java에 있다
      public boolean verifyAccount(Integer userId, HashMap<String, String> submittedQuestions) {
    // short circuit if no questions are submitted
    if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) {
      return false;
    }

    if (submittedQuestions.containsKey("secQuestion0")
        && !submittedQuestions
            .get("secQuestion0")
            .equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) {
      return false;
    }

    if (submittedQuestions.containsKey("secQuestion1")
        && !submittedQuestions
            .get("secQuestion1")
            .equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
      return false;
    }

    // else
    return true;
  }

=> IF문을 보면, 질문의 개수가 다르거나, Q0/Q1의 답이 일치하지 않을때 false를 설정하고 있다.

파라미터에 Q0과 Q1이 없으므로 if문을 통과해버리고 자연스럽게 마지막의 return true가 반환된다

 

 

JWT tokens

Json Web Token

 

구성
[헤더].[페이로드].[시그니처] 각 Base64Url로 이루어짐

 

헤더 : 타입, 시그니쳐에 적용될 알고리즘 정보
페이로드 : 사용자 정보
시그니쳐 : 헤더와 페이로드의 내용을 비밀키를 통해 알고리즘 적용한 데이터 (데이터 조작 방지)

 

문제

 

JWT 토큰을 변조하여 관리자가 된 후 투표에 성공하는 것이 목표

옆에 보면 이렇게 계정을 변경할 수 있다

 

일단 Burp에서 json 데이터 응답 받을 수 있도록 설정해줘야 한다

 

강의와 Burp 버전이 달라서

extender가 없어서 한참 헤맸는데 Extensions에 BApp Store가 있었다

요 플러그인도 설치해야한다

 

Burp에서 확인하면, Proxy탭에 JWS 라는 새로운 탭이 형성되어 있다

 

https://datatracker.ietf.org/doc/html/rfc7518

JWT 토큰은 보통 시그니쳐가 있어 변조가 불가능하지만, none 알고리즘을 적용시 시그니쳐 값이 없어도 인증이 된다

 

 

 

여기서 이렇게 변조를 한다. 시그니쳐 부분은 완전삭제

이렇게 하면 풀려야 하는데......... 강의 버전과 코드가 달라진 모양인지 안됐다

 

=> 나는 바보다; intercept 할 때 휴지통 아이콘을 눌러야 하는데 (왜냐면, 리셋이 목표니까)

계정 변경 아이콘을 intercept 해놓고 안된다고 헛짓하고 있었다....

 

아무튼 성공

 

+

https://jwt.io/

디버거 메뉴에서 짠 붙여넣으면 디코딩 되어 나오니 데이터를 볼 수 있다

 

 

JWT Crack의 원리
헤더 + 페이로드를 무작위로 알고리즘을 적용하여 시그니쳐와 맞는지 비교하여 알아낸다

Hashcat을 이용한 JWT Crack

 

문제
Given we have the following token try to find out secret key and submit a new key with the username changed to WebGoat.

eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImlhdCI6MTczNjM0MjIzMCwiZXhwIjoxNzM2MzQyMjkwLCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQub3JnIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.w1oahquV5fkJuMImk5YtFdv-vsLnL1LR4CvlYxRRZ44

주어진 토큰의 사용자명을 WebGoat으로 변경하여 제출할것

단순히 username만 변경하여 제출하면 이런 응답이 뜬다. 시그니쳐 변조가 필요하다.

 

https://hashcat.net/hashcat/
hashcat 사이트에 들어가서 hashcat binaries를 다운로드 받는다

이런 화면이 나온다

사전파일은  https://github.com/first20hours/google-10000-english/blob/master/google-10000-english.txt 를 이용했다

주어진 토큰값을 jwt.txt로 저장한다

 

-a 공격타입은 3번 모드(Brute-force)
-m 해시모드의 경우 jwt는 16500

따라서
hashcat -a 3 -m 16500 jwt.txt google-10000-english.txt
이렇게 입력한다

(hashcat.exe를 실행하는 것이 아니라, cmd 창에서 해당 위치에 들어가 명령어를 입력한다)

 

결과

Candidates.#1 부분을 보면 된다

너무 오래 걸려서 만료됐다고 퇴짜맞음;

 

새로고침하고, 다시 붙여넣고 진행하면 성공

+이전문제에서 진행한 none 공격으로 진행해도 성공함

 

 

Refresh Token

액세스토큰(jwt)을 재발급 받기 위한 키

 

7번 항목

Bugcrowd 현상금 프로그램을 기반으로 하며
전체 내용은 https://emtunc.org/blog/11/2017/jwt-refresh-token-manipulation/ 에서 확인가능

그냥 제출하면 당연히 에러난다

 

주어진 로그

194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /JWT/refresh/checkout?token=eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q HTTP/1.1" 401 242 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "POST /JWT/refresh/moveToCheckout HTTP/1.1" 200 12783 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "POST /JWT/refresh/login HTTP/1.1" 200 212 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /JWT/refresh/addItems HTTP/1.1" 404 249 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
195.206.170.15 - - [28/Jan/2016:21:28:01 +0100] "POST /JWT/refresh/moveToCheckout HTTP/1.1" 404 215 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" "-"

 

js파일을 보는데

뭘 추가해줘야 할지 몰라서 일단 request랑 response 둘 다 넣었다

 

HTTP History 탭에 들어가면

여러가지 파일 중에 jwt-refresh.js 파일이 있다

핵심내용. 새 토큰을 발급받을때.

 

로그인은 /WebGoat/JWT/refresh/login

다른 사용자의 refresh_token인 GgHHRVjjrGlFmhXwhmof 를 이용하여
주어진 Tom의 액세스 토큰을 통해 재발급받는다

 

url : /WebGoat/JWT/refresh/newToken

 

강의대로 따라했는데 401 Unauthorized 가 떴다 ...

재발급 토큰이 아예 생성이 되지 않으니 당황스럽군... 이에 대해서는 강의 질문을 남겨놓았다

 

 

8번 항목

순서

 

기존과 다르게 추가된 부분은 kid라는 파라미터인데


해당 키를 변조하고 tom의 계정을 삭제해야 한다

1. union based sql injection을 통한 kid 변조 + base64 인코딩
2. jerry를 tom으로 변조

 

 

kid 파라미터에 인젝션하기 전에 취약한 것을 파악한다

"status" : 500,
"error" : "Internal Server Error"

'||' 를 넣었을때 정상적인 응답이 돌아오는 것으로 보아 취약한 것을 확인할 수 있다

 

 

 

Jerry의 토큰값

 

변조한 토큰값

kid부분에 sql injection

( w' and 1=2 union select 'd2ViZ29hdA==' from jwt_keys where id='webgoat_key )

username에 Tom

시그니쳐 부분에 webgoat 넣어주었다 select절에는 webgoat를 base64 인코딩해서 셋팅했다

 

결과는 에러

엥...

혹시나 해서 exp 부분 변조했더니 성공했다 휴

 

 

 

 

 

Password reset 

webwolf 설치 : https://github.com/WebGoat/WebGoat/releases/download/v8.1.0/webwolf-8.1.0.jar

C:\Users\user\Desktop\webgoat>java -jar webwolf-8.1.0.jar

cmd창에서 실행해주고

 

 

http://127.0.0.1:9090/WebWolf/home

webwolf 페이지는 여기인데, 원래 192 ~ ip를 쓰고 있었으나 접속이 안되어 127.0.0.1 로 접속했다.

비밀번호 찾기를 하면 웹울프 메일함에 이렇게 들어와있다

해당 문제는 재설정 패스워드 결함을 의미한다 (자세히 보면 재설정 비밀번호가 id를 거꾸로 나열한 것에 지나지 않는다...)

 

사용자 이름은 webgoat 좋아하는 컬러는 red
다른 사용자의 패스워드를 알아내는 것이 목표
다른 사용자 : tom, admin, larry

=> 해당 문제는 인젝션을 하고 말고 하는게 아니라 그냥 무작위 대입이었다

색깔처럼 고정된 답이 있는 질문은 보안에 취약하다는 의미

 

이러한 무작위 대입은 Intruder에서 리스트를 셋팅하여 빠르게 진행할 수 있다 

 

이외

좋아하는 동물, 어머니와 자신의 생년, 어릴 때 살았던 집 주소나 첫 취직한 도시 이름 등등

추측하기 쉬운 질문들은 보안이 취약하다

 

 

목표 : tom의 계정으로 로그인해야한다

비밀번호 재설정 메일을 보낼 때 해커의 url로 변조될 수 있는 위험이 있다. 이 문제의 경우 Host만 변조하면 그걸로 바꿔쳐짐

 

웹울프로 연결된 url로 host를 변경하면

웹울프의 incoming requests에서 볼 수 있다

앞쪽 url을 웹곳 쪽으로 변경하여 접속하고 비밀번호를 재설정한다

로그인....에 성공해야 하는데 실패한다. 왜인지 도무지 모르겠다.... ;;;

이메일 링크를 보냈고

웹울프로 확인했고

Password changed successfully, please login again with your new password

패스워드 설정 완료까지 떴는데도 로그인이 되지 않는다... 

웹곳자체 오류인것으로 판단되니 넘어가야지;;

 

Secure Passwords

좋은 패스워드의 조건에 대한 항목
특문, 숫자, 소문자, 대문자를 섞어서 입력하자 클리어되었다