모의해킹 실습 - WebGoat / Cross-Site Request Forgeries

이태현·2026년 3월 23일

모의해킹

목록 보기
19/19
post-thumbnail

Cross-Site Request Forgeries

첫 번째 문제 - Basic Get CSRF Exercise

첫 번째 문제를 번역기로 해석해 보니
기본 GET CSRF 연습
로그인하는 동안 외부 소스에서 아래 양식을 트리거합니다. 응답에는 '플래그'(숫자 값)가 포함됩니다.

요약
1. 사용자가 특정 사이트에 로그인된 상태를 이용하여, 외부(공격자)의 웹페이지에서 사용자의 의지와 상관없이 서버로 특정 요청을 보내게 만드는 것이 목표입니다.

문제를 확인해 보니
flag를 얻어서 문제를 해결하라는 문제 같습니다.

Step 1 - 요청하기

제출 버튼을 눌렀을 때 요청을 확인해 봅시다. 아래 본문을 확인해 보니 csrf값은 false, submit값은 URL인코딩되어있습니다. 먼저 인코딩이 된 값을 먼저 풀어보면 한글로 "제출"이라는 단어가 나옵니다.

요청에 대한 응답을 확인해 보니 flag 값이 비어 있습니다. 그리고 메시지를 확인해 보니 요청이 원래 호스트에서 온 거 같다 라는 걸 알려주는데 이게 무슨 뜻일까요? 아직 CSRF공격을 시도하지도 않았는데 어떻게 공격이 아닌지 알고 응답했을까요? 정답은 요청 헤더에 있는 referer헤더때문입니다. referer헤더는 요청이 어디에서 발생했는지 위치를 알려줍니다. CSRF공격은 보통 해커가 피해자를 피싱사이트로 유도하여 요청하게 만들게끔 합니다. 그래서 아마 응답에서는 우리의 referer헤더에 있는 값을 참고하여 기존과 같은 주소에서 요청을 보냈기 때문에 요청이 똑같다고 응답을 보내준 거 같습니다.

Step 2 - 공격

그럼, 이제 제출을 눌렀을 때 요청을 가로챈 뒤 referer헤더의 값을 다른 주소로 변경해 보겠습니다. 위에 보이는 거와 같이 필자는 9090으로 변경하여 요청을 보내보도록 하겠습니다.

주소를 9090으로 변경해서 요청했더니 응답에서는 문제를 해결하였고 flag 값으로 24049이라는 값을 보내주었습니다.

결과

flag 값을 복사하여 문제에 제출하였더니 이번 문제가 해결되었습니다. 하지만 우리는 좀 더 실제 공격과 비슷하게 실습 문제를 해결해 봅시다.

Step 3 - 다른 방법으로 CSRF공격 시도

먼저 제출 버튼을 우클릭해서 검사를 누릅니다.

그러면 input 태그가 나올 텐데 해당 태그의 부모 태그인 form 태그를 확인해줍니다. 그다음 form 태그에 마우스 우클릭 후 copy를 선택하고 copy element를 클릭해 form 태그로 구성된 요소의 코드를 복사합니다.

이제 메모장을 실행해서 복사해 둔 코드를 붙여 넣습니다. 그다음 form 태그 아래에 script를 하나 작성할 겁니다. 우리는 webgoat에서 제출 버튼을 클릭해야 했지만 실제 해커입장에서는 피해자가 피싱 사이트에 접근하면 바로 CSRF공격을 시도하는 게 효율적입니다. 그래서 위와 같이 코드를 작성해서 id 값이 basic-csrf-get인 form 태그가 바로 전송되게 해줍니다.

코드를 다 작성했으면 파일 확장자는 .html로 설정하고 저장해줍니다.

webgoat를 열었던 브라우저에서 새 탭을 열어서 자신이 저장해둔 경로로 파일을 불러옵니다. 위에 사진과같이 문제에서 보았던 제출 버튼이 하나 있습니다. 이제 해당 버튼을 눌러보겠습니다.

