Запрещаем конструкцию eval или как я написал расширение из 2х строк кода на С (ну почти 2х строк :))

Собственно задача - запретить "функцию" eval. Да да, все верно, я взял в кавычки, так как eval - это не функция, а языковая конструкция.

Все опасные функции можно выключить используя специальную директиву в файле php.ini, но не инструкции. Eval выключить через php.ini нельзя, увы.

Про особенности директивы можно прочитать в короткой заметке:

Override internal PHP functions
Переписать функцию PHP без специальных расширений и отладочных инструментов.Возможно ли? Спйолер: Да. Но есть нюанс. Сначала нужно функцию, которую хочется переопределить стереть. Асделать это можно через php.ini файл, вписав функцию в директиву: disable_functions = Для примера возьмем функцию …

Зачем?

Все просто. На одном из своих второстепенных серверов под всякие вордпресы я нашел залитый шел, который выглядел просто и содержал в себе вызов eval.

В общем озадачился такой идеей - выключить нахрен этот евал. Раньше существовал такой проект как Suhosin. Возможно он и сейчас существует, но вот под версию PHP 8 я его не нашел.

Вообще способов вызвать eval в PHP много, но с приходом версии 8, в этом плане многое стало лучше и старые способы уже не работают, такие как:

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()

В общем, давно я не трогал С, и не писал расширений под PHP. Так что я пошел в документацию

Writing PHP Extensions | Zend by Perforce

Скачал исходники PHP:

GitHub - php/php-src: The PHP Interpreter
The PHP Interpreter. Contribute to php/php-src development by creating an account on GitHub.

Создал скелет проекта, согласно документации и пошел изучать как устроено выполнение кода. Находим в исходниках вот такой вот файлик:

php-src/zend_execute.h at master · php/php-src
The PHP Interpreter. Contribute to php/php-src development by creating an account on GitHub.

и к нему же

php-src/zend_execute.c at master · php/php-src
The PHP Interpreter. Contribute to php/php-src development by creating an account on GitHub.

изучаем и прикидываем, что по сути задача наша сломать. Ломать не строить, но ломать тоже надо аккуратно.

Итого что выходит:


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;
}

Это если кратко. Полную версию расширения можно увидеть в репозитории на гитхабе: https://github.com/frontdevops/php-evil

Ну или все проще, можно сразу воспользоваться результатом:

# 1
git clone https://github.com/frontdevops/php-evil
# 2
cd php-evil
# 3
phpize
# 4
./configure
# or ./configure --enable-hide-presence (whether to hide presence this extension)
# 5
make && make install
# 6
# Add to php.ini extension=evil.so
disabled eval in PHP8

Я предусмотрел опцию: скрыть присутствие. По сути это просто другой вывод сообщения, который говорит что есть некая ошибка, вместо явного сообщения о том, что eval выключен.

php 8 - disabled eval

Github

GitHub - frontdevops/php-evil: Disable eval instruction in PHP8
Disable eval instruction in PHP8. Contribute to frontdevops/php-evil development by creating an account on GitHub.