e_yejun
Jun_ : Pwn
e_yejun
전체 방문자
오늘
어제
  • 분류 전체보기 (240)
    • Profile (1)
    • Pwnable (54)
    • Reversing (14)
    • Network (8)
    • Forensic (10)
    • Embedded (4)
    • Android (2)
    • Web (18)
    • 알고리즘 (42)
    • 프로그래밍 (24)
    • 프로젝트 (6)
    • 1-day (7)
    • CTF (15)
    • 기타 (33)
    • 일기장 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • dvwa
  • dreamhack.io
  • Heap
  • x64
  • how2heap
  • X86
  • 1-day
  • rev-basic
  • BOF
  • wargame

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
e_yejun

Jun_ : Pwn

Web

[DVWA] CSP 문제풀이

2023. 4. 15. 23:20

Index

CSP (Content Security Policy)
low
medium
high
impossible

CSP (Content Security Policy)

CSP는 XSS 및 Injection 공격을 탐지하고 완화하기 위해 도움을 주는 보안 계층이다. HTTP 헤더를 기반으로 정책을 추가하는 방식이다.

해당 low 레벨 문제에서는 특정 URL을 받아 include하는 폼이 있다.

low

<?php

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com hastebin.com www.toptal.com example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, hastebin.com, jquery and google analytics.

header($headerCSP);

# These might work if you can't create your own for some reason
# https://pastebin.com/raw/R570EE00
# https://www.toptal.com/developers/hastebin/raw/cezaruzeka

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    <script src='" . $_POST['include'] . "'></script>
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
';

header에서 self와 pastbin.com 등 특정 사이트의 js를 허용한다.

include의 입력 태그를 POST로 받아서 <script> 구문 안으로 넣어 XSS가 발생한다.

pasbin.com에서 스크립트 구문을 작성하고, 이 주소를 입력 폼에 넣어주자.

하지만, 경고창을 띄울 수 없었다. 그래서 CSP에 self도 포함하기 때문에 로컬 경로에 파일을 세팅하고 진행했다.

/tests/csp_low 파일에 alert(document.cookie); 를 입력하고 경로를 include 하면 XSS가 발생한다.

medium

<?php

$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";

header($headerCSP);

// Disable XSS protections so that inline alert boxes will work
header ("X-XSS-Protection: 0");

# <script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    " . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
';

이번 헤더에서는 unsafe-inline 옵션이 들어가 있다. 이 옵션은 인라인 스크립트를 사용할 수 있게 한다. 뒤에 nonce 값을 통해 script에 nonce 값을 넣어줘야 스크립트를 사용할 수 있다. 이 문제에서는 nonce 값이 고정이기 때문에 손쉽게 XSS를 발생시킬 수 있다.

<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(document.cookie)</script>

high

문제의 폼이 바뀌었다. 소스코드를 분석해보자.

<?php
$headerCSP = "Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    " . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>The page makes a call to ' . DVWA_WEB_PAGE_TO_ROOT . '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p>
    <p>1+2+3+4+5=<span id="answer"></span></p>
    <input type="button" id="solve" value="Solve the sum" />
</form>

<script src="source/high.js"></script>
';

solve the sum 버튼을 누르면 앞에 수식의 결과가 나온다. 코드 아래 high.js를 참조하고 있으니, 이 파일을 살펴본다.

source/high.js

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp.php?callback=solveSum";
    document.body.appendChild(s);
}

function solveSum(obj) {
	if ("answer" in obj) {
		document.getElementById("answer").innerHTML = obj['answer'];
	}
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
	solve_button.addEventListener("click", function() {
		clickButton();
	});
}

버튼의 id가 solve로 해놓았기 때문에 이를 통해 요소를 가져온다. addEventListener로 클릭했을 때, clickButton 함수가 호출된다. jsonp.php로 GET 방식으로 callback 인자를 전달한다.

source/jsonp.php

<?php
header("Content-Type: application/json; charset=UTF-8");

if (array_key_exists ("callback", $_GET)) {
	$callback = $_GET['callback'];
} else {
	return "";
}

$outp = array ("answer" => "15");

echo $callback . "(".json_encode($outp).")";
?>

callback에 대한 검증이 따로 없다. 스크립트 구문을 넣으면 될 것 같다.

프록시 도구를 이용하여 패킷을 잡고, jsonp.php로 넘어가는 callback 인자를 변조한다.

원래는 함수 이름을 넘겨서 실행시키는 callback인자이므로, <script>를 감싸지 않고 바로 alert를 띄우면 된다.

impossible

<?php

<!-- high와 코드 동일 -->

<script src="source/impossible.js"></script>
';

참조하는 js파일만 다르다.

source/impossible.js

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp_impossible.php";
    document.body.appendChild(s);
}

function solveSum(obj) {
    if ("answer" in obj) {
        document.getElementById("answer").innerHTML = obj['answer'];
    }
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
    solve_button.addEventListener("click", function() {
        clickButton();
    });
}

high와는 다르게 callback 파라미터를 GET방식으로 넘기지 않는다.

source/jsonp_impossible.php

<?php
header("Content-Type: application/json; charset=UTF-8");

$outp = array ("answer" => "15");

echo "solveSum (".json_encode($outp).")";
?>

php 파일을 확인해보면, callback을 사용하는게 아닌 solveSum을 하드코딩으로 호출해버린다. 그래서 high 난이도의 문제의 취약점을 해결했다.


Uploaded by N2T

    'Web' 카테고리의 다른 글
    • [Node.js] pm2 모듈 사용법 - 무중단 서비스 올리기
    • MYSQL 명령어 실습
    • [DVWA] CSRF 문제풀이
    • [Webgoat] XSS 문제풀이
    e_yejun
    e_yejun
    정리노트 •_•

    티스토리툴바