---
title: 'PHP2Shell: критичен RCE в целия PHP | DevSense'
description: 'Разбор на PHP2Shell — CVE-2026-109618 и CVE-2026-109619, неудостоверен RCE в ядрото на PHP: как са устроени уязвимостите, с какво са опасни, кой се хвърли да кърпи и как да защитите сървъра си. Без работещ експлойт, с образователна цел.'
faq:
    - { question: 'Какво е PHP2Shell и кои версии на PHP са засегнати?', answer: 'PHP2Shell е общо име на две уязвимости в ядрото на PHP — CVE-2026-109618 и CVE-2026-109619, разкрити на 21 октомври 2026 г. Заедно те дават неудостоверено отдалечено изпълнение на код през най-обикновен разбор на HTTP заявка. Засегнати са практически всички клонове от последното десетилетие; поправките излязоха в PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35, а за 8.1/8.0/7.4 PHP пусна минимални бекпортове.' }
    - { question: 'Нужни ли са на атакуващия авторизация или уязвим плъгин?', answer: 'Не. Точно в това е същината: дупката е в самото ядро на PHP, по пътя на разбора на входящата заявка, който се изпълнява още преди кода на приложението. Не трябват нито логин, нито конкретна CMS, нито уязвим плъгин — достатъчно е сървърът да приема HTTP заявки и да върти PHP. Затова изследователите говорят за „70% от уеба“: това е делът на сайтовете на PHP, а не броят на реално пробитите сървъри.' }
    - { question: 'Използва ли се уязвимостта в реални атаки?', answer: 'Към момента на писане (третият ден след разкриването) публично потвърдени пробиви точно през PHP2Shell няма, но Cloudflare и други вече наблюдават сканиране и опити за експлоатация, при това с мутация на payload-а за заобикаляне на филтрите. При неудостоверен RCE с CVSS до 9.2 прозорецът между „никой не успя да обнови“ и „появиха се масови атаки“ се мери в дни.' }
    - { question: 'Какво да правя точно сега, ако не мога да обновя веднага?', answer: 'Обновяването на PHP е единственото пълно решение. Докато то не е разгърнато: включете WAF (Cloudflare, Fastly, Akamai, Imperva и облачните доставчици вече пуснаха защита по подразбиране), ограничете размера на тялото на заявката на обратното прокси, изключете session.upload_progress.enabled и на PHP 8.5 — fatal_error_backtraces, следете в логовете за грешки от изчерпана памет с „Unknown on line 0“ и за падащи работници. Това намалява риска, но не затваря дупката.' }
published: '2026-10-23'
---
# PHP2Shell: критичен RCE в целия PHP — какво се случи и как да се защитим

Има един особен сорт уязвимости — такива, които живеят не в нечий плъгин и не в кривия ред на конкретно приложение, а в самия фундамент, върху който стои всичко останало. PHP2Shell е точно такава. Това не е дупка в WordPress, не е гаф на един разработчик и не е забравен `eval()`. Това е пукнатина в носещата стена: в онзи код на ядрото на PHP, който разбира входящата заявка още преди да се изпълни първият ред на вашето приложение.

На 21 октомври 2026 г. PHP пусна спешни издания и разкри две уязвимости — **CVE-2026-109618** и **CVE-2026-109619**, — които заедно дават онова, от което в уеба почти нищо не е по-страшно: **неудостоверено отдалечено изпълнение на код**. Без логин. Без уязвим плъгин. Без нито едно кликване от жертвата. Тази статия е написана на третия ден след разкриването, когато кръпката вече я има, но половината интернет още не е обновен — и затова е написана без нито един ред работещ експлойт. Ще разберем какво се счупи и защо е толкова опасно, но няма да сложим оръжие в ръцете на никого. Целта е да опознаете врага и да затворите вратата, а не някой да сглоби атака по нашия текст.

**Свързани материали:** [Уеб атаки и защита от тях](web-attacks-and-prevention) · [Устойчиви интеграции](resilient-external-integrations) · [Наблюдаемост и мониторинг](observability-monitoring-laravel) · [Zero-downtime deployment](zero-downtime-deployment-laravel)

## Съдържание