그러면 다시 로그인하라는 webgoat로그인 페이지가 나올 겁니다. 만약 로그인이 되어있다면 상관없습니다. 만약 로그아웃된 상태라면 다시 로그인해 줍니다. 그다음 다시 제출 버튼을 누르면 위와 같이 의도한 대로 HTTP 요청을 보내서 CSRF공격에 성공하면서 실습 문제를 해결할 수 있는 flag 값을 얻었습니다.

결과

CSRF공격으로 얻은 flag값을 넣어주면 이번 문제가 해결된 걸 볼 수있습니다.

두 번째 문제 - Post a review on someone else’s behalf

다른 사람을 대신하여 리뷰 게시
아래 페이지는 댓글/리뷰 페이지를 시뮬레이션합니다. 여기서 차이점은 CSRF 공격과 이전 연습처럼 다른 곳에서 제출을 시작해야 한다는 것입니다. 생각보다 쉽습니다. 대부분의 경우 CSRF 공격을 실행할 곳을 찾는 것이 더 까다롭습니다. 고전적인 예로는 누군가의 은행 계좌에서 계좌/회선 이체가 있습니다.

하지만 여기서는 간단하게 설명하겠습니다. 이 경우 현재 로그인한 사용자를 대신하여 리뷰 제출을 트리거하기만 하면 됩니다.

요약
1. CSRF 공격을 통해 사용자의 이름으로 가짜 리뷰(댓글)를 작성해 보는 과정
2. 사용자가 로그인된 상태에서 공격자가 만든 외부 링크나 페이지를 클릭하면, 본인도 모르게 특정 게시판에 리뷰가 등록되도록 만드는 것이 목표

문제를 확인해 보니
로그인한 사용자로 댓글을 작성하면 되는 거 같습니다.

Step 1 - 요청 변조

이번에도 비슷합니다. 먼저 버튼을 우클릭 후 검사를 통해 input 태그의 부모 태그 form 태그를 찾아서 우클릭 후 form 태그로 구성된 코드를 복사합니다.

메모장을 실행해 form 태그를 html, body 태그로 감싸주고 input 태그들의 리뷰 작성 코드를 찾아서 value 속성값을 추가해 줍니다. 필자는 댓글 입력 칸에 기본값으로 value="CSRF attack" 이렇게 작성하였고, 별점에는 기본값으로 value="99" 이렇게 작성하였습니다. 이제 파일을 저장해줍니다.

Step 2 - 공격

review.html이 저장된 파일 주소를 webgoat가 실행된 브라우저에서 새로 열어줍니다. 그러면 위와 같이 처음에 기본값으로 넣어둔 문장이 보일 겁니다. 이제 제출 버튼을 눌러서 확인해 줍니다.

그러면 위와 같이 JSON 형태의 객체가 하나 보입니다. 피드백을 살펴보니 다른 사이트에서 올바르게 제출한 것 같습니다. 다시 로드하여 게시물이 있는지 확인하세요. 라는 문장이 있습니다. 문제로 돌아가서 확인해 봅시다.

결과

문제로 돌아와서 확인해 보니 우리가 제대로 공격을 성공한 거 같습니다.

세 번째 문제 - CSRF and content-type

세 번째 문제를 번역기로 해석해 보니
CSRF 및 콘텐츠 유형
이전 섹션에서는 콘텐츠 유형에 의존하는 것이 CSRF에 대한 보호가 아니라는 것을 보았습니다. 이 섹션에서는 CSRF에 대해 보호되지 않는 API에 대해 CSRF 공격을 수행할 수 있는 또 다른 방법을 살펴보겠습니다.

이 과제에서는 엔드포인트에 다음 JSON 메시지를 게시하기 위해 달성해야 합니다:

요약
1. Content-Type 헤더 검증이 CSRF 방어책으로 불충분하다는 점을 증명하는 과정
2. 많은 개발자가 "우리 API는 JSON 형식(application/json)만 받으니까, HTML 폼(Form) 기반의 CSRF 공격에는 안전하겠지?"라고 착각하지만, 이를 우회하는 기법을 배우는 것이 핵심

