워게임/dreamhack

[dreamhack] file-csp-1 문제풀이

  • -
[WEB] file-csp-1 문제풀이

CSP(Content Security Policy)는 다양한 웹 보안 정책 중 하나다. 주로 XSS나 Data Injection, Click Jacking 등 웹 페이지에 악성 스크립트를 삽입하는 공격 기법들을 막기 위해 사용된다. 주로 헤더에 내용이 삽입되며 특정 리소스가 어디서 왔는지 검사를 하고 허용된 범위에 포함됐는지 검토한다.

 

문제를 확인해보자.

 


/test 페이지에 접근하니 Test 버튼이 눈에 띈다.

예시로 써있는 저 구문을 입력해서 버튼을 눌러보자.

 

 

이런 결과가 출력된다. 무슨 말인지 모르겠으므로 코드를 봐보자.

 

#!/usr/bin/env python3
import os
import shutil
from time import sleep
from urllib.parse import quote

from flask import Flask, request, render_template, redirect, make_response
from selenium import webdriver

from flag import FLAG

APP = Flask(__name__)


@APP.route('/')
def index():
    return render_template('index.html')


@APP.route('/test', methods=['GET', 'POST'])
def test_csp():
    global CSP
    if request.method == 'POST':
        csp = request.form.get('csp')
        # start bot..
        try:
            options = webdriver.ChromeOptions()
            for _ in ['headless', 'window-size=1920x1080', 'disable-gpu', 'no-sandbox', 'disable-dev-shm-usage']:
                options.add_argument(_)
            driver = webdriver.Chrome('/chromedriver', options=options)
            driver.implicitly_wait(3)
            driver.set_page_load_timeout(3)
            driver.get(f'http://localhost:8000/live?csp={quote(csp)}')
            try:
                a = driver.execute_script('return a()');
            except:
                a = 'error'
            try:
                b = driver.execute_script('return b()');
            except:
                b = 'error'
            try:
                c = driver.execute_script('return c()');
            except Exception as e:
                c = 'error'
                c = e
            try:
                d = driver.execute_script('return $(document)');
            except:
                d = 'error'

            if a == 'error' and b == 'error' and c == 'c' and d != 'error':
                return FLAG

            return f'Try again!, {a}, {b}, {c}, {d}'
        except Exception as e:
            return f'An error occured!, {e}'

    return render_template('check.html')


@APP.route('/live', methods=['GET'])
def live_csp():
    csp = request.args.get('csp', '')
    resp = make_response(render_template('csp.html'))
    resp.headers.set('Content-Security-Policy', csp)
    return resp


if __name__ == '__main__':
    APP.run(host='0.0.0.0', port=8000, debug=True, threaded=True)

 

test 페이지에서 csp 파라미터를 받아서 http://localhost:8000/live?csp={quote(csp)}를 접속한다.

그리고 차례로 a(), b(), c(), $(document)를 실행시켜서 

a='error'이고, b='error'이고, c='c'이고, d!='error'이면 플래그를 출력시킨다.

 

제일 처음 csp로 넘겼던 값은 CSP 헤더에 이렇게 작성되었을 것이다.

Content-Security-Policy: script-src 'unsafe-inline'

이 것은 script tag에서 inline script를 허용한다는 내용이다.

 

그럼 CSP 설정을 하지 않았을 때 어떻게 출력되는지 확인해보자.

 

모든 스크립트 태그가 실행됨을 알 수 있다.

 

각각 a(),b(),c(),$(document) 함수가 script 태그 안에 정의되어 있다.

그럼 여기에서 a(),b() 함수의 실행을 막고 c(), $(document) 만 실행시켜야 한다.

CSP의 script-src 정책을 이용해서 각 태그의 특징을 이용해야 한다.

 

a() 함수는 script 속성이 별도로 지정되어 있지 않다.

b() 함수는 nonce 속성 값으로 "i_am_user_super_random" 이 지정되어 있다.

c() 함수 또한 nonce 속성 값으로 "i_am_user_super_random" 이 지정되어 있다.

$(document) 는 c() 함수와 동일한 스크립트 태그 안에 정의되어 있다,

 

nonce 값으로 설정하기엔 b()와 c()가 동일하기 때문에 스크립트 해시 값으로 실행시켜야한다.

CSP는 스크립트 태그 안에 정의된 구문들을 해시 값으로 만들어서 무결성을 체크할 수 있는데

이 것을 이용하면 해당 해시와 동일한 스크립트 구문만을 실행할 수 있다.

 

그럼 아래 구문을 해시 값으로 만들어야 한다.

 

function c() { return 'c'; }
document.write('c: allow me!<br>');
try { $(document); document.write('jquery: allow me!<br>'); } catch (e) {  }

 

*주의사항은 <script></script> 사이의 모든 공백은 HASH 값에 포함되어야 한다.

 

 

https://report-uri.com/home/hash 페이지에서 스크립트 태그 안 문자열(공백포함)을 sha256 값으로 바꿔준다.

그리고 script-src 정책으로 해당 해시를 넣어줘서 c(), $(document) 구문 만을 실행하도록 한다.

csp=script-src 'sha256-l1OSKODPRVBa1/91J7WfPisrJ6WCxCRnKFzXaOkpsY4='

 

 

가장 아래 4번째 스크립트 태그 안 구문이 실행된 것을 확인했다.

그 위 스크립트 태그도 allow 해줘야한다. 여기는 hash가 있으니 그대로 갖다 쓰면 되겠다.

 

이제 /verify 페이지에서 플래그를 획득해보자.

 

csp=script-src 'sha256-l1OSKODPRVBa1/91J7WfPisrJ6WCxCRnKFzXaOkpsY4=' 'sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8='

 

문제풀이 끗

'워게임 > dreamhack' 카테고리의 다른 글

[dreamhack] web-deserialize-python 문제풀이  (0) 2021.07.07
[dreamhack] funjs 문제풀이  (0) 2021.07.06
[dreamhack] login-1 문제풀이  (0) 2021.07.01
[dreamhack] Mango 문제풀이  (0) 2021.06.24
[dreamhack] simple-ssti 문제풀이  (0) 2021.06.20
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.