[PHP] CSP bypass using output buffer?!?!

nobody09·2024년 9월 18일

Vulnerability Analysis

목록 보기
4/4
post-thumbnail

제목으로 관심을 좀 끌어봤다. 하하하. 특정 상황에서만 쓸 수 있어서 범용성은 좀 떨어진다.

PHP Output Buffer

그래서 php output buffer가 뭔데? echo나 print등으로 발생하는 출력을 클라이언트로 바로 전송하지 않고 버퍼에 담아둘 수 있다. 지정한 버퍼의 크기가 꽉 차거나 ob_flush()등의 함수로 제어해서 보낼 수 있다.

문제는 다음과 같은 상황에 발생한다.

<?php   
...
    if (isset($_GET['comment'])) {
        $comment = $_GET['comment'];

...

        if (strpos($comment, 'script') !== false){
            $untrusted_comment = $_GET['comment'];

            while (strpos($untrusted_comment, 'script') !== false) {
                $alert = 'Malicious string Detected !!!!!';
                $untrusted_comment = str_replace('script', '', $untrusted_comment);
                echo $alert;
                echo $untrusted_comment;
                
            }
        }
    } 


    $nonce = base64_encode(random_bytes(20));
    $csp_header = "Content-Security-Policy: default-src 'self'; script-src *.bootstrapcdn.com 'nonce-" . $nonce . "'; style-src-elem *.bootstrapcdn.com;";
    header($csp_header);
?>

GET으로 comment를 받고, comment에 script가 없어질 때 까지 while문을 돌면서 공백으로 치환한다. 치환만 했으면 문제가 없겠지만.. alert와 함께 untrusted_comment를 출력하고 있다. script를 포함하는, 충분히 긴 문자열을 comment로 넣어주면 버퍼가 꽉 차서 클라이언트로 응답을 그냥 보내버린다. 따라서 코드 아래의 csp_header가 설정되지 않는다. 그렇다면? xss 가능이다. 추가적으로 php의 output buffer는 기본적으로 4096byte=4kb가 설정되어있다.

현장에서 이런식으로 코드를 작성하는 사람은 없겠지만.. 그래도 한 번 정리해 봤다.

0개의 댓글