Skip to content

Commit

Permalink
πŸ”’ Updates for Custom Build of PHP, Testing, Docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ConradSollitt committed Jan 13, 2022
1 parent 28f9a15 commit 058f41f
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 48 deletions.
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# :star2: FastSitePHP Playground
# 🌟 FastSitePHP Playground

**Thanks for visiting!** πŸŒ πŸ‘

Expand Down Expand Up @@ -27,21 +27,21 @@
</tbody>
</table>

## :gear: How it works
## βš™οΈ How it works

<p align="center">
<img src="https://github.com/fastsitephp/static-files/blob/master/img/playground/How-it-Works.svg" alt="Playground - How it works">
</p>

**Update - December 30th, 2021**

Originally this site was hosted on a separate server for years but now the playground is hosted on the same server as the main site along with several other open source sites. This site and the other sites do not get enough traffic to justify the need for separate servers so now only 1 server is used. See detailed setup docs for more. Logic from the above graphic still applies except the separate server.
Originally this site was hosted on a separate server for several years but now the playground is hosted on the same server as the main site along with several other open source sites. This site and the other sites do not get enough traffic to justify the need for separate servers so now only 1 server is used. See detailed setup docs for more. Logic from the above graphic still applies except the separate server.

## :gear: Detailed Server Setup
## βš™οΈ Detailed Server Setup

https://github.com/fastsitephp/playground/blob/master/docs/Playground%20Server%20Setup.txt
https://github.com/fastsitephp/playground/blob/master/docs/playground-server-setup.sh

## :desktop_computer: Running Locally
## πŸ–₯️ Running Locally

Download this repository then run the install script. This will also generate a new `app_data/.env` file which is used for authentication.

Expand All @@ -58,13 +58,22 @@ https://github.com/fastsitephp/fastsitephp/blob/master/website/public/js/playgro

When you run locally on a standard build of PHP user sites will be insecure however this is acceptable for local development.

## :handshake: Contributing
## 🀝 Contributing

* If you find a typo or grammar error please fix and submit.
* Additional language template translations are needed. Refer to the main project if you can help with translations.
* Any changes to the core code will likely not be accepted unless you first open an issue. A lot of security is needed in order to make this site work so every line of code must be carefully considered.
* If you think you’ve found a minor issue with security or have additional security ideas please open an issue. No financial transactions other than the cost of the server are dependent on this site so opening a public issue is ok. However if you are able to write files, obtain root or sudo access to the server then please [get in touch privately](https://www.fastsitephp.com/en/security-issue).

## :memo: License
## πŸ”’ Security

* The actual site uses the following disclaimer `Please do not attack this site or use it for malicious purposes`, however if you are a security researcher its understandable that you may want to test the security of this site.
* Reasonable testing is acceptable however if the site ends up being compromised maliciously or attacks slow down the main sites then it may be taken down so please keep that in mind.
* For manual testing and details on what would be a good starting point to attack the site see files:
* https://github.com/fastsitephp/playground/blob/master/scripts/app-error-testing.php
* https://github.com/fastsitephp/playground/blob/master/scripts/app-error-testing-2.php
* If you think you’ve found an issue with security or have additional security ideas please open an issue. This site has a niche audience and no financial transactions other than the cost of the server ($5 USD a month) are dependent on this site so opening a public issue is ok even if you have an exploit. You can also get in touch privately from: https://www.fastsitephp.com/en/security-issue
* If you accidentally cause serious problems to the server or take it down the please get in contact with the author immediately so a new server can be setup. If someone take the server down from the playground I would be more interested in how and if it can be prevented rather than worried about the server itself.

## πŸ“ License

This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.
40 changes: 25 additions & 15 deletions docs/PHP Custom Build Instructions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
This file provides info on how which files to edit for the custom build of PHP.
Basically a single INI setting is added [file_access_is_limited] that allows for
some requests to have access to writing and modifying files while other requests
will only have read access - using the feature properly requires the function
[ini_set()] to be disabled from [php.ini].
will only have read access.

See the file [Playground Server Setup.txt] for full build and setup instructions.
Using the feature properly requires the function [ini_set()] to be disabled from
[php.ini] and more importantly [ini_set()] is also disabled from the custom build
of PHP. Originally when FastSitePHP was published [php.ini] setting [disable_functions]
was used however based on https://github.com/mm0r1/exploits it can be bypassed by
user code so the custom build of PHP is needed and now a separate script is used
during server setup to update many files.

See the file [playground-server-setup.sh] for full build and setup instructions.

--------------------------------------------------------------------------------------
| Helpful Links for building and working with PHP Source
Expand All @@ -29,7 +35,7 @@ https://eddmann.com/posts/introduction-to-creating-a-basic-php-extension/
https://php.tutorials24x7.com/blog/how-to-install-php-8-from-source-on-ubuntu-20-04-lts

--------------------------------------------------------------------------------------
| ext\standard\file.h
| ext/standard/file.h
--------------------------------------------------------------------------------------
*) Under:
typedef struct {
Expand All @@ -42,7 +48,7 @@ https://php.tutorials24x7.com/blog/how-to-install-php-8-from-source-on-ubuntu-20
int pclose_ret;

--------------------------------------------------------------------------------------
| ext\standard\file.c
| ext/standard/file.c
--------------------------------------------------------------------------------------
*) Before:
PHP_INI_END()
Expand Down Expand Up @@ -106,17 +112,21 @@ https://php.tutorials24x7.com/blog/how-to-install-php-8-from-source-on-ubuntu-20
}

