문제 정보는 다음과 같다.
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를 참고해보았다.
이러한 내용의 php wrapper를 참고할 수 있는데,
php://filter를 사용하여 base64 인코딩/디코딩 형식으로 받아오면 된다.
view&file=과 같이 경로가 입력되는 것이 아닌,
wrapper를 사용하여 flag.php에 바로 접근하게 된다.
그렇게 해서 다음과 같은 내용을 넣어주게 되면,
/?page=php://filter/convert.base64-encode/resource=/var/www/uploads/flag |
위와 같이 base64로 인코딩 되어있는 값들을 볼 수 있고,
base64 디코딩을 시켜주게 되면,
flag를 획득하게 된다.
'CTF > 웹해킹' 카테고리의 다른 글
[Dreamhack] web-misconf-1 (0) | 2022.09.13 |
---|---|
[Dreamhack] simple-ssti (0) | 2022.09.06 |
[Dreamhack] proxy-1 (0) | 2022.08.30 |
[Dreamhack] pathtraversal (0) | 2022.08.29 |
[Dreamhack] Web Hacking 초급 강의 후기 (0) | 2022.07.14 |