- Pour bloquer les publicités YouTube sur Apple TV et iPhone au niveau du réseau, l’auteur a expérimenté pfSense, le blocage DNS, le routage VPN, Squid, MITMProxy, jusqu’à la modification des réponses Protobuf
- Les publicités YouTube étant servies depuis les mêmes domaines que les vidéos ordinaires, il était difficile de séparer de manière fiable contenu et publicité avec le seul blocage DNS de type Pi-hole ou pfBlockerNG
- Après avoir déchiffré le trafic TLS avec MITMProxy, il a supprimé les champs publicitaires JSON de YouTube Web et, dans l’app iOS, a directement repéré et modifié les structures publicitaires au sein des réponses application/x-protobuf
- Le décodage Protobuf complet en Python prenait environ 23 secondes sur le routeur pfSense, mais une approche par scan linéaire autour de
/pagead/a permis de traiter en temps réel même un payload de 1,8 MiB - Cette méthode nécessite l’installation d’une CA de confiance et des performances CPU suffisantes ; elle a permis de bloquer les publicités sur les appareils Apple connectés au réseau, mais a finalement aussi conduit à envisager un abonnement YouTube Premium
Routeur pfSense et segmentation du réseau
- L’objectif était de créer un routeur basé sur FreeBSD et pfSense afin de bloquer, à l’échelle du réseau, les publicités YouTube pre-roll, mid-roll et end-roll sur Apple TV et iPhone
- Le matériel utilisé comprenait un mini-PC J4125 avec jeu d’instructions AES-NI, de la RAM DDR4, un SSD mSATA et une clé USB pour installer pfSense
- La configuration d’exemple comprenait 32 Gio de RAM et un SSD mSATA de 128 Go
- Les 128 Go de stockage étaient jugés utiles pour les logs, la réduction de l’usure du SSD, la capture de paquets et l’espace d’edge cache
- Après l’installation de pfSense, le LAN 1 a été configuré avec l’IP statique
192.168.1.3, en dehors de la plage DHCP existante, puis le portail web d’administration a été ouvert avec le compteadmin/pfsense - Après avoir vérifié l’indication
AES-NI CPU Crypto: Yes (inactive)dans le tableau de bord pfSense, AES-NI a été activé manuellement dans System › Advanced › Miscellaneous - Pour exploiter les 32 Gio de RAM, de généreux RAM disks ont été alloués à
/varet/tmp, avec une sauvegarde des RAM disks configurée toutes les heures
Blocage DNS et segmentation physique du réseau
- À la place du Pi-hole existant, le paquet pfSense pfBlockerNG-devel a été installé pour configurer le blocage des publicités, des contenus malveillants et le blocage géographique
- L’installation ajoutait environ 20 Mio
- Si le service
pfb_dnsblne démarre pas ou si[ Missing CRON task ]apparaît, il est recommandé d’essayer de supprimer le fichier vide/var/run/booting
- Les trois ports Gigabit du routeur pfSense ont été utilisés pour une séparation physique des LAN plutôt que pour des VLAN
- Les appareils de type phoning-home, comme Alexa et Apple TV, ont été placés sur un LAN matériel séparé
- L’objectif était de protéger les appareils utilisés pour la banque, le trading d’actions et les crypto wallets en séparant le LAN critique des objets connectés et appareils Wi-Fi
- Le réseau des appareils connectés a été isolé en
172.31.1.0/24, tandis que le LAN plus fiable est resté en192.168/16- L’auteur estime que l’absence de route entre les réseaux réduit aussi en partie l’impact de règles iptables mal configurées
- Il faut activer le DHCP resolver sur la NIC physique pour que les nouveaux appareils réseau puissent obtenir une adresse
- L’AC1200 Archer C5 a été abandonné en raison de l’absence de mode AP, de problèmes d’accès à distance, d’un stock firmware ancien et du manque de prise en charge OpenWRT/DD-WRT/Tomato du chipset Broadcom
- Par la suite, un Nighthawk R7000 a été utilisé comme AP pour Apple/Amazon/TV et comme AP pour le Trusted Wireless Network
- Sur le Trusted Wireless Network, il a été décidé de désactiver le 2,4 GHz et de n’utiliser que le 5 GHz
- Le 5 GHz étant plus facilement bloqué par les murs et le béton, il a été jugé avantageux pour éviter le snooping à moyenne distance
Forcer tout le DNS vers pfSense
- Des règles NAT ont été ajoutées afin que tous les clients derrière pfSense utilisent le serveur Unbound DNS local
- L’objectif était d’empêcher les apps et assistants domestiques de contourner le réseau avec leurs propres serveurs DNS ou des serveurs DNS codés en dur
- Pour que pfBlockerNG puisse intervenir sur les requêtes DNS, il faut bloquer le DNS over TLS
- Les règles NAT ont d’abord été créées sur chaque interface sauf WAN, puis simplifiées avec l’alias de pare-feu
Non_WAN- En IPv4 comme en IPv6, les requêtes DNS locales sur le port 53 sont redirigées vers localhost
- La NAT reflection doit être désactivée pour empêcher l’accès au serveur DNS local depuis Internet
server: log-queries: yesa été ajouté dans Services › DNS Resolver › Display Custom Options afin de journaliser les requêtes DNS interceptées- Les logs DNS ont montré des requêtes de Windows vers Google Tag Manager, et ces requêtes ont été blackholées vers l’IP inexistante
10.10.10.1
Tentative de contournement du ciblage publicitaire de YouTube via VPN
- Les publicités YouTube provenant des mêmes domaines que les vidéos ordinaires, il était difficile de ne filtrer que les publicités avec des bloqueurs de domaines comme pfBlockerNG ou Pi-hole
- Le blocage de
googleadservices.comn’était jugé utile qu’après avoir vu une publicité vidéo puis cliqué sur celle-ci - Dans un navigateur, uBlock Origin peut intervenir dans le JavaScript, mais l’app YouTube sur iPhone était considérée comme difficile à limiter sans jailbreak
- Le blocage de
- Plutôt que de bloquer directement les publicités, l’auteur a expérimenté une méthode visant à rendre l’utilisateur moins attractif pour l’algorithme publicitaire de YouTube
- L’idée était d’envoyer le trafic de l’Apple TV via un VPN et d’utiliser un point de sortie VPN dans une région où YouTube compte peu de spectateurs
- L’objectif était de faire passer l’utilisateur pour un homme de 70 ans vivant en Italy
- WireGuard a été configuré sur pfSense, avec une private key NordLynx/WireGuard récupérée depuis une VM Linux
- Lors de la saisie de l’adresse du tunnel, entrer
1.0.0.0avec un subnet mask0fait apparaître0.0.0.0/0dans l’interface, selon l’auteur
- Lors de la saisie de l’adresse du tunnel, entrer
- Quand tout le trafic de l’Apple TV a été envoyé via le VPN, YouTube s’est affiché en italien et le nombre de publicités a diminué, mais des problèmes sont apparus avec Netflix et Amazon Prime
- Cela ressemblait à un blocage de fichiers CSS ou font et à des thumbnails qui ne se chargeaient pas
- Netflix et Prime sont signalés comme pratiquant bien le geofencing contre les fournisseurs de VPN
- L’auteur a ensuite tenté de ne router via le VPN que les FQDN liés à YouTube, avec notamment
www.youtube.com,youtube.com,googlevideo.com,accounts.google.com,googleapis.com,gstatic.comparmi les candidats- Après configuration, YouTube voyait l’utilisateur comme étant à Milan, tandis que Netflix et Prime Video le voyaient au Canada
- Les publicités sont devenues rares et, lorsqu’elles apparaissaient, elles étaient en italien
Problèmes de DNS race condition et de domaines wildcard
- Un jour plus tard, une DNS race condition a été découverte : l’alias hostname de pfSense et le cache DNS du client voyaient des ensembles d’IP YouTube différents
- L’intervalle de résolution par défaut d’un alias hostname pfSense est de 300 secondes
- Le TTL DNS de YouTube a été observé à 1 440 secondes
- Si l’IP obtenue par résolution du FQDN par l’Alias Daemon ne correspond pas à celle reçue plus tard par l’Apple TV, le trafic peut manquer le tunnel VPN
- La mesure d’atténuation consiste à faire en sorte que pfSense ignore le TTL de la cible et conserve plus longtemps l’entrée d’alias en cache
- Les variantes de sous-domaines de
googlevideo.comnécessitaient un routage wildcard, mais les règles NAT et firewall fonctionnent sur la base des IP et ne peuvent pas gérer directement les hostnames wildcard - Une PoC a été écrite avec le module Python d’Unbound et l’API REST de pfSense pour capturer les IP des réponses DNS et les ajouter dynamiquement à l’alias
VPN_wildcards- Le TTL de
VPN_wildcardsa été fixé à 1 heure, avec une capacité de 500 - Les enregistrements A sont parsés avec
ipaddress.IPv4Address, les enregistrements AAAA avecipaddress.IPv6Address
- Le TTL de
- Vérification le matin : Unbound DNS Resolver était en état de segfault, et chaque ajout d’IP nécessitait un rechargement des règles pfSense, ce qui rendait pfSense très lent
Déchiffrement HTTPS avec Squid et MITMProxy
- Le nouvel objectif était d’installer un proxy similaire à Squid et d’ajouter à l’appareil un fake-but-trusted CA certificate afin d’effectuer le déchiffrement du trafic TLS
- Squid a été installé comme paquet pfSense et le smoke test de SSL Filtering a réussi, mais la piste a été abandonnée
- Les performances étaient très lentes
- La configuration des ACL était fastidieuse
- Il y avait un issue lié à
https://http/* - La mise à jour de la liste de filtres URL SquidGuard prenait énormément de temps
- L’UI de Squid a été jugée insuffisante
- MITMProxy a ensuite été choisi
- Il dispose de Python scripting et d’une UI, et semblait extensible pour le blocage des publicités YouTube
- Le tarball Linux de mitmproxy 7.0.4 ne s’exécutait pas sur FreeBSD, avec
ELF interpreter /lib64/ld-linux-x86-64.so.2 not foundet des bibliothèques manquantes
- Installation dans l’environnement FreeBSD jail de pfSense avec
pkg install mitmproxy- L’installation visait 50 paquets, 206 MiB d’espace supplémentaire et 33 MiB de téléchargement
- En lançant
mitmproxydepuis la jail, l’UI s’ouvre
- Pour les expérimentations avec MITMProxy, une IP virtuelle
127.0.1.1a été attachée au localhost dans pfSense, et une règle NAT a transféré[Private IPs]:8080vers127.0.1.1:8080- Après avoir configuré le proxy d’un ordinateur portable de test sur
192.168.20.1:8080, les requêtes du navigateur sont apparues dans les logs de l’UI de MITMProxy
- Après avoir configuré le proxy d’un ordinateur portable de test sur
- Le fichier PEM de la CA MITMProxy est
~/.mitmproxy/mitmproxy-ca-cert.pemcert.pema été servi via un serveur web Python 3- MITMProxy fournit aussi le même certificat CA sur
mitm.it - Le certificat a été ajouté à un ordinateur portable propre et à un iPhone
Exploitation de MITMProxy et gestion du certificate pinning
- Sur le routeur,
mitmproxyconsommait beaucoup de CPU même au repos ; la génération à la volée de certificats TLS à chaque requête et le logging excessif de l’UI ont été considérés comme les causes mitmdumpa été jugé moins coûteux en CPU, car il omet l’UI et le logging extrême- À l’exécution, des options comme
--anticomp,--mode regular,--listen-port 8080et--listen-host 127.0.1.1ont été utilisées
- À l’exécution, des options comme
- Le Certificate Pinning est une technique dans laquelle le serveur ou le client connaît à l’avance le fingerprint du certificat attendu, ce qui empêche la falsification de certificat par MITMProxy
- Comme contournement,
--ignore-hostsa été utilisé pour faire en sorte que des hôtes commeapple.com:443eticloud.com:443contournent le proxy
- Comme contournement,
- En mode Transparent Proxy,
next_layer.pyde MITMProxy 7.0.4 a été patché pour que--allowed-hostsfonctionne mieux sur la base du SNI- Auparavant, dans de nombreux cas, seule l’IP du serveur semblait utilisée pour le matching
- Le patch ajoute
server.snicomme candidat hostname, en plus deserver.address[0]
- Après le patch, certains hôtes pouvaient être interceptés de manière stable, tandis que les autres pouvaient passer
Suppression des publicités JSON sur le YouTube web
- Lors du smoke test de MITMProxy, les URL de publicité et de tracking YouTube ont été bloquées avec un petit script
- Sur
youtube.com,/pagead/,/log_event?,/stats/ads,/stats/qoe?,/ptracking?,/generate_204,el=adunit,adformat=,/activeview?, etc. ont été bloqués - Sur
google.cometgoogle.ca,/pagead/a été bloqué
- Sur
- Lors des premiers tests, les requêtes ciblées étaient effectivement bloquées, y compris dans le panneau Network de DevTools
- Les entrées
(failed)provenaient du script - Les échecs
502ont été interprétés comme le résultat du black-hole des requêtes par pfBlockerNG - HTTP/2 a été désactivé pour éviter que les requêtes suivantes sur le même canal ne passent
- Les entrées
- Le simple blocage d’URL ne faisait pas complètement disparaître les publicités ; en examinant le HTML et le JavaScript de YouTube ainsi que les filtres uBlock Origin, la possibilité que les informations publicitaires se trouvent dans le corps des réponses JSON a été explorée
- Dans les réponses JSON capturées par MITMProxy, des informations de publicité et de tracking ont été identifiées dans les structures
playerAdsetplaybackTrackingplayerAdscontenait notammentplayerLegacyDesktopWatchAdsRenderer,playerAdParams,gutParams.tag,showCompanion,showInstreametuseGutplaybackTrackingcontenait notammentvideostatsPlaybackUrl,ptrackingUrl,qoeUrletatrUrlyoutubeRemarketingUrlétait de la formewww.youtube.com/pagead/viewthroughconversion/...
- Sur le YouTube web, il a été possible de supprimer les informations publicitaires du payload JSON et d’éliminer les publicités web via le routeur
Analyse de YouTube iOS et de Protobuf
- L’application YouTube iOS utilise, pour des appels d’API similaires à ceux de la version web, des données au format Protocol Buffer (Protobuf) au lieu de JSON
- Dans Protobuf, les clés sont numériques et peuvent changer, ce qui rend difficile la recherche des sections publicitaires avec une approche de type JSONPath
- Dans le payload, des chaînes publicitaires comme « Telus », « Samsung TV », « Boxing Week » et « Buy now » ont été observées
- Le trafic réseau de YouTube iOS était différent du trafic web
- Dans la version web, les paramètres
rangeouclendes chunks vidéo permettent dans une certaine mesure d’identifier des candidats publicitaires - Le protocole iOS n’utilise pas de paramètre de requête
rangeni d’en-têteRange, mais des compteurs comme&nr=2et&nr=3
- Dans la version web, les paramètres
- En décodant les réponses Protobuf pour les analyser hors ligne, des champs comme
has_unlimited_entitlement: Falseethas_premium_lite_entitlement: Falseont été trouvés- Modifier ces valeurs donnant l’impression de « tricher », l’auteur est revenu à une approche heuristique
- Les essais de blocage des URL publicitaires ont provoqué des boucles infinies, des erreurs d’interface et des crashs dans l’application iOS
- Des réponses
200avec body vide,404,503, des corps de réponse tronqués ou le remplacement partiel de vidéos publicitaires parnullralentissaient l’app ou la laissaient dans un état cassé avant de la faire crasher - L’endpoint de signalement d’erreurs
/error_204/indiquait « dev assertion failed » et était bloqué
- Des réponses
- Les publicités semblent être enregistrées dans des slots au sein d’une vidéo donnée
- Les types de slots incluent pre-roll, mid-roll, end-roll, full-page et ad pod
- Si l’on bloque seulement l’URL publicitaire, une erreur du type « une publicité inexistante a réservé un slot » se produit et l’interface passe en état de panic
Problèmes de performance de Protobuf et blackboxprotobuf
- Décoder environ 500 Kio de Protobuf brut en texte lisible par un humain uniquement avec Python était très lent
- Sur un PC de bureau avec CPU i7-6700, cela prenait environ 2,06 à 2,11 secondes
- Sur un routeur pfSense, environ 22,8 à 24,2 secondes
- Le
protoc --decode_rawen C++ était beaucoup plus rapide- Sur un PC de bureau avec CPU i7-6700, environ 0,017 à 0,022 seconde
- Sur un routeur pfSense, environ 0,12 à 0,14 seconde
- Comme le raw decoding n’est pas pris en charge en Python, l’approche retenue a été de communiquer directement avec le binaire C++
protocviasubprocess.Popen blackboxprotobufpour Burp Suite peut décoder un message Protobuf wire brut, y injecter des valeurs, puis le réencoder- Il est recommandé d’utiliser la version Burp Suite d’origine, et non le fork PyPI
- Certains forks peuvent provoquer un stack overflow à cause d’une récursion profonde
- Définir
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp"avant l’import deprotobufpermet d’utiliser l’implémentation C++libprotobuf.solorsque c’est possible
protobuf_to_json(data)deblackboxprotobufpeut produire un schéma.protoestimé au mieux, mais le résultat est très volumineux, profondément imbriqué et imparfait- Le dump de schéma Python dépassait environ 250 000 caractères
- Cela a été jugé suffisant pour extraire les détails publicitaires
Neutraliser une section publicitaire avec une modification d’un octet
- Avec le format Protobuf Wire, décoder, éditer puis réencoder sans le schéma d’origine peut modifier l’encodage
- Les causes avancées sont l’utilisation éventuelle du ZigZag encoding, l’impossibilité de déterminer le type numérique et le caractère non déterministe de l’ordre des champs d’un objet
- La solution a consisté à exploiter la compatibilité ascendante de Protobuf pour faire passer la section publicitaire pour un champ inconnu
- Elle s’appuie sur le comportement par lequel un ancien logiciel ignore les champs inconnus lorsqu’il lit un nouveau champ
- En modifiant un octet à un emplacement critique, une section profondément imbriquée peut sembler appartenir à une future version du schéma, ce qui conduit Protobuf à l’ignorer
- La clé de champ cible
49399797devait être trouvée non pas par simple recherche de chaîne, mais par balayage des tags varint- Le wire type est
2, ce qui correspond à une chaîne ou un message imbriqué à longueur délimitée - Le tag cible est calculé comme
AA FF B8 BC 01 - En décalant les 3 bits du wire type, on récupère la clé de champ
49399797
- Le wire type est
- La recherche effective consiste à trouver d’abord, dans les octets Protobuf bruts, une signature d’URL publicitaire comme
/pagead/, puis à remonter à proximité pour trouver le tag du champ cible et la clé de champ- L’exemple d’interception cible
POST youtubei.googleapis.com:443/youtubei/v1/browse?key=... - La réponse était
200,application/x-protobuf,1.87m - Dans l’exemple de logs,
49399797est trouvé à la position4465, et50195462à la position4477
- L’exemple d’interception cible
- Lors d’un smoke test en O(n), 1,8 Mio de données Protobuf ont été balayés une seule fois, sans mémoire supplémentaire, et la suppression des publicités a fonctionné
- La cible a été trouvée au 30 593e octet
- Environ 600 octets de backtracking ont permis de trouver la clé de champ à altérer
- Il n’est plus nécessaire de bloquer les URL contenant
*.googleadservices.comou/pagead/, et la requête correspondante n’est tout simplement plus créée
Structure de l’addon MITMProxy
- Le script PoC est enregistré sous
youtube.pyet exécuté avecmitmdump --listen-port 8080 --listen-host 127.0.0.1 -s "youtube.py"- Comme prérequis FreeBSD, il indique
pkg install protobuf,pkg install py38-pipetpip install jsonpath-ng
- Comme prérequis FreeBSD, il indique
- Le script se compose des classes
Logger,trunc,KilledError,JSONPathReplacement,ProtobufDebugParseretYouTubeAdBlocker - La regex des hôtes interceptés par
YouTubeAdBlockerest\.youtube\.com|google\.(com|ca)|googleapis\.com|googleadservices\.com|googlevideo\.com- La chaîne de recherche d’URL publicitaire Protobuf est
b"/pagead/" - La limite de recherche est
80_000 - Le tag du champ cible est
50195462
- La chaîne de recherche d’URL publicitaire Protobuf est
- Les règles de blocage des requêtes tuent le flow en vérifiant, selon l’hôte, des chaînes partielles dans l’URL
- Pour
youtube.com, cela inclut notammentpagead/,log_event?,stats/ads,stats/qoe?,ptracking?,generate_204,error_204,adformat=,activeview?,_ad_,ai?,sw.js - Un commentaire sur
sw.jsindique que les service workers sont refusés
- Pour
- Sur les réponses JSON, plusieurs remplacements JSONPath sont appliqués
$.responseContext.serviceTrackingParams[*].params[?(@.key == 'yt_ad')].valueest remplacé par"0"$..adPlacementsest remplacé par[]$..adPlacementRenderer,$..adPlacementConfig,$..playerAdParams,$..gutParamssont remplacés par{}$..adVideoIdest remplacé par une chaîne vide$..showCompanion,$..showInstream,$..useGutsont remplacés parFalse
- Dans les réponses Protobuf, lorsque le content type contient
protobuf, le corps est converti enbytearrayet/pagead/est recherché dans les 80 000 premiers octets- Les octets du tag cible sont générés avec
TagBytes(self.target_field_tag, WIRETYPE_LENGTH_DELIMITED), puis de nouveaux octets pourtarget_field_tag - 1sont créés - Une recherche inverse est effectuée jusqu’à juste avant la position de
/pagead/pour trouver les octets du tag cible - S’ils sont trouvés, ces octets sont écrasés par les nouveaux octets et le corps de la réponse est remplacé via
flow.response.set_content(bytes(body))
- Les octets du tag cible sont générés avec
- D’après les commentaires, cette PoC bloque 90 % des publicités
- D’autres sections contiennent aussi d’autres clés de champ, et il peut y avoir plusieurs sections publicitaires à altérer
Portée et limites
- Cette technique est présentée comme hautement spécialisée pour bloquer les publicités YouTube sur les appareils Apple, ou le trafic de trackers comme Instagram, WhatsApp et Facebook
- La charge CPU nécessaire pour déchiffrer/réchiffrer le trafic HTTPS est jugée largement au-delà de ce qu’un Raspberry Pi peut gérer
- Après jailbreak de l’Apple TV, l’ajout du certificat racine pfSense permettrait à la passerelle pfSense de déchiffrer le trafic de l’Apple TV et de bloquer les requêtes en inspectant le hostname publicitaire dans les en-têtes
- En revanche, cela ne s’appliquerait toujours pas aux publicités sur iPhone ; le jailbreak d’un iPhone est plus difficile, et les applications bancaires peuvent le détecter et refuser de fonctionner
- Le jailbreak lui-même est considéré comme trop extrême
- Si une fausse CA de confiance est possible, les paquets TLS peuvent être déchiffrés en clair et un blocage par URL peut être appliqué
- Les exemples d’URL bloquées cités sont les chemins YouTube
/pagead/viewthroughconversion/...et/pagead/conversion/...
- Les exemples d’URL bloquées cités sont les chemins YouTube
- Au final, il configure un routeur matériel depuis zéro, divise le LAN entre zone de confiance et zone non fiable, ajoute un blocage DNS des publicités et un proxy MITM transparent, puis bloque efficacement les publicités YouTube sur les appareils Apple connectés au réseau
YouTube Premium et soutien aux créateurs
- Après avoir bloqué les publicités YouTube pendant quelques mois, il commence à payer YouTube Premium pour soutenir les créateurs de contenu
- Il ajoute la réserve suivante : « ce n’est pas parce qu’on peut le faire qu’on doit le faire »
- Le prix de YouTube Premium est mentionné comme étant passé de CAD
$9.99/moà$11.99/mo, soit environ$13.43/motaxes incluses - Dans une expérience de visionnage de publicités, il utilise un ordinateur portable propre et une navigation privée pour regarder YouTube par intermittence pendant une journée
- D’après l’historique, 10 vidéos ont été regardées
- Il a été exposé à 8 publicités, dont seulement 2 étaient passables
- En supposant un CPV de USD
$0.15, le coût publicitaire quotidien est de$1.20, soit environ USD$36/mopar extrapolation mensuelle - Un autre calcul basé sur des chiffres de Statista indique qu’en 2019, les annonceurs américains ont dépensé
$15.1 billionsur YouTube, tandis que les résidents américains ont regardé916 billionvidéos, soit une moyenne de USD$0.0165par vue- Avec ce calcul, le coût quotidien est d’environ USD
$0.13, soit environ USD$3.96par mois par extrapolation - Il estime que cette valeur n’est pas proche des USD
$10de Premium
- Avec ce calcul, le coût quotidien est d’environ USD
- Lorsqu’une réclamation DMCA est déposée, les revenus publicitaires peuvent revenir au plaignant, comme Sony ou Viacom, plutôt qu’au créateur
- À cause de cela, il peut arriver que l’on ne donne rien, sans le savoir, à une chaîne que l’on apprécie
- Il juge qu’il n’est donc pas surprenant que de nombreux créateurs migrent vers Patreon
2 commentaires
Le billet original est extrêmement long ; le processus est intéressant, mais le point à retenir, c’est que l’auteur a finalement fini par payer YouTube Premium et l’utiliser.
Avis sur Hacker News
Dans l’ensemble, c’est un hack impressionnant, mais certaines formulations à propos de Protobuf paraissent étranges.
Il s’agit de casser volontairement le tag d’un champ dans Protobuf ; ignorer les numéros de tags non reconnus n’est pas un « défaut », mais un élément central de la conception pour l’extensibilité.
1,87 Mio n’est pas non plus une taille énorme, et ce genre de message ne doit sans doute pas être diffusé en streaming en continu ; l’explication selon laquelle ce serait un obstacle de performance n’est donc pas très convaincante.
L’encodage Protobuf n’a pas été conçu pour rendre le décodage coûteux, mais au contraire pour être décodé efficacement ; même sans le schéma
.protod’origine, on peut le décoder directement avecUnknownFieldSet.Une meilleure méthode aurait sans doute consisté à utiliser un faux schéma
.protone contenant que le champ à supprimer. L’approche par scan de chaînes est plus sujette aux erreurs, car la même séquence d’octets peut apparaître par hasard dans d’autres données.Si l’ordre des champs change, les octets obtenus après réencodage peuvent être différents, mais le destinataire devrait traiter cela comme le même message, et il paraît peu probable que l’app YouTube détecte un changement d’ordre des champs.
Pour quelqu’un qui a travaillé sur Protobuf par le passé, l’auteur semble avoir mal compris cette partie.
J’ai vécu la majeure partie de ma vie dans des zones rurales, et quand ce n’est pas mon Wi-Fi, même ça représente en pratique un gros téléchargement. Sur mobile, il existe peut-être des contournements, mais le Wi-Fi rural a encore du mal avec l’architecture du Web 2.0 et s’utilise souvent à des débits de 2 à 4G.
Dans les zones urbaines, où il y a assez de population pour soutenir l’infrastructure, 1,87 Mo est généralement devenu un petit fichier, mais il peut y avoir des exceptions vers 18 h, quand tout le monde sur la ligne câble se met à streamer.
without the C++ source proto files: j’ai créé un projet appelé protodump, qui génère les fichiers source.protoà partir de binaires.Il recrée les définitions des messages et des champs, y compris leurs noms d’origine ; il suffit d’extraire le binaire de la box Apple TV.
https://github.com/arkadiyt/protodump
Protobuf a été la technologie qui m’a fait découvrir les IDL, et à l’époque l’idée me paraissait magique. J’en ai été d’autant plus surpris après avoir bricolé moi-même un IDL bancal puis découvert Protobuf.
Si l’on ne veut pas tirer toute la dépendance
protoc, on peut écrire soi-même un petit décodeur Protobuf de quelques centaines de lignes : https://github.com/kubernetes/test-infra/blob/master/guberna... https://github.com/kubernetes/test-infra/blob/master/guberna...Depuis que j’ai découvert The Proxomitron il y a plus de vingt ans, je fais passer le trafic par un proxy homme-du-milieu pour supprimer les publicités et réécrire les pages avec, par exemple, du CSS utilisateur.
Des services comme CloudFlare ont tendance à me classer comme « bot », mais il existe aussi des moyens de contourner cela, même si ce n’est pas trivial. Ce genre de cas montre aussi pourquoi l’attestation distante est dangereuse pour la liberté des utilisateurs.
Il semble exister plusieurs projets « successeurs », et je me demande aussi si c’est uniquement pour Windows. Je cherchais vaguement un proxy simple capable d’insérer des liens locaux dans du contenu distant.
Pour l’instant, j’ai même débranché le pi-hole qui tournait sur mon Pi 4. J’ai passé des heures à essayer de le faire fonctionner correctement avec plusieurs services, puis j’ai fini par abandonner ; cela ne valait pas le temps investi pour un réseau domestique.
Ce qui fonctionne vraiment, ce sont les bloqueurs de publicité dans le navigateur et les patchers d’applications comme ReVanced. À mesure que mes économies augmentent, je penche davantage vers le fait de simplement payer des services sans pub — YouTube Premium, Hulu, Netflix, Max — quand ces deux solutions ne suffisent pas.
Je ne l’ai jamais utilisé pour l’usage évoqué ici, mais il était excellent comme proxy derrière le pare-feu de l’entreprise. À l’époque, le pare-feu exigeait des identifiants de connexion pour les connexions externes, ce qui empêchait beaucoup de programmes d’accéder à Internet.
Privaxy empaqueté avec Docker vient à l’esprit. C’est un proxy d’interception compatible avec les listes de blocage d’UBlock Origin.
Quand on voit la quantité de publicités et de scripts de tracking présents sur les produits connectés, surtout les TV, c’est assez surprenant. D’après mes tests jusqu’ici, plus de 40 % du trafic était inutile, et l’expérience consistant à retirer les pubs des apps de smart TV était plutôt amusante.
https://github.com/deetungsten/webui-privaxy est un fork dockerisé de https://github.com/Barre/privaxy
J’avais voulu modifier le fork pour éviter que le frontend utilise l’adresse
0.0.0.0codée en dur, afin de pouvoir vraiment isoler le conteneur Docker, mais la vie s’en est mêlée. Tu as essayé sur Apple TV ?https://github.com/AdguardTeam/urlfilter
Cet article est une excellente réponse à la question récurrente : « comment apprendre à devenir hacker ? »
Il montre bien le cheminement de pensée et le travail acharné qui entrent dans n’importe quel exploit.
Il y a un passage disant « utilisons WireGuard — Intel dispose du jeu d’instructions de chiffrement AES-NI », mais à ma connaissance WireGuard n’utilise pas AES.
Globalement, l’auteur semble surestimer un peu les besoins CPU du chiffrement TLS, ou sous-estimer les performances des ordinateurs monocartes modernes.
L’explication selon laquelle les besoins CPU pour déchiffrer puis rechiffrer du trafic HTTPS sur un Raspberry Pi seraient largement dépassés me laisse aussi perplexe. Je serais assez surpris qu’un traitement TLS en interception soit réellement impossible sur un RPi 4, même avec du RSA purement logiciel.
Parmi les téléphones Android encore utilisés, certains ont un CPU moins puissant qu’un RPi 4, et ils utilisent pourtant TLS.
Si un téléphone Android peu puissant ne peut traiter que 50 Mb/s de trafic TLS, ce n’est pas forcément un gros problème en usage réel. Les téléphones lents sont généralement connectés à des réseaux lents.
En revanche, si tu as une connexion gigabit à la maison et qu’un appareil peu puissant placé entre tous tes ordinateurs et Internet crée un goulot d’étranglement à 50 Mb/s, ça devient un vrai problème.
Les besoins CPU de TLS dépendent énormément de la bande passante visée. À des débits plus élevés, l’offload vers un accélérateur devient parfois pratiquement indispensable. Le coût du handshake n’est pas négligeable non plus et peut limiter le nombre de connexions par seconde. C’est rarement un problème sur un seul appareil, mais cela peut prendre de l’ampleur à l’échelle de tout un réseau d’appareils.
Super article. J’espérais une méthode pour faire de l’interception sur des appareils qui n’autorisent pas l’installation d’une CA personnalisée.
J’ai un appareil IoT qui n’expose pas d’API locale et n’affiche ses données que via le cloud ; j’aimerais capturer le trafic entre l’appareil et le cloud.
Au final, est-ce qu’il n’y a pas d’autre solution que de dumper la mémoire flash, remplacer la CA, puis reflasher ?
Il y a un bon article qui donne des pistes pour intercepter des appareils IoT sans toucher au matériel ni au firmware :
https://robertheaton.com/2019/11/21/how-to-man-in-the-middle...
Si c’est possible, cela revient à s’appuyer sur une faille d’implémentation.
Honnêtement, je pense que même pour les quelques appareils qui permettent aujourd’hui d’installer des certificats de confiance personnalisés, ce temps est compté.
De nouvelles méthodes pour bloquer les pubs sur YouTube ou n’importe quelle plateforme apparaissent toujours, mais quelques mois plus tard elles changent et deviennent inutiles.
Et si, à la place, on attaquait les annonceurs ? YouTube/Google semble ne suivre que les « clics », mais suivent-ils aussi les achats réels ?
En théorie, si suffisamment de faux bots et de vrais utilisateurs cliquent sur les publicités sans rien acheter, on peut brûler les budgets publicitaires. Avec le temps, les équipes marketing verront que, sur une plateforme donnée, les clics atteignent des records mais que le taux de conversion par rapport aux clics ou aux impressions est très faible, et elles finiront peut-être par quitter cette plateforme.
Article étonnant. Dès que j’ai vu l’étape de patch mitm, je me suis dit que ce serait quelque chose de spécial, et c’était bien le cas.
Le passage de la table des matières « Nouvel objectif : faire croire à YouTube que je suis un homme de 70 ans vivant en Italie » m’a marqué.
Il y a quelque temps, je ne sais pas comment, le ciblage publicitaire s’est mis à croire que j’étais quelqu’un qui voulait acheter un pyjama en soie lavable à 500 dollars pour ma petite amie.
Les pubs elles-mêmes étaient excellentes, mais je me demande combien ils payaient par impression.
Depuis que je suis passé à l’Apple TV, j’ai surtout des pubs locales avec un ciblage géographique erroné. En moyenne, c’est peut-être mieux comme ça.
Ce n’est pas une « faille » de Protobuf. Le fait que, lorsqu’on modifie des octets, ils soient décodés comme un champ situé ailleurs correspond à un fonctionnement prévu
Protobuf est à l’origine un protocole fondé sur des numéros de champ et des préfixes de longueur, qui part de l’hypothèse raisonnable que les octets ne changent pas pendant le transport, et laisse au lecteur la responsabilité de l’intégrité
Même si c’était une faille, ce serait celle de l’app YouTube pour iOS, pas de Protobuf ; et comme en réalité ce n’est même pas une faille, il est difficile de parler d’« exploit ». À la rigueur, on pourrait dire que les échanges Protobuf de l’app YouTube iOS ne vérifient pas le hash du payload renvoyé
Après cet article, ils vont probablement se mettre à le vérifier
Ce n’est pas une faille, c’est un comportement conforme à la conception
Le passage disant que « Google rend le décodage, la modification et le réencodage coûteux en calcul sans les fichiers proto source C++ » est lui aussi étrange. Avec du code Python non optimisé, ce serait coûteux, mais en C ou dans un autre langage compilé, parcourir un Protobuf de 1,8 Mo est trivial, qu’on ait ou non les fichiers source proto
Il est peu probable que l’objectif de conception ait été de rendre les fichiers Protobuf difficiles à décoder sans les sources. Si c’était l’objectif, il aurait été plutôt mal atteint