* [Накратко: какво трябва да знаете за тридесет секунди](#tldr)
* [Защо уязвимост в ядрото е друг мащаб](#why-core)
* [Таймлайн: как ИИ намери дупката в целия PHP](#timeline)
* [Две врати: какво се крие зад двете CVE](#two-doors)
* [Колко сериозни са щетите](#impact)
* [Погледът на атакуващия: модел на заплахите без инструкция](#attacker)
* [Кой вече се хвърли да кърпи](#responders)
* [Има ли вече пострадали](#victims)
* [Как да се защитим: стъпка по стъпка](#defense)
* [Как да видим атаката в своите логове](#detection)
* [PHP е жив — и това е доказателството](#php-alive)
* [Чеклист](#checklist)
* [Тест за самопроверка](#self-test-quiz)

---

<a id="tldr"></a>
## Накратко: какво трябва да знаете за тридесет секунди

* **Какво:** две уязвимости в ядрото на PHP под общото име PHP2Shell — CVE-2026-109618 и CVE-2026-109619.
* **С какво заплашва:** неудостоверено отдалечено изпълнение на код (RCE), тежест до **CVSS 9.2**.
* **Кого засяга:** практически всички клонове на PHP от последното десетилетие, независимо от CMS и фреймуърка.
* **Къде е поправено:** PHP **8.5.12, 8.4.27, 8.3.36, 8.2.35**; за 8.1/8.0/7.4 — минимални бекпортове от екипа на PHP.
* **Какво да правите:** обновете PHP и рестартирайте PHP-FPM и работниците на опашките. Незабавно. Останалото са само временни подпори.

Ако четете това от продакшън на незакърпена версия — затворете статията, обновете се, върнете се. Сериозно.

---

<a id="why-core"></a>
## Защо уязвимост в ядрото е друг мащаб

Повечето уеб уязвимости приличат на незаключен прозорец в един конкретен апартамент: бъг в плъгин, SQL инжекция в самописан контролер, забравена проверка на правата. Поправяте апартамента — прозорецът е затворен. PHP2Shell е фабричен дефект в ключалката, която стои на всяка втора врата на планетата.

PHP обработва входящата заявка на слоеве. Първо — ядрото: то чете заглавките, разбира тялото на заявката, пълни суперглобалните масиви `$_POST`, `$_FILES`, `$_COOKIE`. И едва тогава управлението стига до вашия код — до рутера на Laravel, до ядрото на WordPress, до първия ред, който сте написали вие. PHP2Shell живее **на първия слой**. Уязвимият път се изпълнява при всички и винаги, просто защото сървърът е приел заявка.

Оттук идва и прочутата формулировка на изследователите за „70% от интернет“. Важно е да разберем какво означава тя: PHP обслужва около 70% от всички сайтове в света, и теоретичната повърхнина за атака — това са всички те. Това **не** значи, че 70% от сайтовете вече са пробити или че всеки от тях гарантирано се пробива с една заявка. Значи, че таванът на тази уязвимост е голям колкото целия уеб.

---

<a id="timeline"></a>
## Таймлайн: как ИИ намери дупката в целия PHP

Тази история има една подробност, заради която ще влезе в учебниците — и това не е самата уязвимост. Намериха я не с класически ръчен одит, а със свръзка от човек и ИИ. Изследователите от Wiz водиха търсенето с помощта на съвременни модели и по собствените им думи моделът внесе „неоценим принос“ не само в откриването, но и в превръщането на находките в работещи експлойти срещу няколко цели — „за часове“. Живеем в свят, в който fuzzing на ядрото на PHP води не само човек с дебъгер, но и ИИ, и двете страни на барикадата вече го разбраха.

Хронология на 2026 г. (по данни на Wiz):

| Дата | Събитие |
|------|---------|
| 19 август | Намерена е първата от уязвимостите |
| 20 август | Потвърден неудостоверен RCE срещу Drupal |
| 21 август | Потвърден неудостоверен RCE срещу WordPress |
| 24 август | Предадено на екипа по сигурност на PHP |
| 21 септември | PHP потвърди проблема и започна координирана поправка |
| 21 октомври | Издадени кръпки и извършено публично разкриване |

Почти два месеца — между тихото предаване на екипа на PHP и публичното разкриване. Това е и правилният, „зрелият“ процес: първо кърпят, после разказват. Статията, която четете, се появи два дни след последния ред от тази таблица.

---

<a id="two-doors"></a>
## Две врати: какво се крие зад двете CVE

Под името PHP2Shell се крият два различни дефекта — две врати към една и съща стая. Различните изследователи и доставчици описват залегналите в основата бъгове с малки разминавания в детайлите, и под всяко CVE се крие по-скоро клас проблеми, отколкото един-единствен ред. Нарочно оставаме на ниво механика — „какво точно се счупи“, — без да слизаме до рецептата за разкрутка до shell.

### CVE-2026-109618 — обработка на входящите данни на заявката

Първата врата се отваря на етапа, когато PHP разбира тялото на POST заявката и обработва качванията. Проблемът е в работата с паметта по този път: при определена форма на входните данни ядрото посяга към памет, която вече е освободило, или нарушава отчетността при заделянето ѝ. Там, където трябва да е спретнатото „заделих — използвах — освободих“, възниква прозорец, в който състоянието на паметта спира да отговаря на очакванията на кода. А нарушената работа с паметта в нативен код е класически трамплин: от нея води път и към изтичане на парченца от паметта на процеса (а значи и към заобикаляне на защити като ASLR), и към контрол над изпълнението.

Ключова подробност: този път не изисква нито авторизация, нито специална конфигурация на приложението. Достатъчно е PHP автоматично да разбира тялото на заявката — а той прави това винаги.

### CVE-2026-109619 — остатъчно състояние между заявките

Втората врата е по-фина и в някакъв смисъл по-изящна. PHP-FPM е дълго живеещ процес: един и същ работник обслужва заявка след заявка, без да презарежда фреймуърка (защо това е едновременно бързо и опасно, разбрахме в статията за [опашките в продакшън](laravel-queues-production#memory)). Ако след обработката на една заявка в работника остане „боклучаво“ състояние — например от механизма за проследяване на прогреса при качване на файлове (`session.upload_progress`) или от формирането на трасировки на фатални грешки, — то следващата заявка може да се натъкне на тези вкиснати данни. Една заявка подготвя капана, втората попада в него.

Коварството е в това, че част от тези механизми работят дори ако приложението никога не ги е извиквало явно. `session.upload_progress` е включен по подразбиране и се задейства без нито един `session_start()` във вашия код.

> [!NOTE]
> Запомнете двете настройки от втората врата — `session.upload_progress.enabled` и (на PHP 8.5) `fatal_error_backtraces`. По-долу, в раздела за защитата, точно тях ще прикриваме, ако обновяването точно сега е невъзможно.

---

<a id="impact"></a>
## Колко сериозни са щетите

RCE е върхът на хранителната верига на уязвимостите. Не „изтекоха данни“, не „подмениха страница“, а **чужд код се изпълнява на вашия сървър с правата на вашия уеб процес**. Какво означава това на практика:

* **Пълен контрол над приложението.** Атакуващият чете и променя каквото пожелае в кода и файловете, достъпни за `www-data`.
* **Достъп до тайните.** `.env` с паролата от базата, ключовете на платежните системи, API токените, `APP_KEY` — всичко, което процесът може да прочете, го чете и атакуващият.
* **Цялата база данни.** Не през хитра инжекция, а директно — със същите данни за достъп като приложението.
* **Странично придвижване.** Сървърът се превръща в плацдарм: оттук сканират вътрешната мрежа, атакуват съседните услуги, закрепват се през уеб shell.
* **Тишина.** Успешната експлоатация може да върне обикновен HTTP 200 и да не събори работника. Отвън — нищо, отвътре — чуждият вече е у дома.

За сайт като DevSense, където няма плащания и персонални данни на потребителите над минимума, преките щети са по-малки, отколкото за онлайн магазин или банка. Но „по-малки“ не значи „никакви“: дори нашият сървър е достъп до БД, до пощенските ключове, до инфраструктурата за деплой и отличен плацдарм за атаки срещу други. Затова [обновихме PHP](../tools/dockerfile-php-best-practices) още същия ден.

---

<a id="attacker"></a>
## Погледът на атакуващия: модел на заплахите без инструкция

Полезно е да погледнем уязвимостта през очите на атакуващия — така по-ясно се вижда къде да сложим защитата. Но „погледът на атакуващия“ тук означава **модел на заплахите и икономика на атаката**, а не рецепта стъпка по стъпка. Рецепта няма да дадем по принцип: на два дни е, бие по неудостоверен RCE, и половината сървъри още не са затворени.

Какво движи атакуващия в такава ситуация:

* **Масовостта е по-важна от точността.** Когато е уязвим „целият уеб“, никой не избира жертва прицелно. Пуска се широко сканиране: пробваме всички подред, закрепваме се при онези, у които е сработило. Вашият сайт попада под удар не защото сте интересни, а защото съществувате и отговаряте на заявки.
* **Надпревара с кръпката.** Стойността на експлойта е най-висока в първите дни, докато масите не са се обновили. Оттук и скокът на активността веднага след разкриването — той вече се наблюдава.
* **Заобикаляне на филтрите.** Щом доставчиците на WAF пуснаха правила, атакуващите започнаха да мутират payload-а, за да не попадат под тях. Това вече е засечено от Cloudflare. Изводът за вас: WAF е спечелено време, а не победа. Побеждава само кръпката.
* **Автоматизацията е и на тяхна страна.** Ако ИИ помогна да се намери и разкрути уязвимостта за часове от страната на изследователите, то и от страната на нападателите цикълът „от CVE до масов скенер“ стана по-кратък от всякога.

Практическият смисъл на тази оптика е един: не разчитайте, че „моят малък сайт на никого не трябва“. В света на широкообхватните атаки ненужни сайтове няма.

---

<a id="responders"></a>
## Кой вече се хвърли да кърпи

Добрата новина: индустрията реагира на PHP2Shell като сплотен организъм, и това е може би най-добрата илюстрация, че екосистемата на PHP е жива и здрава. Разкриването беше координирано — към час Х защитата вече беше на място.

* **Cloudflare** пусна правила за WAF **около 9 часа преди публичното разкриване** и включи защитата по подразбиране на 21 октомври в 3:02 UTC — на всички планове, включително безплатния, без действие от страна на клиента. По техни данни вече виждат атакуващ трафик и неговите мутации.
* **Fastly, Akamai, Imperva** — пуснаха собствени защитни правила за клиентите, които не могат да се обновят мигновено.
* **AWS, Google Cloud, Microsoft, Vercel** — публикуваха ръководства за реагиране и защита на ниво собствени платформи.
* **Automattic** (компанията зад WordPress.com) и други участници в екосистемата — са в списъка на онези, които помогнаха с координирания отговор.

Отделно си струва да отбележим самия екип по сигурност на PHP: два месеца тиха работа, синхронно издаване на кръпки по всички поддържани клонове и дори бекпортове за клоновете, чиято официална поддръжка вече е приключила (7.4, 8.0, 8.1). За проект, който години наред погребват в коментарите, това е образцова реакция.

---

<a id="victims"></a>
## Има ли вече пострадали

Тук е важно да бъдем честни и да не множим паниката. **На третия ден след разкриването публично потвърдени пробиви точно през PHP2Shell няма.** Нито една голяма организация не е назована за жертва засега.

Но няколко неща се знаят със сигурност:

* Работещи експлойти съществуват — демонстрирани са от изследователите срещу свежи образи на WordPress, Drupal и Joomla. Това е демонстрация на повърхнината, а не коренът на проблема: въпросът не е в тези CMS, а в PHP под тях.
* Сканиране и опити за експлоатация вече текат — за това говорят и Cloudflare, който наблюдава атакуващ трафик, и отрасловите сводки, фиксиращи „появата на опити за експлоатация“.
* Липсата на публични жертви на третия ден не е „размина ни се“, а „още е рано“. Между масовото сканиране и първите публични доклади за пробиви обикновено минават седмици. Прозорецът, в който трябва да успеете да се обновите, е отворен точно сега.

С прости думи: тишината на таблото не е отбой, а преднина. Използвайте я.

---

<a id="defense"></a>
## Как да се защитим: стъпка по стъпка

### 1. Обновете PHP — това е единственото истинско решение

Всичко останало по-долу са подпори, които купуват време. Дупката я затваря само кръпката.

```bash
# Debian/Ubuntu, хранилище на Ondřej Surý (както е при нас)
sudo apt-get update
sudo apt-get install --only-upgrade -y \
  $(dpkg-query -W -f='${db:Status-Abbrev} ${Package}\n' 'php8.5*' | awk '$1 == "ii" {print $2}')

# Рестартирайте всичко, което държи стария бинарник в паметта
sudo systemctl restart php8.5-fpm
sudo supervisorctl restart all   # работниците на опашките също са PHP
```

Целеви версии: **8.5.12 / 8.4.27 / 8.3.36 / 8.2.35** или по-нови. Проверете и CLI, и FPM:

```bash
php -v | head -1
/usr/sbin/php-fpm8.5 -v | head -1
```

> [!WARNING]
> Рестартирането на PHP-FPM е задължително. Дълго живеещият процес държи стария, уязвим бинарник в паметта дори след `apt upgrade`, докато не бъде рестартиран. Същото важи за работниците на опашките под Supervisor или Horizon — те не виждат новия PHP до рестарт.

Подробно за обновяването и пресглобяването на образите — в нашия разбор на [production образа за PHP](../tools/dockerfile-php-best-practices).

### 2. Вдигнете WAF

Ако сте зад Cloudflare — защитата вече е включена по подразбиране, проверете само дали правилата са в режим на блокиране. Fastly, Akamai, Imperva и облачните доставчици пуснаха аналогично. Помнете за мутацията на payload: WAF е временна мярка.

### 3. Ограничете тялото на заявката на границата

На обратното прокси (nginx, балансьор) отрежете аномално големите тела на заявките, преди да стигнат до PHP. Това не лекува, но събаря значителна част от автоматичните опити.

### 4. Прикрийте втората врата с настройки

Ако кръпката още не е разгърната — изключете механизмите, през които работи CVE-2026-109619. DevSense не ги използва, на работата на сайта това не влияе:

```ini
; /etc/php/8.5/fpm/conf.d/99-hardening.ini
session.upload_progress.enabled = 0
fatal_error_backtraces = 0   ; само PHP 8.5
expose_php = Off
```

```bash
sudo systemctl restart php8.5-fpm
```

Това намалява експозицията, но **не заменя обновяването**.

---

<a id="detection"></a>
## Как да видим атаката в своите логове

Защитата без наблюдаемост е сляпа. Ето честните индикатори, на които си струва да гледате (нито един от тях сам по себе си не доказва пробив — важна е корелацията):

* **В логовете на PHP-FPM:** `Allowed memory size ... exhausted` в свръзка с `Unknown on line 0`. Редът `on line 0` означава, че падането е станало на етапа на инициализация на заявката, още преди кода на приложението — точно там живее първата врата.
* **Падане на работници:** segfault-и (`SIGSEGV`, `exited on signal 11`) в логовете на PHP-FPM или Apache, особено на серии.
* **Аномални заявки:** POST с необичайно дълги имена на полета (от порядъка на мегабайти), двоични данни и нулеви байтове в стойностите на полетата.
* **Необичайно голяма cookie `PHPSESSID`** — един от признаците, които посочват самите изследователи.
* **Процеси-сираци от уеб потребителя:** shell, стартиран от `www-data`, вече не е признак, а почти присъда:

```bash
ps -eo user,pid,ppid,cmd | awk '$1=="www-data"' | grep -vE "php-fpm|nginx"
sudo grep -h "Unknown on line 0" /var/log/php8.5-fpm.log* 2>/dev/null | tail
```

Как да вградим такива сигнали в постоянен мониторинг и алерти — в статията за [наблюдаемостта](observability-monitoring-laravel).

---

<a id="php-alive"></a>
## PHP е жив — и това е доказателството

PHP го погребват със завидна редовност. „Мъртъв език“, „легаси“, „всички минаха на Node и Go“ — този некролог го пишат всяка година. PHP2Shell, колкото и парадоксално да звучи, е аргумент точно в обратната посока.

Първо, уязвимост от такъв мащаб е възможна само при технология, върху която реално стои огромна част от уеба. Мъртвите езици не попадат в заглавията на CISA и не карат Cloudflare да пуска защита девет часа преди разкриването. В дупка с размера на 70% от интернет пропада само това, което този интернет държи.

Второ — и това е най-важното — погледнете реакцията. Екипът по сигурност на PHP проведе образцова координирана поправка, издаде кръпки по всички клонове синхронно и дори бекпортира фиксовете в клонове без официална поддръжка. Цялата индустрия — от Automattic до AWS — отработи като единен организъм. Така се държи не умиращ проект, а зряла, жива екосистема със зрели процеси.

PHP 8.5 с property hooks, асиметрична видимост, типизирани свойства и pipe оператор е съвременен език, а не музеен експонат. Живото има имунна система, и през октомври 2026 г. тя сработи бързо и сплотено. Жив и здрав — включително защото умее бързо да лекува такива рани.

---

<a id="checklist"></a>
## Чеклист

1. PHP е обновен до 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 или по-нов — и CLI, и PHP-FPM.
2. PHP-FPM е рестартиран; работниците на опашките (Supervisor/Horizon) са рестартирани.
3. Проверено е, че процесът на FPM не държи стария бинарник (`/proc/<pid>/exe` без отметка `(deleted)`).
4. WAF е включен и в режим на блокиране; помнете за временността на тази мярка.
5. На границата е ограничен размерът на тялото на заявката.
6. Ако кръпката не е разгърната — изключени са `session.upload_progress.enabled` и `fatal_error_backtraces`.
7. Логовете са проверени за `Unknown on line 0`, segfault-и и shell-ове от `www-data`.
8. Образите на контейнерите са пресглобени и предеплойнати, ако PHP се слага от образ.

---

## Обобщение

PHP2Shell е рядък случай, в който уязвимостта е интересна не само с това, което чупи, но и с това, което показва. Чупи тя фундамента: неудостоверен RCE в ядрото, под което стои голяма част от уеба. А показва — че екосистемата около това ядро е жива, бърза и сплотена. Кръпката излезе, големите играчи прикриха със себе си онези, които не успяха, а от вас се иска едно просто действие: обновете се и рестартирайте. Направете го, преди да свърши преднината.

---

<a id="self-test-quiz"></a>
## Тест за самопроверка

### Въпрос 1: Защо PHP2Shell е по-опасна от типична уязвимост в плъгин на CMS?
- А) Защото е по-трудна за откриване от скенери.
- Б) Защото е в ядрото на PHP, по пътя на разбора на заявката, и се задейства преди кода на приложението — без авторизация и независимо от CMS или фреймуърка.
- В) Защото засяга само остарели версии на PHP.

<details>
<summary>Покажи правилния отговор</summary>

**Правилен отговор: Б**
Дефектът живее на първия слой на обработка на заявката, общ за всички PHP приложения. Нито логин, нито конкретна CMS, нито уязвим плъгин са нужни — достатъчно е сървърът да приема заявки и да изпълнява PHP.
</details>

### Въпрос 2: Защо след `apt upgrade` е задължително да се рестартират PHP-FPM и работниците на опашките?
- А) Иначе няма да се обновят конфигурационните файлове.
- Б) Защото дълго живеещите процеси държат стария, уязвим бинарник на PHP в паметта, докато не бъдат рестартирани.
- В) За да се нулира OPcache от статичните страници.

<details>
<summary>Покажи правилния отговор</summary>

**Правилен отговор: Б**
PHP-FPM и работниците на опашките са дълго живеещи процеси. Те продължават да изпълняват стария бинарник, зареден в паметта, дори след обновяване на пакета, докато не бъдат рестартирани. Проверка може да се направи по символната връзка `/proc/<pid>/exe`.
</details>

### Въпрос 3: Защо WAF е спечелено време, а не пълно решение?
- А) WAF забавя сайта и се налага да бъде изключен.
- Б) Защото атакуващите мутират payload-а, за да заобикалят правилата — дупката я затваря само обновяването на PHP.
- В) Защото WAF защитава само от удостоверени атаки.

<details>
<summary>Покажи правилния отговор</summary>

**Правилен отговор: Б**
Правилата на WAF филтрират известните форми на атака, но нападателите вече мутират payload-а, за да не попадат под тях (това е засечено от Cloudflare). WAF намалява риска и купува време за обновяване, но единственото пълно решение е кръпката.
</details>