--------------------------------------------------------------------------------------
| ext\standard\exec.c
| main/php.h
--------------------------------------------------------------------------------------
# 4 functions end up being disabled in code. Originally when FastSitePHP
# was published [php.ini] setting [disable_functions] was used however
# based on https://github.com/mm0r1/exploits it can be bypassed by user code
# so the custom build of PHP is needed.
*) Under:
#define PHP_METHOD ZEND_METHOD
*) Add:
#define DISABLED_FOR_PLAYGROUND \
php_error_docref(NULL, E_ERROR, "This function is disabled by using a custom PHP build for the FastSitePHP Playground."); \
RETURN_FALSE

PHP_FUNCTION(shell_exec)
PHP_FUNCTION(exec)
--------------------------------------------------------------------------------------
| Many files are also updated from the script [update-php-c-source-files.php]
| All of the updates are related to the custom C Macro `DISABLED_FOR_PLAYGROUND()`
| How it works it the first line of each function ends up with the Macro.
| Example below for [ext\standard\exec.c]. See the PHP script for details.
--------------------------------------------------------------------------------------
PHP_FUNCTION(system)
PHP_FUNCTION(passthru)
{
php_error_docref(NULL, E_ERROR, "This function is disabled by using a custom PHP build for the FastSitePHP Playground.");
RETURN_FALSE;
DISABLED_FOR_PLAYGROUND;
7 changes: 5 additions & 2 deletions docs/PHP INI Settings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
zend_extension=opcache.so
# or for PHP 8 uncomment line: [zend_extension=opcache]

# Edit and verify the following:
# Edit and verify the following
# Many other functions with file i/o exist (example: gzwrite), however
# the custom build of PHP excludes many functions by default so they
# do not have to be added to the disabled list.
allow_url_fopen = Off
allow_url_include = Off
file_uploads = Off
Expand All @@ -35,5 +38,5 @@ post_max_size = 1M
default_socket_timeout = 1
enable_dl = Off
opcache.revalidate_freq=0
disable_functions = ini_set, ini_restore, exec, passthru, shell_exec, system, proc_open, proc_nice, popen, curl_exec, curl_multi_exec, dl, sleep, usleep, gc_disable, set_include_path, set_time_limit, tempnam, tmpfile, fopen, fwrite, ftruncate, fputcsv, link, umask, touch, chown, chmod, chgrp, glob, symlink, stream_socket_client, stream_socket_server, stream_context_create, stream_socket_pair, dns_get_record, dns_check_record, dns_get_mx, fsockopen, pfsockopen, setcookie, setrawcookie, syslog, openlog, stream_wrapper_restore, finfo_set_flags, gzwrite, gzwrite, mail, session_start, session_create_id, error_log
disable_functions = ini_set, ini_restore, exec, passthru, shell_exec, system, proc_open, proc_nice, popen, curl_exec, curl_multi_exec, dl, sleep, usleep, set_include_path, set_time_limit, tempnam, tmpfile, fopen, fwrite, ftruncate, fputcsv, link, umask, touch, chown, chmod, chgrp, glob, symlink, stream_socket_client, stream_socket_server, stream_context_create, stream_socket_pair, dns_get_record, dns_check_record, dns_get_mx, fsockopen, pfsockopen, setcookie, setrawcookie, syslog, openlog, stream_wrapper_restore, finfo_set_flags, mail, session_start, session_create_id, error_log, lchown, lchgrp, move_uploaded_file
disable_classes = SplFileObject, SplTempFileObject, FilesystemIterator, DirectoryIterator, GlobIterator
11 changes: 6 additions & 5 deletions docs/playground-server-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,18 @@ mkdir /var/www/fastsitephp-playground/public/sites

# Setup custom build of PHP with Apache for FastSitePHP Playground
which php
# This is the active version of PHP prior to these commands
# This is the active version of PHP prior to these commands (and needed if re-running)
# Output: /usr/bin/php
sudo apt install -y apache2 apache2-dev libxml2-dev
wget https://www.php.net/distributions/php-7.4.27.tar.bz2
tar xjf php-7.4.27.tar.bz2
wget https://fastsitephp.s3-us-west-1.amazonaws.com/playground/php-7.4.27/file.h
wget https://fastsitephp.s3-us-west-1.amazonaws.com/playground/php-7.4.27/file.c
wget https://fastsitephp.s3-us-west-1.amazonaws.com/playground/php-7.4.27/exec.c
wget https://fastsitephp.s3.us-west-1.amazonaws.com/playground/php-7.4.27/php.h
mv file.h ~/php-7.4.27/ext/standard/file.h
mv file.c ~/php-7.4.27/ext/standard/file.c
mv exec.c ~/php-7.4.27/ext/standard/exec.c
mv php.h ~/php-7.4.27/main/php.h
/usr/bin/php /var/www/fastsitephp-playground/scripts/update-php-c-source-files.php
cd php-7.4.27
./configure --with-apxs2=/usr/bin/apxs --disable-all --enable-json --enable-filter --enable-ctype --enable-opcache
# run `make` - this is expected to take several minutes once `wait` is called on most servers
Expand Down Expand Up @@ -137,7 +138,7 @@ sudo service apache2 restart
# Runs once per minute, if not using [sudo] then sites will end up not being deleted.
sudo crontab -e
# Enter [1] for nano, and add the following after header comments:
* * * * * /usr/bin/php /var/www/scripts/delete-expired-sites.php > /var/www/app_data/last-cron-job.txt 2>&1
* * * * * /usr/bin/php /var/www/fastsitephp-playground/scripts/delete-expired-sites.php > /var/www/fastsitephp-playground/app_data/last-cron-job.txt 2>&1

# Point ngnix to the Apache site running at 127.0.0.1:8080
nano nginx-config.txt
Expand Down Expand Up @@ -182,6 +183,6 @@ sudo reboot
# - Run local build of FastSitePHP and you can test the new playground server.
# See the readme and docs on how to run FastSitePHP. The setup is quick and simple.
# - Try the site and verify it works and shows the installed version of PHP.
# - Copy and paste contents from the following PHP server side scripts to verify errors:
# - Copy and paste contents from the following PHP server side scripts to verify error tests:
# scripts/app-error-testing.php
# scripts/app-error-testing-2.php
100 changes: 83 additions & 17 deletions scripts/app-error-testing.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
// PHP Build on a live server most routes will fail with an expected error.
//
// To use copy the contents of this file to [app.php] after creating a custom site.
//
// If you are a security research and interested in testing attacks the first
// thing to do would be to overwrite the [.htaccess] file root of the temporary
// site. If that file can be overwritten then you will have full write access
// to the server (as allowed under Apache permissions) and that would be a good
// starting point for more serious exploits. If you do use this site to test
// security and accidentally take down the server or cause serious issues with it
// then please let the author of FastSitePHP know so that the issue can be fixed
// and so a new server can be setup (if needed) in a timely manner.
//
// For more Advanced Exploit Testing see the file [app-error-testing-2.php].

$app->get('/', function() use ($app) {
$html = <<<'HTML'
Expand All @@ -30,6 +41,7 @@
<li><a href="timeout">Timeout Test</a></li>
<li><a href="error-log">Check Error Log</a></li>
<li><a href="memory">Memory Limit</a></li>
<li><a href="disabled-object">Disabled Object</a></li>
<li><a href="error-page">Error Page</a></li>
<li><a href="php-func">PHP Classes and Functions</a></li>
<li><a href="php-info">PHP Info</a></li>
Expand Down Expand Up @@ -117,7 +129,9 @@
});

// Error when function is disabled:
// ini_set() has been disabled for security reasons
// ini_set() has been disabled for security reasons
// Error when disabled with custom PHP build:
// ini_set(): This function is disabled by using a custom PHP build for the FastSitePHP Playground.
$app->get('/ini-set', function() {
ini_set('display_errors', 'off');
return ini_get('display_errors');
Expand Down Expand Up @@ -178,7 +192,7 @@
// This should show an empty array
var_dump($_FILES);

// If an actual file made it to the server then the folowing could be used:
// If an actual file made it to the server then the following could be used:
// move_uploaded_file($filename, $destination)
});

Expand All @@ -194,10 +208,13 @@
});

