Уязвимость: приведение типов без проверки границ превращает заголовок в отрицательный размер массива

Когда Android получает WAP Push сообщение, функция WapPushOverSms.decodeWapPdu() читает длину заголовка WSP как uintvar. Значение возвращается как long, приводится к int без проверки диапазона и затем используется прямо как размер нового массива байт:

// WapPushOverSms.java:217  заголовок прочитан как long, приведен без проверки границ
int headerLength = (int) pduDecoder.getValue32();
    ...
// WapPushOverSms.java:244  приведенное значение используется как размер массива
byte[] header = new byte[headerLength];

5-байтовый uintvar 88 80 80 80 00 декодируется в 0x80000000. При приведении к знаковому 32-битному int получается -2147483648. Попытка выделить new byte[-2147483648] генерирует необработанное исключение NegativeArraySizeException в основном потоке телефонии, завершая com.android.phone:

E AndroidRuntime: FATAL EXCEPTION: main
E AndroidRuntime: Process: com.android.phone
E AndroidRuntime: java.lang.NegativeArraySizeException: -2147483648
E AndroidRuntime:   at ...WapPushOverSms.decodeWapPdu(WapPushOverSms.java:244)
E AndroidRuntime:   at ...WapPushOverSms.dispatchWapPdu(WapPushOverSms.java:339)
E AndroidRuntime:   at ...InboundSmsHandler.processMessagePart(InboundSmsHandler.java:1169)
E AndroidRuntime:   at ...InboundSmsHandler$DeliveringState.processMessage(InboundSmsHandler.java:627)

Сообщение доставляется как SMS данных и никогда не показывается пользователю: ничего не появляется во входящих, и жертва никогда не видит номер отправителя.

Воздействие: удалённое, молчаливое, восстановление только с усилиями

  • Без необходимости взаимодействия. Жертва ничего не делает. Нет касаний, нет открытия, нет уведомлений.
  • Молчаливое. Ничего не появляется в Messages; номер злоумышленника никогда не показывается.
  • Вызовы прерываются, включая экстренные. Активные голосовые вызовы завершаются с кодом DisconnectCause CS_DEATH во время перезагрузки процесса.
  • Отключение телефонии. 1–2 секунды без обслуживания на каждое сообщение пока com.android.phone перезагружается.
  • Переотправка оператором усиливает эффект. Неподтвержденные сообщения отправляются оператором заново, снова выводя телефон из строя; одно сообщение вызвало перебои в течение недели при тестировании.
  • ~20 сообщений делают устройство непригодным для использования на продолжительный период.
  • Стойкий отказ в обслуживании. Быстрая повторяющаяся доставка повреждает базу данных SQLite, стоящую за хранилищем SMS, превращая кратковременный краш в телефон, который крашится при каждой загрузке (подробнее ниже).

Протестировано на разных производителях и моделях (Pixel 9 на прошивке April 2026, различные Samsung Galaxy и A-series) со 100%-ной успешностью воспроизведения.

От 2-секундного краша к «кирпичу»: race condition в SQLite

Одно сообщение — это повторяющийся кратковременный отказ. Отправка полезной нагрузки быстро подряд (≈30 сообщений) намного хуже: крахи переплетаются с записями оператора в хранилище SMS и попадают в race condition, который повреждает базу данных SQLite, содержащую сообщения устройства.

Когда база повреждена, com.android.phone уже не нуждается в новом сообщении для отказа: он крашится сразу при каждой загрузке при чтении поврежденного хранилища. Телефон теперь без телефонии на постоянной основе, и перезагрузка не очищает состояние.

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

  • Извлечение физической SIM и вставление её в не-Android устройство (например, iPhone), чтобы повторные попытки оператора были подтверждены и прекратили переотправку;
  • Затем очистка записей SMS / поврежденной базы через ADB.

На устройстве с eSIM, где SIM нельзя просто переместить на другой телефон, восстановление было бы намного сложнее, и для неподготовленного пользователя практически недостижимо.

Это различие, на котором основывается отчет. Это не кратковременный краш: это удалённый, без необходимости взаимодействия, стойкий отказ в обслуживании, требующий сброса к заводским настройкам (и не только) для восстановления, что точно соответствует форме «Destructive Remote DoS» в собственных правилах VRP.

Почему это серьёзно: удалённый злоумышленник может отрезать телефон от экстренных служб

Разрыв вызовов — не просто неудобство, когда один из этих вызовов идёт на экстренные службы. Пока устройство подвергается этой атаке или выведено из строя повреждением SQLite, оно не может надежно позвонить на 000 (экстренный номер). Атака удалённая, требует только номера жертвы и ничего ей не показывает.

Австралия рассматривает доступ к экстренным вызовам как обязательное свойство мобильного сервиса, а не опцию. В соответствии с Telecommunications (Emergency Call Service) Determination, администрируемым ACMA, операторы должны определить мобильные телефоны, которые не могут достичь 000, помочь клиенту перейти на работающее устройство и прекратить предоставление услуги затронутому телефону. Telstra ясно говорит, что обязана блокировать телефоны, которые больше не могут звонить на 000, уведомляя клиента и блокируя устройство, если ничего не будет сделано в течение 28 дней.

