Disable eval in PHP 8
Evil — extension for PHP8

Prohibiting the use of eval or how I wrote a 2-line C extension (well, almost 2 lines 😀)
The task at hand is to prohibit the use of the “function” eval. Yes, indeed, I put it in quotes because eval is not a function, but a language construct.
All dangerous functions can be disabled using a special directive in the php.ini file, but not constructs. Unfortunately, eval cannot be disabled through php.ini.
Override internal PHP functions Let’s take a step back and figure out how to rewrite a function in PHP without special extensions and debugging tools. Is it possible? Spoiler: Yes. But there is a catch. First, we need to delete the function we want to override. This can be done by adding the function to the directive in the php.ini file:
disable_functions =
For example, let’s take the function date and do the following:
php.ini
disable_functions = date
auto_prepend_file = path/to/my_defined_functions.php
Write something like this:
<?php declare(strict_types=1);
/**
@param string $s
@return string
*/
function date(string $s): string {
return 'Does the date really matter?';
}
echo date('d.m.Y');
That’s it. There is no longer a built-in date function. This is how potentially dangerous functions are handled, which could potentially compromise the system.
Let’s get back to the topic of our article. On one of my secondary servers for various WordPress sites, I found an uploaded shell that looked simple and contained an eval call.
In general, I was intrigued by the idea of disabling this eval. There used to be a project called Suhosin. Maybe it still exists, but I couldn’t find it for PHP 8.
There are many ways to call eval in PHP, but with the arrival of version 8, many things have improved, and old methods no longer work, such as:
preg_replace('/a/e', $_REQUEST['shell'], 'a');
// Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
mb_ereg_replace(‘a’, $_REQUEST[‘shell’], ‘a’, ‘e’); // Fatal error: Uncaught ValueError: Option “e” is not supported
create_function(“fn() => 1”); // Fatal error: Uncaught Error: Call to undefined function create_function()
In general, I haven’t touched C in a long time and haven’t written extensions for PHP. So I went to the documentation:
Downloaded the PHP sources:
Created a project skeleton according to the documentation and started studying how code execution works. We find a file like this in the source code:
and to the same:
We study and estimate what our task is to break. Breaking, not building, but breaking must also be done carefully. So what do we get:
void evil_execute_ex(zend_execute_data *execute_data)
{
if (execute_data->opline && (execute_data->opline->opcode == ZEND_INCLUDE_OR_EVAL) && (execute_data->opline->extended_value == ZEND_EVAL))
{
zend_error(E_ERROR, “Eval disabled!”);
return;
}
zend_old_execute_ex(execute_data);
}
PHP_MINIT_FUNCTION(evil)
{
zend_old_execute_ex = zend_execute_ex;
zend_execute_ex = evil_execute_ex;
return SUCCESS;
}
That’s if you want it in short. The full version of the extension can be seen in the repository on GitHub:
Or, it’s even easier, you can just use the result:
git clone https://github.com/frontdevops/php-evil
cd php-evil
phpize
./configure or ./configure —enable-hide-presence (whether to hide presence this extension)
make && make install
# Add to php.ini extension=evil.so

I have provided an option to hide the presence. In fact, this is just a different message output that says that there is an error, instead of an explicit message that eval is disabled.