// Make sure `error_log()` can't be used to overwrite `.htaccess`.
// This would overwrite the file so it works on the server and does not
// include settings [open_basedir, file_access_is_limited]; with those
// two settings excluded a end-user will have full-write access to any
// folder visible to PHP and Apache.
$app->get('/error-log', function() use ($app) {
$s = "php_value open_basedir /\n";
$s .= "php_flag file_access_is_limited off\n";
error_log($s, 3, __DIR__ . '/../.htaccess');
$contents = "FallbackResource index.php";
error_log($contents, 3, __DIR__ . '/../.htaccess');
return 'Success [.htaccess] is overwritten';
});

Expand All @@ -210,31 +227,80 @@
}
});

// Error when disabled from [php.ini]:
// SplFileObject() has been disabled for security reasons
// If using the custom build of PHP but standard [php.ini] settings:
// SplFileObject::__construct(): This function is disabled by using a custom PHP build for the FastSitePHP Playground.
$app->get('/disabled-object', function() use ($app) {
$app->header('Content-Type', 'text/plain');
$text = '';
$file = new SplFileObject(__FILE__);
foreach ($file as $line_num => $line) {
$text .= "$line_num: $line";
}
return $text;
});

// This should return the standard error template
$app->get('/error-page', function() {
throw new \Exception('Test');
});

