CTF/웹해킹

[Dreamhack] php-1

dDong2 2022. 9. 1. 01:36

문제 정보는 다음과 같다.

 

php로 작성된 Back Office 서비스입니다.
LFI 취약점을 이용해 플래그를 획득하세요.
플래그는 /var/www/uploads/flag.php에 있습니다.

 

❗LFI 취약점이란?

> 공격 대상 서버에 위치한 파일 등을 포함하여 해당 내용을 읽어오는 공격이다.

> 일반적으로 php 코드 상 include를 사용할 때, 

input에 대한 필터링이 적절히 이루어지지 않아서 발생하는 취약점이다.

> 또한, 디렉토리 변경 명령어들을 삽입했을 때 허용되면 일어나는 취약점이다.

> 대부분 LFI 취약점은 url을 통해 이루어지는데,

이는 개발자가 GET 메소드를 선호하기 때문으로 볼 수 있다.

 

그 다음 문제 가상환경으로 접속해보자!

 

 

 

총 3가지의 화면을 볼 수 있다.

그리고 나서 문제 파일을 다운로드 해보면,

 

< index.php >

<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>PHP Back Office</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="/">PHP Back Office</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
            <li><a href="/?page=list">List</a></li>
            <li><a href="/?page=view">View</a></li>
          </ul>

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

 

< main.php>

<h2>Back Office!</h2>

 

< list.php>

<h2>List</h2>
<?php
    $directory = '../uploads/';
    $scanned_directory = array_diff(scandir($directory), array('..', '.', 'index.html'));
    foreach ($scanned_directory as $key => $value) {
        echo "<li><a href='/?page=view&file={$directory}{$value}'>".$value."</a></li><br/>";
    }
?>

 

< view.php>

<h2>View</h2>
<pre><?php
    $file = $_GET['file']?$_GET['file']:'';
    if(preg_match('/flag|:/i', $file)){
        exit('Permission denied');
    }
    echo file_get_contents($file);
?>
</pre>

 

이렇게 총 4가지의 php 파일이 존재하는 것을 볼 수 있다.

우선, index.php를 맨 마지막에 살펴보기로 하고,

나머지 3개의 코드를 살펴보자.

 

1) main.php는 아무것도 없으니 패스하고,

 

2) list.php를 보면 List 페이지에서 array_diff로 무언가 비교하는 듯하다.

array_diff 함수는 php에서 array_diff(배열1, 배열2) 형태로 사용되고,

알아보니 배열1 값중 배열2에 없는 값만 배열 형태로 반환되는 함수라고 설명되어있다.

그렇다면, directory 변수에 담긴 ../uploads/ 에서

scandir라는 함수를 통해 데이터 디렉토리 파일 목록을 배열로 가져오게 된다.

그 다음, ..이나 .이나 index.html의 내용을 앞서 스캔한 목록과 비교하게 된다.

foreach 구문으로 Key와 Value를 가져와서

/?page=view&file=~~~ 을 echo로 출력하게 된다. (view 페이지로 이동)

 

3) view.php로 이동하였으니, 해당 파일을 살펴보면

file 변수에 GET으로 파일을 받고 있는 것 같고,

preg_match 함수를 통해 문자열 필터링을 하게 된다.

해당 함수는 preg_match(조건, 비교할거) 이런식인데,

정규표현식이라던지 문자열이라던지 필터링 할 내용을 조건에 넣고

비교할 거와 비교하여 필터해준다.

여기서 나오는 것은 flag 문자열과 |(or) : 문자열인데,

preg_match bypass 등 우회 방법을 여러가지 찾아봤을 때,

일단 직접적으로 flag를 타이핑하거나 뒤에 i옵션 때문에 FLAG, fLag 등은

모두 필터링 되는 것을 확인할 수 있다.

또한, hex 값을 통한 우회를 막기 위해서인지 : 문자열도 필터링 된다.

여기 부분에서 많이 헤맸는데... 답은 내가 보지 못했던 index.php에 있었다.

 

4) index.php를 살펴보면 맨 아래에 삼항연산자로 include 구문을 사용하였는데,

$_GET['page']가 일치하면 .php를 불러오고 그게 아니면 main.php를 불러온다.

main.php가 Back Office!인데, 메인화면에 불러오는게 바로 그것이다(이게 해답인듯..)

그렇다면 우리는 GET 방식으로 불러와서 .php를 불러오면 될 것이고,

flag를 삽입하여 /var/www/uploads/flag.php를 불러오면 되지 않을까 생각이 들었다.

바로 실행에 옮겨보자!

 

GET 방식으로 실행시켜주기 위해서

/?page=/var/www/uploads/flag를 삽입해보았다.

 

 

무슨 보일랑말랑하게 Can you see $flag?라고 되어있었다.

include는 include '[불러올 파일명]' 형태로 작성하게 되는데,

현재 flag.php를 그대로 불러온 형태로만 작성된 것이다.

그렇다면, 소스를 가져와야 한다는 것인데..

여기서 flag 필터링 우회를 위한 php wrapper를 참고해보았다.

 

출처:&nbsp;https://www.php.net/manual/en/wrappers.php

 

이러한 내용의 php wrapper를 참고할 수 있는데,

php://filter를 사용하여 base64 인코딩/디코딩 형식으로 받아오면 된다.

view&file=과 같이 경로가 입력되는 것이 아닌,

wrapper를 사용하여 flag.php에 바로 접근하게 된다.

그렇게 해서 다음과 같은 내용을 넣어주게 되면,

 

/?page=php://filter/convert.base64-encode/resource=/var/www/uploads/flag

 

 

위와 같이 base64로 인코딩 되어있는 값들을 볼 수 있고,

base64 디코딩을 시켜주게 되면,

 

 

flag를 획득하게 된다.