Результат парадоксален: нормативный способ исправления телефона, который не может достичь 000, — это отключить его от сети, а не патчить ОС. Таким образом, злоумышленник, который может удалённо создать такое состояние на Android телефоне, может, по сути, добиться блокировки своего собственного устройства оператором до момента выхода исправления. Регулирование существует именно потому, что потеря доступа к экстренным вызовам считается отказом безопасности; эта ошибка производит такой отказ по требованию.

Система была ужесточена в 2024 году после отключения 3G, которое оставило некоторые телефоны способными совершать обычные вызовы, но неспособными достичь экстренных служб — то же функциональное состояние, которое производит эта уязвимость.

Исправление: одна проверка границ

Решение — это проверка диапазона перед приведением в WapPushOverSms.java (строка 217), предоставленная Google в день первого отчета:

long rawHeaderLen = pduDecoder.getValue32();
if (rawHeaderLen < 0 || rawHeaderLen > pdu.length) {
    result.statusCode = Intents.RESULT_SMS_GENERIC_ERROR;
    return result;
}
int headerLength = (int) rawHeaderLen;

История раскрытия: коммуникация с Google

Отчет был подан через Android & Google Devices VRP и переподан дважды как апелляция на неправильную тriage. Через три тикета и четырех инженеров Google классифицировала это как проблему, не связанную с безопасностью.

  • 5 мая 2026 — Отчет подан: zero-click WAP Push краш в WapPushOverSms (issue 509520497). Рекомендуемое исправление предоставлено в тот же день.
  • 5 мая 2026 — Назначена инвестигация; исследователю предложено следовать ответственному раскрытию.
  • 15 мая 2026 — Запрос повышения приоритета: воспроизведено на 5 телефонах, влияние на экстренные вызовы, австралийские нормативы операторов.
  • 20 июня 2026 — Закрыто как Won't Fix (Infeasible): "не является уязвимостью безопасности."
  • 20 июня 2026 — Уточнение: это удалённый постоянный DoS; ~20 сообщений надолго отключают телефон. Переподано как апелляция (issues 525810560 и 525816147, "SMS of DEATH").
  • 20 июня 2026 — Переподача 525810560 закрыта за 3 минуты как Won't Fix (Not Reproducible).
  • 22 июня 2026 — Доклад о повреждении SQLite от быстрых отправок → краш при загрузке; восстановление требует SIM swap на не-Android устройство + ADB.
  • 23 июня 2026 — Запрос планов раскрытия; напоминание о 90-дневном сроке VRP и просьба проверить любые материалы заранее.
  • 23 июня 2026 — Согласие отложить ради общественной безопасности; предложение провести брифинг австралийским операторам, чтобы они смогли запланировать блокировку. Повторение однострочного исправления.
  • 2–3 июля 2026 — Апелляция отмечена как дубликат оригинала; переоценка подтверждает то же корневую причину.
  • 16 июля 2026 — Оригинал переоткрыт после появления проблемы на Discord, затем снова подтвержден как дубликат.
  • 16 июля 2026 — Добавлено уточнение: поведение соответствует критерию VRP "Destructive Remote DoS".
  • 17 июля 2026 — Подтверждение дополнительного контекста; triage для еще одного взгляда: "4 инженера оценят отчет."
  • 27 октября 2026 — Запрос обновления статуса после трех месяцев молчания.
  • 29 октября 2026 — Финальное решение: Won't Fix, со ссылкой на "не соответствует пороговому значению серьезности ... классифицируется как Non-Security Issue (NSI)."

Почему это публично. Проблема была сообщена конфиденциально и скрыта далеко за 90-дневным окном VRP. Google отказался исправлять её в трех тикетах и четырех инженеров, классифицируя удалённый, zero-click, приводящий к разрыву экстренных вызовов отказ в обслуживании как проблему, не связанную с безопасностью. Полное раскрытие следует, чтобы пользователи, операторы и нижестоящие OEM смогли оценить риск и смягчить его.

Proof of Concept: исходный код и APK

Proof-of-concept приложение Android и полный исходный код опубликованы на GitHub. Приложение создает поврежденный WAP Push PDU и отправляет его как SMS данных на целевой номер.

Предупреждение: это работающее оружие. Репозиторий содержит proof-of-concept, который может удалённо нарушить и вывести из строя мобильные телефоны. Он опубликован исключительно для исследования безопасности, образования и оборонительного тестирования.

Запускайте его только на устройствах, которыми вы владеете или явно авторизованы тестировать. Использование против кого-либо еще — преступление, и помеха в способности человека достичь экстренных служб (000) — серьёзное уголовное преступление в Австралии и большинстве стран.

Программное обеспечение предоставляется "как есть", без гарантий, под лицензией Apache License 2.0. Автор не принимает никакой ответственности за любое использование, неправильное использование или ущерб. Загружая APK или исходный код, вы принимаете полную ответственность за то, что вы с этим делаете.