Given a script temp.php
in current user directory ~
:
#!/usr/bin/php
<?php
$p=$argv[$argc-1];
$a=file_exists($p);
echo "File exists?". $a ."\n";
include $p
?>
Using the script above, one can pass a filename as argument and retrieve its text content. I don't think it has any practical usages other than illustrating my problem. However, some CTF solutions leverage a malformed path string to include any file. It seems that no matter what precedes the string '?/../' or whether it exists, the following content will be treated as a path from the current directory.
cd ~
# Make the script executable
chmod +x temp.php
# Create a temporary file
echo empty > empty
./temp.php empty # Output "File exists?1" and "empty". It's fine and expected.
./temp.php 'test?/../empty' # Ouput 'empty' and a newline
./temp.php 'test?/../../../../../etc/hosts' # Output contents in /etc/hosts
I can't find related information documented on PHP page of the include statement. Does anyone have knowledge on this topic?
2020/04/18 21:06 Update. My PHP version is 7.2.24 on Ubuntu 18.04.
2020/04/18 21:20 Update. Orz maybe I figure out that it was the ..
causing the problem, not the question mark ?
. PHP include
seems to collapse consecutive ..
s. I am still wondering if this behavior was properly documented somewhere?
ubuntu@VM-0-5-ubuntu:~$ ./temp.php 'test/../empty'
File exists?
empty
ubuntu@VM-0-5-ubuntu:~$ ./temp.php 'test/../../ubuntu/empty'
File exists?
empty
ubuntu@VM-0-5-ubuntu:~$