문제를 확인해 보니
공격자 역할을 하는 별도의 서버(WebWolf)에서 피해자(WebGoat에 로그인된 브라우저)에게 요청을 보내도록 설계하는 것이 핵심인 거 같습니다.

Step 1 - 임의의 값 요청 확인

임의의 값들을 넣어서 요청을 확인해 보도록 하겠습니다.

위와 같이 필자가 입력한 값들이 요청 본문에서 확인할 수 있습니다.

응답을 확인해 보니 해결책이 올바르지 않아서 죄송합니다. 다시 시도해 주세요 라는 피드백을 받았습니다. 어떻게 CSRF공격을 할 수 있을까요?

Step 2 - 공격

메모장을 실행해 form 태그를 감싸는 html, body 태그를 입력해 줍니다. action 속성에는 csrf공격으로 호출할 URI(http:/127.0.0.1:8080/WebGoat/csrf/feedback/message)를 넣어줍니다. method속성에는 요청을 어떤 방식으로 보낼 것인지 작성해야 하는데, 요청 Header를 참고하여 post를 넣어줍니다. id 속성값은 csrf-context-type-attack이라는 값을 넣고 enctype속성은 http 요청 본문에 파라미터들을 포함할 때 어떤 인코딩 방식을 이용할 것인지 명시하는 속성으로 test/plain을 넣어줌으로써 "그냥 글자들" 방식, 특수문자나 구조를 따지지 않고 통째로 보냅니다. 여기서 중요한 부분은 input 태그의 name, value 속성입니다. input 태그의 name 속성은 파라미터를 의미하고, value 속성은 파라미터에 대입될 값입니다. 보통 파라미터=값 형태로 http 요청을 보내는 데 이를 이용해 데이터를 JSON 형태인 척 구성할 수 있습니다. '{"name":"TaeHyun","email":"TaeHyun@TaeHyun.com","subject":"service","message":"' value='"CSRF-Context-Type-Attack"}' 빨간색 부분까지가 name 속성에 대입되는 부분이고 파란색 부분이 value 속성에 대입됩니다. name 속성과 value 속성에 대입된 값을 파라미터=값 형태로 변환해 보면 {"name":"TaeHyun","email":"TaeHyun@TaeHyun.com","subject":"service","message":"=CSRF-Context-Type-Attack"}가 되고 실제로 JSON 형태를 이용한 것은 아니지만 마치 JSON 형태인 척 http 요청 본문을 구성할 수 있습니다.

저장한 파일을 열어주면 문제가 해결됐다는 피드백과 flag 값을 알아낼 수 있습니다.

결과

복사한 flag 값을 문제에 제출하면 이번 실습이 해결된 것을 볼 수 있습니다.

네 번째 문제 - Login CSRF attack

네 번째 문제를 번역기로 해석해 보니
로그인 CSRF 공격
로그인 CSRF 공격에서 공격자는 해당 사이트에서 공격자 ���의 사용자 이름과 비밀번호를 사용하여 정직한 사이트에 로그인 요청을 위조합니다. 위조가 성공하면 정직한 서버는 세션 쿠키를 저장하고 사용자를 정직한 사이트에 공격자로 로그인하여 브라우저가 상태를 변경하도록 지시하는 Set-Cookie 헤더로 응답합니다. 이 세션 쿠키는 사용자의 세션에 대한 후속 요청을 바인딩하는 데 사용되며, 따라서 공격자의 인증 자격 증명에 바인딩하는 데 사용됩니다. 로그인 CSRF 공격은 심각한 결과를 초래할 수 있습니다. 예를 들어, 아래 그림에서는 공격자가 google.com 에서 계정을 생성한 후 피해자가 악성 웹사이트를 방문하고 사용자가 공격자로 로그인하는 경우를 볼 수 있습니다. 그런 다음 공격자는 나중에 사용자의 활동에 대한 정보를 수집할 수 있습니다.

요약
1. 로그인 CSRF는 "사용자를 공격자의 계정으로 강제 로그인"시키는 것이 핵심

문제를 확인해 보니
csrf-사용자이름 형태로 공격자 계정을 하나 만들어서 피해자가 공격자의 계정으로 로그인하게 만들어야 하는 문제 같습니다.