// Use this to see what is enabled on the server
// IMPORTANT - [php.ini] settings [disable_functions] and other settings are not secure
// from advanced exploits. Because of this fact a custom build of PHP is used to fully
// block the disabled functions and classes. See [app-error-testing-2.php] for more.
// This code is making assumptions that disabled function and classes listed here
// are actually disabled in the build.
$app->get('/php-func', function() use ($app) {
$classes = array_values(get_declared_classes());
$disabled_classes = ini_get('disable_classes');
$disabled_classes = explode(',', str_replace(' ', '', $disabled_classes));
$classes = array_diff($classes, $disabled_classes);
$text = str_repeat('-', 80) . "\n";
$text .= count($classes) . " Classes\n";
$text .= str_repeat('-', 80) . "\n";
foreach ($classes as $name) {
$text .= $name . "\n";
}

$functions = get_defined_functions(true);
$functions = get_defined_functions(false);
$functions = array_values($functions['internal']);
$text .= "\n\n" . str_repeat('-', 80) . "\n";
$text .= count($functions) . ' Functions' . "\n";
$text .= str_repeat('-', 80) . "\n";
foreach ($functions as $name) {
$text .= $name . "\n";
if (filter_var(ini_get('file_access_is_limited'), FILTER_VALIDATE_BOOLEAN) === true) {
// This info is hard-coded on the assumption that PHP is built with modified functions.
// This script confirms each modified function.
$modified_functions = ['file_put_contents', 'mkdir', 'rmdir', 'rename', 'unlink', 'copy'];
} else {
$modified_functions = [];
}
$disabled_functions = ini_get('disable_functions');
$disabled_functions = explode(',', str_replace(' ', '', $disabled_functions));
$unused_disabled_fn = [];
foreach ($disabled_functions as $fn) {
if (!in_array($fn, $functions)) {
$unused_disabled_fn[] = $fn;
}
}
$functions = array_diff($functions, $disabled_functions);
$functions = array_diff($functions, $modified_functions);

$obj_groups = [
[$modified_functions, 'Modified Functions'],
[$disabled_classes, 'Disabled Classes'],
[$disabled_functions, 'Disabled Functions'],
[$unused_disabled_fn, 'Disabled Functions (Not included with this PHP Build)'],
[$classes, 'Classes'],
[$functions, 'Functions'],
];

$text = '';
foreach ($obj_groups as $group) {
$fn = $group[0];
if (count($fn) === 0) {
continue;
}
$label = $group[1];
$text .= "\n" . str_repeat('-', 80) . "\n";
$text .= count($fn) . ' ' . $label . "\n";
$text .= str_repeat('-', 80) . "\n";
foreach ($fn as $name) {
$text .= $name . "\n";
}
$text .= "\n";
}

$app->header('Content-Type', 'text/plain');
Expand Down
Loading

0 comments on commit 058f41f

Please sign in to comment.