[WEB] php-1 문제풀이 |
LFI(Local Include Inclusion) 취약점 이란 공격 대상 서버에 위치한 파일을 포함시켜 읽어오는 공격을 말한다. 특수문자 필터링 혹은 디렉터리 권한 설정이 적절하지 않을 때 LFI 취약점이 발생할 수 있는데 예를 들어 filename 파라미터 값에 ../../../../etc/passwd와 같은 값을 넘겨주면 해당 파일을 include 할 수 있다. inculde() 함수 외에도, include_once(), require(), require_once(), file_get_contents() 등의 함수로부터 해당 취약점이 발생할 수 있다.
PHP Wrapper란 파일 시스템 함수와 함께 사용하기 위한 다양한 URL 스타일 프로토콜을 내장 wrapper가 제공하는 것을 말한다. wrapper란 실제 데이터의 앞에서 틀을 잡아주는 데이터 또는 다른 프로그램이 성공적으로 실행되도록 설정하는 프로그램을 말한다. php wrapper를 이용하면 개발자의 의도와 다른 행위를 발생시킬 수 있다.
php wrapper의 몇 가지 예시를 보자.
(1) expect:// : system command의 실행이 가능하다. ex) [주소]?page=expect://[command] (2) php://filter : I/O 스트림을 다루는데 사용하며 encode/decode를 이용하여 서버 내 파일을 읽을 수 있다. 대표적으로 base64를 이용한다. ex) [주소]?page=php://filter/convert.base64-encode/resource=[파일] (3) zip:// : 압축을 풀고 그 안에 있는 파일의 코드를 실행시켜준다. ex) [주소]?file=zip://[파일] |
설명이 길었다. 그럼 문제를 확인해보자.
LFI 취약점을 이용해 /var/www/uploads/flag.php 에 있는 FLAG를 획득하라고 한다.
바로 접속해보자.
List 페이지에 들어가보자.
flag.php 링크를 눌러보자
GET 파라미터로 /?page=view&file=../uploads/flag.php 를 전달한다.
flag.php를 보는 것이 권한이 없다고 나온다.
그럼 hello.json 링크를 들어가보자.
GET 파라미터로 /?page=view&file=../uploads/hello.json 을 전달한다.
위 flag.php 와 다르게 hello.json 파일은 읽어진다.
일단은 여기까지 하고 모르겠으니 소스코드를 확인해보자.
우리가 확인해야할 소스코드는 총 3개이다.
- index.php
- list.php
- view.php
먼저 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>
GET 요청으로 들어온 'page' 파라미터 값이 존재하면 해당 파라미터 값에 해당하는 php 파일을 include하고
값이 존재하지 않을 경우 main.php 를 실행시킨다.
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/>";
}
?>
list.php 는 ../uploads/ 디렉토리에 있는 파일 및 디렉터리 배열 중 '..', '.', 'index.html' 를 제외한
나머지 배열을 이용하여 /?page=view&file={$directory}{$value}를 만들어 낸다.
※ 이 코드는 그다지 중요하지 않으므로 스킵해도 좋다.
마지막으로 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>
view 페이지에서는 GET으로 받아온 file 파라미터 값에 flag 문자열이 포함되어 있으면 Permission denied를 출력하고,
그렇지 않으면 file_get_contents() 함수로 해당 파일을 출력한다.
index.php 에서는 include() 함수로 file 파라미터 값 읽어서 include 하고,
view.php에서는 file_get_contents() 함수로 file 파라미터 값을 include 한다.
문제에서 FLAG는 /var/www/uploads/flag.php 에 있다고 했기 때문에
flag 문자열을 필터링하는 view.php가 아닌 index.php 에서 해당 파일을 읽어와야한다.
공격 페이로드는 다음과 같다.
http://host1.dreamhack.games:12281/index.php?page=../uploads/flag |
문구가 출력되어 있는데 잘 안보여서 소스코드를 봤더니 'can you see $flag?' 라고 농락당했다.
내가 include 시킨 flag.php 파일은 브라우저 상에서 html로 작성된 부분만 출력해줄텐데
실제 플래그는 php 코드에 있는 모양이다.
그렇다면 php wrapper를 이용해서 php 파일 자체를 불러와야한다.
풀이 최상단에 작성한 가장 기본적인 php wrapper인 php://filter를 이용하여 flag.php 파일을 출력해보자.
공격 페이로드는 다음과 같다.
http://host1.dreamhack.games:12281/index.php?page=php://filter/convert.base64-encode/resource=/var/www/uploads/flag |
php wrapper를 이용해 /var/www/uploads/flag.php 파일을 base64 인코딩하여 출력했기 때문에 다시 디코딩해보자.
플래그가 나왔다.
문제풀이 끗
'워게임 > dreamhack' 카테고리의 다른 글
[dreamhack] simple-ssti 문제풀이 (0) | 2021.06.20 |
---|---|
[dreamhack] web-misconf-1 문제풀이 (0) | 2021.06.15 |
[dreamhack] proxy-1 문제풀이 (0) | 2021.06.08 |
[dreamhack] Carve Party 문제풀이 (0) | 2021.06.08 |
[dreamhack] csrf-1 문제풀이 (0) | 2021.06.02 |