Step 1 - 공격자 계정 생성

위와 같이 회원가입 페이지에서 csrf-123123이라는 공격자 계정을 만들었습니다.

로그인 요청의 본문을 확인해 보니 파라미터로 username, password를 사용하고 있으니 이를 바탕으로 post 방식으로 전달하는 공격용 html을 만들어 보겠습니다.

Step 2 - 공격

메모장을 실행해 csrf공격을 하기 위한 코드를 작성합니다.

webgoat를 실행했던 브라우저로 파일을 열어줍니다.

로그인을 누르는 순간 공격자 계정인 csrf-123123으로 로그인이 되어버렸습니다.

결과

다시 사용자계정으로 돌아와서 문제에 있는 해결 버튼을 누르면 문제가 해결되었습니다.

마무리

이번 실습에서는 CSRF 공격에 대해서 배워봤습니다. CSRF를 사람들이 XSS랑 많이들 헷갈립니다. 물론 CSRF와 XSS는 분명 비슷한 정의를 가집니다. 하지만 공격의 타겟과 목적에서 큰 차이가 있습니다. XSS는 '사용자의 브라우저'를 믿게 만드는 것이고, CSRF는 '사용자의 권한'을 도용하는 것입니다. 그래서 XSS는 사용자의 세션 쿠키 탈취, 개인정보 유출, 페이지 변조 같은 공격을 많이 하고 CSRF는 사용자가 이미 로그인되어 있는 상태(세션이 유효한 상태)를 이용합니다. 그래서 사용자의 권한으로 비밀번호 변경, 자금 송금, 게시글 작성 등 특정 동작을 수행하게 합니다.
1. XSS (Cross-Site Scripting)
"사용자가 웹사이트를 신뢰한다는 점을 악용"

XSS는 공격자가 악성 스크립트(주로 JavaScript)를 웹 페이지에 삽입하는 방식입니다. 사용자가 그 페이지를 방문하면 브라우저에서 스크립트가 실행됩니다.

  • 공격 대상: 웹사이트를 이용하는 사용자(클라이언트).

  • 주요 목적: 사용자의 세션 쿠키 탈취, 개인정보 유출, 페이지 변조.

  • 작동 방식:

  1. 게시판 등에 <script>stealCookie()</script> 같은 코드를 남김.
  2. 일반 사용자가 해당 게시글을 읽음.
  3. 사용자의 브라우저에서 스크립트가 실행되어 정보가 공격자에게 전송됨.

2. CSRF (Cross-Site Request Forgery)
"웹사이트가 사용자의 브라우저를 신뢰한다는 점을 악용"

CSRF는 사용자가 의도하지 않은 요청을 특정 웹사이트에 보내도록 강제하는 방식입니다. 사용자가 이미 로그인되어 있는 상태(세션이 유효한 상태)를 이용합니다.

  • 공격 대상: 특정 웹 서버의 리소스.

  • 주요 목적: 사용자의 권한으로 비밀번호 변경, 자금 송금, 게시글 작성 등 특정 동작 수행.

  • 작동 방식:

공격자가 가짜 링크나 이미지가 포함된 메일을 보냄.

사용자가 로그인된 상태에서 그 링크를 클릭.

브라우저가 사용자의 쿠키를 담아 웹 서버에 "비밀번호 변경" 같은 요청을 보냄. 서버는 정상적인 요청으로 착각하고 처리함.

3. 핵심 차이점 비교

구분XSSCSRF
핵심 기제악성 스크립트 실행사용자 권한 도용 (요청 위조)
공격 위치사용자의 브라우저 내부사용자의 브라우저 → 서버 방향
인증 상태로그인 여부와 관계없음 (주로)반드시 로그인된 상태여야 함
방어 방법입출력 값 필터링 (HTML Sanitizing)CSRF 토큰 사용, SameSite 쿠키 설정

요약
XSS: "너(사용자)의 브라우저에서 내 코드를 실행할게!"

CSRF: "너(사용자)의 이름으로 서버에 이 명령을 보낼게!"

profile
이해하고 분석하고 지배한다

0개의 댓글