- Um YouTube-Werbung auf Apple TV und iPhone auf Netzwerkebene zu blockieren, wurden nacheinander pfSense, DNS-Blocking, VPN-Routing, Squid, MITMProxy und schließlich die Manipulation von Protobuf-Antworten getestet
- Da YouTube-Werbung über dieselben Domains wie normale Videos ausgeliefert wird, war es mit reinem DNS-Blocking wie bei Pi-hole oder pfBlockerNG schwierig, Inhalte und Werbung zuverlässig zu trennen
- Nach der Entschlüsselung des TLS-Traffics mit MITMProxy wurden in Web-YouTube die JSON-Werbefelder entfernt; in der iOS-App wurden die Werbestrukturen in Antworten vom Typ application/x-protobuf direkt gesucht und verändert
- Ein vollständiges Protobuf-Decoding auf Python-Basis dauerte auf dem pfSense-Router rund 23 Sekunden, aber mit einem linearen Scan im Bereich um
/pagead/ließ sich selbst ein 1,8-MiB-Payload in Echtzeit verarbeiten - Diese Methode erfordert die Installation einer vertrauenswürdigen CA und ausreichend CPU-Leistung; auf mit dem Netzwerk verbundenen Apple-Geräten ließ sich Werbung zwar blockieren, letztlich wurde aber sogar eine YouTube-Premium-Zahlung in Betracht gezogen
pfSense-Router und Netzwerksegmentierung
- Ziel war es, einen Router auf Basis von FreeBSD und pfSense zu bauen, um YouTube-Pre-Roll-, Mid-Roll- und End-Roll-Werbung auf Apple TV und iPhone im gesamten Netzwerk zu blockieren
- Verwendet wurden ein J4125-Mini-PC mit AES-NI-Befehlssatz, DDR4-RAM, eine mSATA-SSD und ein USB-Laufwerk zur Installation von pfSense
- Eine Beispielkonfiguration bestand aus 32 GiB RAM und einer 128-GB-mSATA-SSD
- Die 128 GB Speicher wurden als nützlich für Logs, geringeren SSD-Verschleiß, Paketmitschnitte und Edge-Cache-Platz angesehen
- Nach der Installation von pfSense wurde LAN 1 auf die statische IP
192.168.1.3außerhalb des bestehenden DHCP-Bereichs gesetzt, und auf das Admin-Webportal wurde mit dem Kontoadmin/pfsensezugegriffen - Nach Prüfung der Anzeige
AES-NI CPU Crypto: Yes (inactive)im pfSense-Dashboard wurde AES-NI unter System › Advanced › Miscellaneous manuell aktiviert - Die 32 GiB RAM wurden genutzt, um
/varund/tmpgroßzügig als RAM-Disk zuzuweisen; außerdem wurde eine stündliche Sicherung der RAM-Disk eingerichtet
DNS-Blocking und physische Netztrennung
- Statt des bisherigen Pi-hole wurde das pfSense-Paket pfBlockerNG-devel installiert, um Werbe- und Malware-Inhalte sowie Geo-Blocking zu konfigurieren
- Der Speicherbedarf erhöhte sich dabei um etwa 20 MiB
- Falls der Dienst
pfb_dnsblnicht startet oder[ Missing CRON task ]erscheint, wird empfohlen, die leere Datei/var/run/bootingzu löschen
- Die drei Gigabit-Ports des pfSense-Routers wurden statt für VLANs für eine physische Trennung der LANs verwendet
- Geräte mit starkem „Phoning Home“ wie Alexa und Apple TV kamen in ein separates Hardware-LAN
- Ein wichtiges LAN wurde von Smart-Geräten und WLAN-Geräten getrennt, um Geräte für Banking, Aktienhandel und Crypto Wallets zu schützen
- Das Netz für Smart-Geräte wurde auf
172.31.1.0/24ausgelagert, während das stärker vertrauenswürdige LAN auf192.168/16blieb- Wenn es keine Route zwischen den Netzen gibt, reduziert das aus dieser Sicht auch teilweise die Auswirkungen falsch konfigurierter iptables-Regeln
- Auf der physischen NIC muss der DHCP-Resolver aktiviert werden, damit neue Netzwerkgeräte Adressen erhalten
- Ein AC1200 Archer C5 wurde ausgemustert, weil AP mode fehlte, Remote-Zugriff problematisch war, die Stock-Firmware veraltet war und der Broadcom-Chipsatz nur schwache Unterstützung durch OpenWRT/DD-WRT/Tomato bot
- Anschließend wurde ein Nighthawk R7000 als AP für Apple/Amazon/TV und als AP für das Trusted Wireless Network verwendet
- Im Trusted Wireless Network sollte 2,4 GHz deaktiviert und nur 5 GHz genutzt werden
- 5 GHz gilt als günstiger gegen Snooping auf mittlere Distanz, weil Wände und Beton das Signal stärker dämpfen
Gesamten DNS-Verkehr auf pfSense erzwingen
- Es wurden NAT-Regeln hinzugefügt, damit alle Clients hinter pfSense den lokalen Unbound-DNS-Server verwenden
- Ziel war, zu verhindern, dass Apps und Home Assistants über eigene oder fest einprogrammierte DNS-Server ausweichen
- Damit pfBlockerNG DNS-Anfragen beeinflussen kann, muss DNS over TLS blockiert werden
- Die NAT-Regeln wurden zunächst pro Interface außer WAN angelegt und später per Firewall-Alias
Non_WANvereinfacht- Lokale DNS-Abfragen auf Port 53 werden sowohl für IPv4 als auch für IPv6 auf localhost umgeleitet
- NAT Reflection muss deaktiviert werden, damit aus dem externen Internet kein Zugriff auf den lokalen DNS-Server möglich ist
- Unter Services › DNS Resolver › Display Custom Options wurde
server: log-queries: yesergänzt, um abgefangene DNS-Anfragen zu protokollieren - In den DNS-Logs war zu sehen, dass Windows auf Google Tag Manager zugreifen wollte; diese Anfrage wurde in ein Blackhole auf die nicht existierende IP
10.10.10.1umgeleitet
Versuch, YouTube-Ad-Targeting per VPN zu umgehen
- Weil YouTube-Werbung über dieselben Domains wie normale Videos kommt, war es mit Domain-Blockern wie pfBlockerNG oder Pi-hole schwierig, nur die Werbung herauszufiltern
- Das Blockieren von
googleadservices.comwurde als erst dann sinnvoll betrachtet, wenn nach dem Ansehen eines Werbevideos auf die Werbung geklickt wird - Im Browser kann uBlock Origin in JavaScript eingreifen, aber in der YouTube-App auf dem iPhone ist Werbebeschränkung ohne Jailbreak nur schwer möglich
- Das Blockieren von
- Statt Werbung direkt zu blockieren, wurde experimentiert, den YouTube-Werbealgorithmus dazu zu bringen, den Nutzer als weniger attraktives Werbeziel einzustufen
- Die Idee war, den Apple-TV-Traffic über ein VPN zu leiten und einen VPN-Endpunkt in einer Region mit wenigen YouTube-Zuschauern zu verwenden
- Ziel war es, den Nutzer wie einen 70-jährigen Mann aus Italien erscheinen zu lassen
- Auf pfSense wurde WireGuard eingerichtet; der private NordLynx-/WireGuard-Schlüssel wurde aus einer Linux-VM übernommen und konfiguriert
- Gibt man bei der Tunneladresse
1.0.0.0und die Subnetzmaske0ein, zeigt die UI das Ergebnis als0.0.0.0/0an
- Gibt man bei der Tunneladresse
- Als der gesamte Apple-TV-Traffic über das VPN lief, zeigte YouTube Inhalte auf Italienisch an und es gab weniger Werbung, aber Netflix und Amazon Prime machten Probleme
- Es wirkte so, als würden CSS- oder Font-Dateien blockiert und Thumbnails nicht geladen
- Es wird darauf hingewiesen, dass Netflix und Prime Geofencing gegenüber VPN-Anbietern gut erkennen
- Danach wurde versucht, nur YouTube-bezogene FQDNs über das VPN zu routen; als Kandidaten dienten
www.youtube.com,youtube.com,googlevideo.com,accounts.google.com,googleapis.comundgstatic.com- Nach der Konfiguration sah YouTube den Nutzer in Mailand, während Netflix und Prime Video ihn in Kanada verorteten
- Werbung trat seltener auf, und die angezeigte Werbung war auf Italienisch
DNS-Race-Condition und Wildcard-Domain-Problem
- Einen Tag später wurde eine DNS-Race-Condition entdeckt, bei der der pfSense-Hostname-Alias und der DNS-Cache des Clients unterschiedliche Mengen von YouTube-IPs sahen
- Das Standard-Resolve-Intervall des pfSense-Hostname-Alias beträgt 300 Sekunden
- Die YouTube-DNS-TTL wurde mit 1.440 Sekunden beobachtet
- Wenn die vom Alias Daemon für die FQDN-Auflösung ermittelten IPs nicht mit den IPs übereinstimmen, die Apple TV später erhält, kann der Traffic den VPN-Tunnel verfehlen
- Als Gegenmaßnahme soll pfSense die Ziel-TTL ignorieren und Alias-Einträge länger cachen
- Für die variierenden Subdomains von
googlevideo.comwar Wildcard-Routing nötig, aber NAT und Firewall-Regeln arbeiten IP-basiert und können Wildcard-Hostnamen nicht direkt verarbeiten - Es wurde ein PoC geschrieben, der mit dem Unbound-Python-Modul und der pfSense-REST-API DNS-Antwort-IPs erfasst und sie dynamisch dem Alias
VPN_wildcardshinzufügt- Die TTL von
VPN_wildcardswurde auf 1 Stunde gesetzt, die Kapazität auf 500 - A-Records werden als
ipaddress.IPv4Address, AAAA-Records alsipaddress.IPv6Addressgeparst
- Die TTL von
- Bei der Prüfung am Morgen befand sich der Unbound DNS Resolver im Segfault-Zustand, und für jedes Hinzufügen einer IP war ein Reload der pfSense-Regeln nötig, wodurch pfSense sehr langsam wurde
HTTPS-Entschlüsselung mit Squid und MITMProxy
- Das neue Ziel war, einen Squid-ähnlichen Proxy zu installieren und dem Gerät ein gefälschtes, aber vertrauenswürdiges CA-Zertifikat hinzuzufügen, um TLS-Traffic zu entschlüsseln
- Squid wurde als pfSense-Paket installiert und sogar ein SSL-Filtering-Smoke-Test war erfolgreich, wurde dann aber verworfen
- Die Performance war sehr langsam
- Die ACL-Konfiguration war umständlich
- Es gab ein Problem im Zusammenhang mit
https://http/* - Das Aktualisieren der SquidGuard-URL-Filterliste dauerte sehr lange
- Die Squid-UI wurde als unzureichend angesehen
- Danach fiel die Wahl auf MITMProxy
- Es bietet Python-Scripting und eine UI und wurde als erweiterbar für YouTube-Werbeblockierung angesehen
- Das Linux-Tarball von mitmproxy 7.0.4 lief unter FreeBSD wegen
ELF interpreter /lib64/ld-linux-x86-64.so.2 not foundund fehlender Bibliotheken nicht
- In der FreeBSD-Jail-Umgebung von pfSense wurde es mit
pkg install mitmproxyinstalliert- Es waren 50 Pakete zur Installation vorgesehen, mit 206 MiB zusätzlichem Speicherbedarf und 33 MiB Download-Volumen
- Wenn
mitmproxyinnerhalb der Jail ausgeführt wird, öffnet sich die UI
- Für die MITMProxy-Experimente wurde in pfSense die virtuelle IP
127.0.1.1an localhost gebunden und per NAT-Regel[Private IPs]:8080an127.0.1.1:8080weitergeleitet- Nachdem auf einem Test-Laptop der Proxy auf
192.168.20.1:8080gesetzt wurde, erschienen Browser-Anfragen im MITMProxy-UI-Log
- Nachdem auf einem Test-Laptop der Proxy auf
- Die MITMProxy-CA-PEM-Datei ist
~/.mitmproxy/mitmproxy-ca-cert.pemcert.pemwurde über einen Python-3-Webserver bereitgestellt- MITMProxy stellt dasselbe CA-Zertifikat auch unter
mitm.itbereit - Das Zertifikat wurde auf einem sauberen Laptop und einem iPhone hinzugefügt
Betrieb von MITMProxy und Umgang mit Certificate Pinning
- Auf dem Router verbrauchte
mitmproxyselbst im Leerlauf viel CPU; als Ursache wurden das On-the-fly-Erzeugen von TLS-Zertifikaten pro Anfrage und das übermäßige Logging der UI vermutet mitmdumpwurde als CPU-schonender angesehen, da es auf UI und extremes Logging verzichtet- Beim Start wurden unter anderem
--anticomp,--mode regular,--listen-port 8080,--listen-host 127.0.1.1verwendet
- Beim Start wurden unter anderem
- Certificate Pinning ist eine Technik, bei der Server oder Client den erwarteten Zertifikat-Fingerprint im Voraus kennen, sodass die Zertifikatsfälschung durch MITMProxy nicht funktioniert
- Als Umgehung wurde
--ignore-hostsverwendet, damit Hosts wieapple.com:443undicloud.com:443den Proxy umgehen
- Als Umgehung wurde
- Im Transparent-Proxy-Modus wurde
next_layer.pyvon MITMProxy 7.0.4 gepatcht, damit--allowed-hostsauf Basis von SNI besser funktioniert- Zuvor wurde in vielen Fällen offenbar nur die Server-IP für das Matching verwendet
- Der Patch fügt nicht nur
server.address[0], sondern auchserver.snials Kandidaten für Hostnamen hinzu
- Nach dem Patch konnten einige Hosts zuverlässig abgefangen werden, während der Rest durchgelassen wurde
Entfernen von JSON-Werbung auf YouTube im Web
- Im MITMProxy-Smoke-Test wurden YouTube-Werbe- und Tracking-URLs mit einem kleinen Skript blockiert
- Auf
youtube.comwurden unter anderem/pagead/,/log_event?,/stats/ads,/stats/qoe?,/ptracking?,/generate_204,el=adunit,adformat=,/activeview?blockiert - Auf
google.comundgoogle.cawurde/pagead/blockiert
- Auf
- In ersten Tests wurden die zu blockierenden Anfragen auch im DevTools-Network-Panel tatsächlich als blockiert angezeigt
- Einträge mit
(failed)stammen aus dem Skript 502-Fehler wurden als Ergebnis davon angesehen, dass pfBlockerNG die Anfrage in ein Black Hole leitete- HTTP/2 wurde deaktiviert, damit nachfolgende Anfragen auf demselben Kanal nicht durchkommen
- Einträge mit
- Mit einfachem URL-Blocking verschwanden die Anzeigen nicht vollständig; daher wurde anhand von YouTube-HTML, JavaScript und uBlock-Origin-Filtern untersucht, ob Werbeinformationen im JSON-Antwort-Body enthalten sind
- In den von MITMProxy erfassten JSON-Antworten wurden Werbe- und Tracking-Informationen in den Strukturen
playerAdsundplaybackTrackingbestätigtplayerAdsenthältplayerLegacyDesktopWatchAdsRenderer,playerAdParams,gutParams.tag,showCompanion,showInstream,useGutund mehrplaybackTrackingenthältvideostatsPlaybackUrl,ptrackingUrl,qoeUrl,atrUrlund mehryoutubeRemarketingUrlhatte die Formwww.youtube.com/pagead/viewthroughconversion/...
- Bei YouTube im Web konnten durch das Entfernen von Werbeinformationen aus dem JSON-Payload Web-Anzeigen über den Router beseitigt werden
Analyse von iOS-YouTube und Protobuf
- Die iOS-YouTube-App verwendet bei API-Aufrufen ähnlich wie die Web-Version Daten im Format Protocol Buffer (Protobuf) statt JSON
- In Protobuf sind die Schlüssel numerisch und können sich ändern, daher ist es schwierig, den Werbeabschnitt mit einem JSONPath-Ansatz zu finden
- Im Payload waren Werbestrings wie „Telus“, „Samsung TV“, „Boxing Week“ und „Buy now“ zu sehen
- Der Netzwerkverkehr von iOS-YouTube unterschied sich vom Web-Traffic
- In der Web-Version lassen sich Werbekandidaten teilweise über den
range- oderclen-Parameter der Video-Chunks abschätzen - Das iOS-Protokoll verwendet weder den Query-Parameter
rangenoch den HeaderRange, sondern Zähler wie&nr=2und&nr=3
- In der Web-Version lassen sich Werbekandidaten teilweise über den
- Beim Dekodieren von Protobuf-Antworten zur Offline-Analyse wurden Einträge wie
has_unlimited_entitlement: Falseundhas_premium_lite_entitlement: Falsegefunden- Das Ändern dieser Werte fühlte sich wie „Cheating“ an, daher wurde wieder zu einem heuristischen Ansatz zurückgekehrt
- Experimente zum Blockieren von Werbe-URLs führten in der iOS-App zu Endlosschleifen, UI-Fehlern und Abstürzen
200mit leerem Body,404,503, abgeschnittene Response-Bodys oder das Nullsetzen von Teilen des Ad-Videos machten die App langsam oder ließen sie in einem defekten Zustand abstürzen- Der Error-Reporting-Endpunkt
/error_204/zeigte „dev assertion failed“ an und wurde blockiert
- Werbung scheint in Slots innerhalb eines bestimmten Videos registriert zu werden
- Zu den Slot-Typen gehören Pre-Roll, Mid-Roll, End-Roll, Full-Page und Ad Pod
- Wenn nur die Ad-URL blockiert wird, entstehen Fehler nach dem Muster „eine nicht existierende Werbung hat einen Slot reserviert“, worauf die UI in einen Panic-Zustand gerät
Protobuf-Performance-Probleme und blackboxprotobuf
- Das Dekodieren von rund 500 KiB rohem Protobuf in menschenlesbaren Text nur mit Python war sehr langsam
- Auf einem Desktop mit i7-6700-CPU dauerte es etwa 2,06 bis 2,11 Sekunden
- Auf einem pfSense-Router dauerte es etwa 22,8 bis 24,2 Sekunden
- C++
protoc --decode_rawwar deutlich schneller- Auf einem Desktop mit i7-6700-CPU dauerte es etwa 0,017 bis 0,022 Sekunden
- Auf einem pfSense-Router lag es bei etwa 0,12 bis 0,14 Sekunden
- Da Raw-Decoding in Python nicht unterstützt wurde, fiel die Wahl auf direkte Kommunikation mit dem C++-Binary
protocübersubprocess.Popen blackboxprotobuffür Burp Suite kann rohe Protobuf-Wire-Messages dekodieren, Werte injizieren und danach wieder re-encodieren- Es wird empfohlen, nicht den PyPI-Fork, sondern die originale Burp-Suite-Version zu verwenden
- Einige Forks können durch tiefe Rekursion einen Stack Overflow auslösen
- Wenn
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp"vor dem Import vonprotobufgesetzt wird, kommt nach Möglichkeit die C++-Implementierunglibprotobuf.sozum Einsatz
protobuf_to_json(data)vonblackboxprotobufkann ein.proto-Schema per Best Guess erzeugen, aber das Ergebnis ist sehr groß, tief verschachtelt und nicht perfekt- Der Python-Schema-Dump hatte ungefähr mehr als 250.000 Zeichen
- Zum Extrahieren von Werbedetails wurde es jedoch als ausreichend angesehen
Werbeabschnitt mit 1-Byte-Änderung deaktivieren
- Beim Dekodieren, Bearbeiten und Re-Encodieren des Protobuf Wire Format ohne ursprüngliches Schema kann sich die Kodierung ändern
- Als Gründe werden die mögliche Verwendung von ZigZag-Encoding, die fehlende Erkennbarkeit numerischer Typen und die nicht deterministische Reihenfolge von Objektfeldern genannt
- Die Lösung bestand darin, die Backward Compatibility von Protobuf zu nutzen, um den Werbeabschnitt wie ein unbekanntes Feld aussehen zu lassen
- Dabei wurde das Verhalten genutzt, dass alte Software unbekannte Felder ignoriert, wenn sie neue Felder liest
- Wenn man an einer kritischen Stelle 1 Byte ändert, sodass ein tief verschachtelter Abschnitt aussieht, als gehöre er zu einer zukünftigen Schema-Version, ignoriert Protobuf ihn
- Der Ziel-Feldschlüssel
49399797musste nicht per einfacher Stringsuche, sondern per Varint-Tag-Scanning gefunden werden- Der Wire Type war
2und steht für length-delimited nested string/message - Das Ziel-Tag wurde als
AA FF B8 BC 01berechnet - Wenn die 3 Bits des Wire Type herausgeschoben werden, erhält man wieder den Feldschlüssel
49399797
- Der Wire Type war
- Die tatsächliche Suche lief so ab, dass zunächst im rohen Protobuf-Byte-Stream nach einer Werbe-URL-Signatur wie
/pagead/gesucht wurde und man sich dann in der Nähe rückwärts zum Ziel-Feld-Tag und Feldschlüssel vorarbeitete- Beispielziel beim Intercept war
POST youtubei.googleapis.com:443/youtubei/v1/browse?key=... - Die Antwort war
200,application/x-protobuf,1.87m - Im Beispiel-Log wurde
49399797an Position4465und50195462an Position4477gefunden
- Beispielziel beim Intercept war
- In einem O(n)-Smoke-Test funktionierte die Werbeentfernung, indem 1,8 MiB Protobuf-Daten einmal ohne zusätzlichen Speicher gescannt wurden
- Das Ziel wurde beim 30.593. Byte gefunden
- Durch etwa 600 Byte Backtracking wurde der zu verfälschende Feldschlüssel gefunden
- Es ist nicht mehr nötig, URLs mit
*.googleadservices.comoder/pagead/zu blockieren, weil diese Anfrage gar nicht erst erzeugt wird
Struktur des MITMProxy-Add-ons
- Das PoC-Skript wird als
youtube.pygespeichert und mitmitmdump --listen-port 8080 --listen-host 127.0.0.1 -s "youtube.py"ausgeführt- Als Voraussetzungen unter FreeBSD werden
pkg install protobuf,pkg install py38-pipundpip install jsonpath-nggenannt
- Als Voraussetzungen unter FreeBSD werden
- Das Skript besteht aus den Klassen
Logger,trunc,KilledError,JSONPathReplacement,ProtobufDebugParserundYouTubeAdBlocker - Das Host-Regex für die Interception in
YouTubeAdBlockerlautet\.youtube\.com|google\.(com|ca)|googleapis\.com|googleadservices\.com|googlevideo\.com- Der Protobuf-Suchstring für Werbe-URLs ist
b"/pagead/" - Das Suchlimit beträgt
80_000 - Das Ziel-Feld-Tag ist
50195462
- Der Protobuf-Suchstring für Werbe-URLs ist
- Die Regel zum Blockieren von Requests prüft je Host partielle URL-Strings und killt dann den Flow
- Für
youtube.comumfasst das unter anderempagead/,log_event?,stats/ads,stats/qoe?,ptracking?,generate_204,error_204,adformat=,activeview?,_ad_,ai?,sw.js - Zu
sw.jsgibt es den Kommentar, dass Service Workers abgelehnt werden
- Für
- Bei JSON-Antworten werden mehrere JSONPath-Replacements angewendet
$.responseContext.serviceTrackingParams[*].params[?(@.key == 'yt_ad')].valuewird zu"0"geändert$..adPlacementswird zu[]geändert$..adPlacementRenderer,$..adPlacementConfig,$..playerAdParams,$..gutParamswerden zu{}geändert$..adVideoIdwird zu einem leeren String geändert$..showCompanion,$..showInstream,$..useGutwerden zuFalsegeändert
- Bei Protobuf-Antworten wird, wenn der Content-Type
protobufenthält, der Body zu einembytearraygemacht und innerhalb der ersten 80.000 Byte nach/pagead/gesucht- Mit
TagBytes(self.target_field_tag, WIRETYPE_LENGTH_DELIMITED)werden die Ziel-Tag-Bytes erzeugt, außerdem werden neue Bytes fürtarget_field_tag - 1erstellt - Direkt vor der Position von
/pagead/wird rückwärts nach den Ziel-Tag-Bytes gesucht - Wenn sie gefunden werden, werden diese Bytes mit den neuen Bytes überschrieben und mit
flow.response.set_content(bytes(body))der Response-Body ersetzt
- Mit
- Laut Kommentar blockiert dieses PoC 90 % der Werbung
- In anderen Sections gibt es weitere Field Keys, und es kann mehrere Ad-Sections geben, die manipuliert werden müssen
Geltungsbereich und Grenzen
- Diese Technik wird als hochspezialisierte Methode zum Blockieren von YouTube-Werbung auf Apple-Geräten oder von Tracker-Traffic bei Instagram, WhatsApp und Facebook beschrieben
- Der CPU-Bedarf für das Entschlüsseln und erneute Verschlüsseln von HTTPS-Traffic wird als deutlich über dem angesehen, was ein Raspberry Pi bewältigen kann
- Nach einem Jailbreak des Apple TV könnte man ein pfSense-Root-Zertifikat hinzufügen, sodass das pfSense-Gateway den Apple-TV-Traffic entschlüsselt und auf Werbe-Hostnames in den Request-Headern prüft, um ihn zu blockieren
- Auf iPhone-Werbung wäre das weiterhin nicht anwendbar, ein iPhone-Jailbreak ist schwieriger, und Banking-Apps könnten ihn erkennen und dann nicht mehr funktionieren
- Der Jailbreak selbst wird als zu extrem eingeschätzt
- Wenn eine gefälschte vertrauenswürdige CA möglich ist, können TLS-Pakete im Klartext entschlüsselt und URL-Blocking-Regeln angewendet werden
- Als Beispiel für zu blockierende URLs werden bei YouTube die Pfade
/pagead/viewthroughconversion/...und/pagead/conversion/...genannt
- Als Beispiel für zu blockierende URLs werden bei YouTube die Pfade
- Abschließend wird beschrieben, dass ein Hardware-Router von Grund auf eingerichtet, das LAN in vertrauenswürdige und nicht vertrauenswürdige Zonen aufgeteilt, DNS-Ad-Blocking und ein transparenter MITM-Proxy ergänzt und damit YouTube-Werbung auf mit dem Netzwerk verbundenen Apple-Geräten mit guter Performance blockiert wird
YouTube Premium und Unterstützung für Creator
- Nach einigen Monaten des Blockierens von YouTube-Werbung begann der Autor, für YouTube Premium zu zahlen, um Content Creator zu unterstützen
- Verbunden mit dem Hinweis: „Nur weil man etwas tun kann, heißt das nicht, dass man es tun sollte“
- Der Preis von YouTube Premium wird mit CAD
$9.99/mobis$11.99/mo, inklusive Steuern etwa$13.43/mo, angegeben - Für ein Experiment zum Ansehen von Werbung wurde YouTube einen Tag lang auf einem sauberen Laptop und im privaten Browsermodus sporadisch genutzt
- Laut Verlauf wurden 10 Videos angesehen
- Es wurden 8 Werbeanzeigen eingeblendet, von denen nur 2 überspringbar waren
- Bei einem angenommenen CPV von USD
$0.15ergeben sich Werbekosten von$1.20pro Tag, hochgerechnet etwa USD$36/mo - In einer anderen Berechnung mithilfe von Statista-Zahlen gaben US-Werbetreibende 2019
$15.1 billionfür YouTube aus, während Einwohner der USA916 billionVideos ansahen, was im Schnitt USD$0.0165pro View ergibt- Nach dieser Rechnung liegen die Kosten pro Tag bei etwa USD
$0.13, hochgerechnet etwa USD$3.96pro Monat - Dieser Wert wird nicht als in der Nähe von Premium zu USD
$10angesehen
- Nach dieser Rechnung liegen die Kosten pro Tag bei etwa USD
- Bei DMCA-Claims können Werbeeinnahmen nicht an den Creator, sondern an Anspruchsteller wie Sony oder Viacom gehen
- Dadurch kann es passieren, dass man seinen Lieblingskanälen unbemerkt gar nichts gibt
- Deshalb sei es nicht überraschend, dass viele Creator zu Patreon wechseln
2 Kommentare
Der Originalbeitrag ist ziemlich lang. Der Ablauf ist zwar interessant, aber der eigentliche Punkt ist, dass der Autor am Ende doch einfach YouTube Premium bezahlt und nutzt.
Meinungen auf Hacker News
Insgesamt ein cooler Hack, aber einige Aussagen zu Protobuf wirken seltsam.
Hier wurde absichtlich das Tag eines Felds in Protobuf beschädigt; unbekannte Tag-Nummern zu ignorieren ist kein „Mangel“, sondern ein zentraler Designaspekt für Erweiterbarkeit.
1,87 MiB ist auch keine besonders große Größe, und solche Nachrichten werden vermutlich nicht fortlaufend gestreamt; daher überzeugt mich die Erklärung als Performance-Hürde ebenfalls nicht so recht.
Protobuf-Encoding wurde nicht so entworfen, dass das Decoding teuer wird, sondern im Gegenteil so, dass es effizient decodiert werden kann; auch ohne das ursprüngliche
.proto-Schema lässt es sich direkt überUnknownFieldSetdecodieren.Die bessere Methode wäre wohl gewesen, ein gefälschtes
.proto-Schema zu verwenden, das nur das eine zu entfernende Feld enthält. Ein String-Scan ist fehleranfälliger, weil dieselbe Bytefolge zufällig in anderen Daten vorkommen kann.Wenn sich die Feldreihenfolge ändert, können sich die Bytes des neu encodierten Ergebnisses zwar unterscheiden, aber der Empfänger muss es als dieselbe Nachricht behandeln; es wirkt unwahrscheinlich, dass die YouTube-App eine geänderte Feldreihenfolge erkennt.
Aus Sicht von jemandem, der früher an Protobuf gearbeitet hat, scheint der Autor diesen Teil missverstanden zu haben.
Ich habe den größten Teil meines Lebens in ländlichen Gegenden verbracht, und wenn es nicht mein eigenes WLAN ist, ist selbst so etwas in der Praxis ein großer Download. Auf Mobilfunk gibt es vielleicht Workarounds, aber ländliches WLAN hat noch immer mit Web-2.0-Strukturen zu kämpfen und wird oft mit Geschwindigkeiten im Bereich von 2G bis 4G genutzt.
In Ballungsräumen, wo genügend Menschen vorhanden sind, um die Infrastruktur zu tragen, ist 1,87 MB meist zu einer kleinen Datei geworden – aber gegen 18 Uhr, wenn alle an den Kabelanschlüssen streamen, kann das eine Ausnahme sein.
without the C++ source proto files: Ich habe ein Projekt namens protodump gebaut, das aus Binaries die Quell-.proto-Dateien erzeugt.Es rekonstruiert Nachrichten- und Felddefinitionen einschließlich ihrer ursprünglichen Namen; man muss nur das Binary von der Apple-TV-Box extrahieren.
https://github.com/arkadiyt/protodump
Protobuf war die Technologie, die mich erstmals mit IDL in Kontakt brachte, und damals wirkte die Idee wie Magie. Nachdem ich selbst eine unbeholfene IDL gebaut und dann Protobuf entdeckt hatte, war ich noch beeindruckter.
Wenn man nicht die gesamte
protoc-Abhängigkeit hereinziehen will, kann man einen einfachen Protobuf-Decoder mit ein paar hundert Zeilen selbst schreiben: https://github.com/kubernetes/test-infra/blob/master/guberna... https://github.com/kubernetes/test-infra/blob/master/guberna...Seit ich vor über 20 Jahren The Proxomitron entdeckt habe, leite ich Traffic über einen Man-in-the-Middle-Proxy, um Werbung zu entfernen und Seiten mit Dingen wie eigenem CSS umzuschreiben.
Anbieter wie CloudFlare neigen dazu, mich als „Bot“ einzustufen, aber auch dafür gibt es Umgehungen, wenn auch keine ganz einfachen. Solche Fälle zeigen auch, warum Remote Attestation gefährlich für die Freiheit der Nutzer ist.
Es scheint mehrere „Nachfolge“-Projekte zu geben, und ich frage mich auch, ob es nur Windows ist. Ich hatte lose nach einem einfachen Proxy gesucht, der lokale Links in Remote-Inhalte einfügen kann.
Inzwischen habe ich auch das pi-hole, das auf einem Pi 4 lief, ausgesteckt. Ich habe Stunden damit verbracht, es mit mehreren Diensten zuverlässig zum Laufen zu bringen, aber am Ende aufgegeben; für ein Heimnetz war es die Zeit nicht wert.
Was tatsächlich gut funktioniert, sind browserbasierte Adblocker und App-Patcher wie ReVanced. Mit wachsenden Ersparnissen tendiere ich außerdem stärker dazu, bei Fällen, die sich damit nicht lösen lassen – YouTube Premium, Hulu, Netflix, Max –, einfach für werbefreie Dienste zu bezahlen.
Für den hier genannten Zweck habe ich es nie eingesetzt, aber als Proxy hinter einer Firmen-Firewall war es großartig. Früher verlangte die Firewall für externe Verbindungen Login-Daten, sodass viele Programme nicht ins Internet kamen.
Mir fällt Privaxy ein, als Docker-Paket. Ein Man-in-the-Middle-Proxy, der mit den Blocklisten von uBlock Origin kompatibel ist.
Es ist erstaunlich, wie viel Werbung und Tracking-Skripte es auf smarten Produkten gibt, insbesondere auf TVs. Nach meinen bisherigen Tests machte unnötiger Traffic über 40 % aus, und das Experimentieren damit, Werbung aus Smart-TV-Apps herauszulösen, war ziemlich interessant.
https://github.com/deetungsten/webui-privaxy ist ein dockerisierter Fork von https://github.com/Barre/privaxy
Ich wollte den Fork so ändern, dass im Frontend keine hartcodierte Adresse
0.0.0.0mehr verwendet wird, damit man den Docker-Container wirklich isolieren kann, aber dann kam das Leben dazwischen. Hast du es auf dem Apple TV ausprobiert?https://github.com/AdguardTeam/urlfilter
Dieser Artikel ist eine hervorragende Antwort auf die häufige Frage: „Wie lernt man, Hacker zu werden?“
Er zeigt sehr gut den Denkprozess und die beharrliche Arbeit, die in jedem Exploit steckt.
Da steht sinngemäß: „Nimm WireGuard — es gibt den Intel-AES-NI-Befehlssatz für Verschlüsselung“, aber soweit ich weiß, verwendet WireGuard kein AES.
Insgesamt scheint der Autor die CPU-Anforderungen von TLS-Verschlüsselung etwas zu überschätzen oder die Leistung moderner Single-Board-Computer zu unterschätzen.
Auch die Erklärung, dass die CPU-Anforderungen zum Entschlüsseln und erneuten Verschlüsseln von HTTPS-Traffic auf einem Raspberry Pi deutlich überschritten würden, finde ich fragwürdig. Wenn TLS-Man-in-the-Middle auf einem RPi 4 tatsächlich unmöglich wäre, würde mich das ziemlich überraschen, selbst bei rein softwarebasierter RSA-Nutzung.
Unter den noch genutzten Android-Smartphones gibt es Geräte mit schwächeren CPUs als beim RPi 4, und auch sie verwenden TLS.
Wenn ein schwaches Android-Smartphone TLS-Traffic nur mit 50 Mb/s verarbeiten kann, ist das im Alltag vielleicht kein großes Problem. Langsame Smartphones hängen schließlich meist an langsamen Netzen.
Wenn man zu Hause dagegen Gigabit-Internet hat und ein schwaches Gerät zwischen allen Computern und dem Internet einen Flaschenhals bei 50 Mb/s erzeugt, ist das ein großes Problem.
Die CPU-Anforderungen von TLS hängen sehr stark von der angestrebten Bandbreite ab. Bei höheren Bandbreiten wird Offloading auf Beschleuniger praktisch unverzichtbar. Auch die Kosten des Handshakes sind nicht zu vernachlässigen und können die Zahl der Verbindungen pro Sekunde begrenzen. Auf einem einzelnen Gerät ist das selten ein Problem, in einem ganzen Gerätenetzwerk kann es aber stärker ins Gewicht fallen.
Großartiger Artikel. Ich hatte gehofft, eine Methode zu sehen, Geräte per Man-in-the-Middle zu bearbeiten, die die Installation einer eigenen CA nicht erlauben.
Ich habe ein IoT-Gerät, das keine lokale API bereitstellt und Daten nur über die Cloud anzeigt, und ich möchte den Traffic zwischen Gerät und Cloud mitschneiden.
Bleibt am Ende wirklich nur, den Flash-Speicher zu dumpen, die CA auszutauschen und das Ganze wieder aufzuspielen?
Es gibt einen guten Artikel dazu, wie man versuchen kann, IoT-Geräte ohne Hardware- oder Firmware-Arbeiten abzufangen:
https://robertheaton.com/2019/11/21/how-to-man-in-the-middle...
Wenn es möglich ist, beruht es auf einem Implementierungsfehler.
Ehrlich gesagt glaube ich, dass selbst einige Geräte, auf denen man heute noch eigene vertrauenswürdige Zertifikate installieren kann, dafür nicht mehr lange offen sein werden.
Es kommen immer wieder neue Methoden auf, Werbung auf YouTube oder anderen Plattformen zu blockieren, aber ein paar Monate später werden sie geändert und sind nutzlos.
Wie wäre es stattdessen, die Werbetreibenden anzugreifen? YouTube/Google scheint nur „Klicks“ zu verfolgen — aber verfolgen sie auch tatsächliche Käufe?
Theoretisch könnten genügend Fake-Bots und echte Nutzer auf Anzeigen klicken, aber nichts kaufen, und so das Werbebudget verbrennen. Mit der Zeit würde die Marketingabteilung sehen, dass die Klickzahlen auf einer bestimmten Plattform Rekordwerte erreichen, die Conversion-Rate im Verhältnis zu Klicks oder Impressions aber sehr niedrig ist, und sich schließlich von dieser Plattform zurückziehen.
Erstaunlicher Artikel. Sobald ich den Schritt mit dem mitm-Patch gesehen habe, dachte ich, dass das etwas Besonderes werden würde, und genau das war es auch.
Der Eintrag im Inhaltsverzeichnis „Neues Ziel: YouTube glauben lassen, ich sei ein 70-jähriger Mann, der in Italien lebt“ ist mir hängen geblieben.
Vor einiger Zeit hat das Ad-Targeting es irgendwie geschafft zu glauben, ich sei jemand, der für seine Freundin einen waschbaren Seidenpyjama für 500 Dollar kaufen will.
Die Werbung selbst war großartig, aber ich frage mich, wie viel sie pro Impression bezahlt haben.
Seit dem Wechsel auf Apple TV bekomme ich meistens lokale Werbung, bei der das regionale Targeting falsch liegt. Im Durchschnitt ist das vielleicht sogar besser.
Das ist kein „Fehler“ in Protobuf. Dass es beim Ändern von Bytes als Feld an einer anderen Position dekodiert wird, ist Verhalten wie vorgesehen.
Protobuf ist von Anfang an ein Protokoll auf Basis von Feldnummern und Längenpräfixen, trifft die vernünftige Annahme, dass Bytes während der Übertragung nicht verändert werden, und überlässt die Integrität der lesenden Seite.
Selbst wenn es ein Fehler wäre, läge er nicht bei Protobuf, sondern in der YouTube-App für iOS; tatsächlich ist es aber nicht einmal ein Fehler, daher ist es auch schwer, das als „Exploit“ zu bezeichnen. Es sei denn, gemeint ist, dass beim Protobuf-Austausch der YouTube-iOS-App der Hash der zurückgegebenen Payload nicht geprüft wird.
Nach diesem Artikel wird das vermutlich künftig geprüft werden.
Es ist kein Fehler, sondern funktioniert wie entworfen.
Auch die Aussage, „Google mache das Dekodieren, Modifizieren und erneute Enkodieren ohne C++-Source-Proto-Datei rechnerisch teuer“, ist seltsam. Mit nicht optimiertem Python-Code mag es teuer sein, aber in C oder einer anderen kompilierten Sprache ist das Scannen eines 1,8-MB-Protobufs trivial – unabhängig davon, ob man die Proto-Quelldatei hat oder nicht.
Es dürfte kaum ein Designziel gewesen sein, Protobuf-Dateien ohne Source schwer dekodierbar zu machen. Wenn das das Ziel war, wurde es ziemlich schlecht umgesetzt.