1 điểm bởi GN⁺ 2025-03-19 | 1 bình luận | Chia sẻ qua WhatsApp
  • Đây là một PoC đặt proxy MITM dựa trên pfSense giữa Apple TV và Internet để giải mã HTTPS, rồi chỉnh sửa các phản hồi Protobuf do YouTube gửi xuống nhằm ngăn các slot quảng cáo được đăng ký trên thiết bị Apple
  • Các trình chặn DNS và định tuyến VPN hiện có vấp phải những giới hạn như DNS TTL, sai lệch IP, lỗi 403 và rò rỉ ASN, do quảng cáo YouTube và video chính dùng cùng domain và hạ tầng
  • Thử nghiệm với Squid bị dừng vì vấn đề hiệu năng và cấu hình; sau đó chuyển sang cách dùng mitmproxy/mitmdump trong FreeBSD jail để giải mã lưu lượng TLS và sửa trực tiếp các phản hồi JSON/Protobuf
  • YouTube bản web có thể loại bỏ adPlacements, playerAdParams, URL pagead trong JSON, v.v., nhưng ứng dụng YouTube trên iOS chứa slot quảng cáo và thông tin theo dõi trong phản hồi application/x-protobuf, nên phải xử lý cấu trúc Protobuf
  • Cách cuối cùng là quét tuyến tính và sửa 1 byte: tìm ngược field tag gần chuỗi /pagead/, rồi đổi các tag như 50195462 thành target_field_tag - 1; cách này đủ hiệu năng để xử lý thời gian thực mà không cần giải mã toàn bộ

Mục tiêu và thiết kế mạng ban đầu

  • Mục tiêu là tạo một router dựa trên FreeBSD và pfSense để chặn quảng cáo YouTube pre-roll, mid-roll và end-roll trên Apple TV và iPhone ở phạm vi toàn mạng
  • Nếu đặt một proxy man-in-the-middle giữa Apple TV và Internet bên ngoài, có thể giải mã lưu lượng HTTPS và đọc dữ liệu Protocol Buffer mà Google dùng để lấp đầy quảng cáo YouTube
  • Sau vài tháng triển khai chặn quảng cáo YouTube, tác giả bắt đầu trả tiền cho YouTube Premium và nói rằng “có thể làm” khác với “nên làm”
  • Các lý do chặn quảng cáo/theo dõi được nêu gồm theo dõi dữ liệu cá nhân, lãng phí băng thông, clickbait và cryptojacking
    • Tác giả cho rằng 25–40% lưu lượng mạng có thể là quảng cáo, script theo dõi, fingerprint.js, googletagmanager.js và các loader phân tích thời gian thực như Hotjar
    • Tác giả giải thích rằng JavaScript đào tiền mã hóa như CoinHive.js có thể làm máy tính quá nhiệt hoặc bị lạm dụng để kiếm những khoản tiền nhỏ

Phần cứng pfSense và thiết lập cơ bản

  • Để bảo vệ toàn bộ mạng SMB, tác giả cho rằng VM, image Docker hay Raspberry Pi không đủ hiệu năng, nên cần phần cứng chuyên dụng chỉ đảm nhiệm định tuyến gói tin, giải mã và giám sát
  • Phần cứng router được dùng gồm mini PC có tập lệnh AES-NI, RAM DDR4, SSD mSATA và USB để flash pfSense
    • Cấu hình ví dụ là mini PC J4125, RAM DDR4 32GiB và SSD mSATA 128GiB
    • Dung lượng lưu trữ 128GB được xem là đủ cho log, giảm wear của SSD, bắt gói tin và cache biên NPM/Docker
  • Image cài đặt pfSense khoảng 360MB và có thể flash vào USB bằng Etcher AppImage
  • Sau thiết lập đầu tiên, AES-NI hiển thị là “Yes (inactive)”, nên tác giả bật thủ công trong System › Advanced › Miscellaneous
  • Để tận dụng RAM 32GiB, tác giả cấp phát rộng rãi RAM disk cho /var/tmp, đồng thời cấu hình sao lưu RAM disk mỗi giờ với kỳ vọng SSD 128GiB có wear-leveling
  • Trên Dashboard, tác giả thêm widget S.M.A.R.T. để có thể phát hiện bất thường của SSD

Chặn DNS, tách mạng và pfBlockerNG

  • Trước đây tác giả dùng Pi-hole trên Raspberry Pi làm trình chặn quảng cáo ở mức DNS; trên pfSense, tác giả cài pfBlockerNG-devel để thử chặn quảng cáo/nội dung độc hại và geo-blocking
  • Nếu dịch vụ pfb_dnsbl không khởi động hoặc tab status hiển thị [ Missing CRON task ], tác giả khuyên thử xóa file rỗng /var/run/booting
  • Tận dụng 3 cổng Gigabit của mini PC, tác giả tạo các mạng vật lý thay vì VLAN, và tách các thiết bị “phoning-home” như Alexa và Apple TV khỏi mạng chính
    • Thiết bị untrusted được đặt trong mạng riêng 172.31.1.0/24
    • LAN trusted được giữ ở 192.168/16
    • LAN phần cứng dành cho IoT đi qua adblocker, đồng thời cố chặn YouTube vượt qua trình chặn DNS bằng cách chặn bắt các truy vấn DNS hard-coded như 1.1.1.19.9.9.9
  • Tác giả cấu hình quy tắc NAT để mọi client phía sau pfSense dùng máy chủ Unbound DNS cục bộ
    • Tác giả cho rằng phải chặn DNS over TLS trước thì mới có thể chặn bắt truy vấn DNS
    • iPhone có thể hiển thị Privacy Warning về việc chặn lưu lượng DNS được mã hóa, nhưng các yêu cầu DNS upstream được mã hóa tới Cloudflare
    • Cần tắt NAT reflection để Internet bên ngoài không thể truy cập máy chủ DNS
  • Tác giả tạo firewall alias Non_WAN để chuyển hướng các truy vấn DNS cục bộ trên cổng 53 từ các interface không phải WAN về localhost
  • Vì YouTube phân phối quảng cáo và video chính từ cùng domain, rất khó chỉ lọc quảng cáo bằng trình chặn theo tên miền như pfBlockerNG hay Pi-hole

Thử nghiệm né bằng VPN và các điểm thất bại

  • Thay vì chặn quảng cáo, tác giả cũng thử đánh lừa thuật toán quảng cáo của YouTube để trông giống một người dùng kém hấp dẫn hơn với nhà quảng cáo
    • Tác giả cố định tuyến lưu lượng theo dõi vị trí của YouTube qua VPN tới khu vực có ít người xem bằng router pfSense
    • Mục tiêu là để tài khoản YouTube được nhận diện là “nam 70 tuổi, sống tại Italy”
  • Trên pfSense, tác giả dùng WireGuard thay vì OpenVPN để thực hiện thử nghiệm cơ sở: đưa toàn bộ lưu lượng Apple TV qua VPN
    • Cài gói WireGuard cho FreeBSD rồi thêm và kích hoạt tunnel
    • Để cấu hình NordLynx, tác giả kiểm tra private key bằng sudo wg showconf nordlynx trên một VM Linux rồi chuyển sang pfSense
  • Kết quả thử nghiệm cho thấy Google trên laptop hiển thị bằng tiếng Italy, và YouTube trên Apple TV cũng chuyển sang tiếng Italy
    • Quảng cáo vẫn xuất hiện một phần, nhưng được cho là ít hơn trước
    • Netflix và Amazon Prime gặp vấn đề; có vẻ các file CSS hoặc font bị chặn, hoặc thumbnail không tải được
    • Tác giả cảnh báo không nên đưa toàn bộ lưu lượng Apple TV qua VPN, và cho rằng Netflix và Prime phát hiện tốt VPN provider và geofencing
  • Sau đó, để chỉ đưa lưu lượng YouTube của Apple TV qua VPN, tác giả cấu hình firewall policy rule nhắm tới www.youtube.com, youtube.com, googlevideo.com, accounts.google.com, googleapis.com, gstatic.com, v.v.
    • Kết quả là YouTube thấy người dùng ở Milan, còn Netflix và Prime Video thấy người dùng ở Canada
    • Quảng cáo giảm xuống mức “thưa thớt lắm mới có”
  • Một ngày sau, DNS race condition xuất hiện
    • Hostname alias của pfSense mặc định được resolve mỗi 300 giây
    • DNS TTL của YouTube có thể là 1.440 giây, tức 24 phút
    • Nếu IP mà Alias Daemon resolve được khác với IP mà client thực sự nhận, policy có thể không tunnel lưu lượng YouTube
  • Một số video YouTube không phát được do 403 Forbidden
    • YouTube được cho là nhúng IP của người dùng vào từng yêu cầu googlevideo.com
    • Nếu một domain biến thể như r5---sn-hpa7kn76.googlevideo.com không được tunnel, yêu cầu sẽ đi ra từ IP sai và gây lỗi
    • Thứ cần có là tunnel wildcard *.googlevideo.com, nhưng NAT và firewall rule hoạt động theo IP chứ không theo wildcard hostname

PoC theo dõi IP dựa trên truy vấn DNS

  • Đã nghĩ ra phương thức chiếm quyền truy vấn DNS của Google Video để định tuyến *.googlevideo.com qua VPN
    • Cách làm là theo dõi định kỳ log truy vấn DNS và thêm các truy vấn *.googlevideo.com vào danh sách alias
    • Nếu mỗi video dùng một domain riêng và đã được biến đổi, thì cách này được cho là sẽ không hoạt động trừ khi làm mới cho từng video
  • Mục tiêu mới là dùng Python 3 và pfSense REST API để giám sát truy vấn DNS, bắt IP, tạm giữ phản hồi, sau đó thêm IP vào quy tắc VPN tunneling rồi release DNS reply
  • Đã cài pfSense REST API và gửi yêu cầu GET tới https://pfsense/api/v1/firewall/alias để truy vấn alias VPN_domains
  • Đã tìm hiểu module Python của Unbound DNS Resolver và ghi log được DNS-query message
    • Phiên bản Python hiện tại là 3.8
    • Ví dụ của Unbound Python module dựa trên Python 2.4, nên cho rằng có thể cần 2to3 hoặc định dạng lại
  • Script PoC trích xuất IP trong A/AAAA record từ DNS response và thêm vào alias của pfSense
    • Bản ghi A được xử lý bằng ipaddress.IPv4Address(d.rr_data[j][2:]).exploded
    • Bản ghi AAAA được xử lý bằng ipaddress.IPv6Address(d.rr_data[j][2:]).exploded
    • TTL của alias được đặt là 1 giờ, capacity là 500
  • Ngày hôm sau, Unbound DNS Resolver bị segfault, và vì mỗi lần thêm IP đều phải reload rule của pfSense nên pfSense trở nên rất chậm

Chuyển từ Squid sang mitmproxy

  • Mục tiêu mới chuyển sang hướng khảo sát và cài đặt proxy họ Squid, tạo chứng chỉ CA giả được tin cậy rồi giải mã TLS traffic
  • Trong thử nghiệm Squid, đã kiểm tra liệu proxy squid3 được cung cấp dưới dạng pfSense package có đáp ứng yêu cầu hay không
    • Tạo thư mục riêng /squid_cache và đặt kích thước cache là 8GiB
    • Kỳ vọng có hỗ trợ Transparent HTTPS
  • Sau một ngày cấu hình Squid và SquidGuard thì đã bỏ cuộc
    • Tốc độ rất chậm
    • Cấu hình ACL rườm rà
    • Có issue liên quan đến https://http/*
    • Việc update danh sách filter URL của SquidGuard mất rất nhiều thời gian
    • UI của Squid còn thiếu
  • Sau đó quyết định dùng mitmproxy được viết bằng Python
    • Chọn mitmproxy thay vì SSLSplit vì khả năng mở rộng bằng Python hook và UI
    • Phiên bản FreeBSD của pfSense là 12.2-Stable, bản build 64-bit
  • Trong môi trường mặc định của pfSense, jail bị disabled nên đã cài thủ công ezjail và tạo jail cho mitmproxy
    • Tạo jail bằng ezjail-admin create mitmproxy 'lo0|127.0.1.1'
    • Đặt allow.raw_sockets=1 cho transparent proxy mode
    • Nếu raw socket bị chặn thì có thể xuất hiện lỗi như Transparent mode failure hoặc Cannot open connection, no hostname given.
  • Việc chạy Linux tarball binary trên FreeBSD thất bại
    • Xuất hiện lỗi ELF interpreter /lib64/ld-linux-x86-64.so.2 not found
    • Cũng không tìm thấy libdl.so.2, libz.so.1, libpthread.so.0, libc.so.6
  • Trong jail, đã chạy pkg install mitmproxy; quá trình cài đặt yêu cầu 50 package, thêm 206MiB dung lượng và tải xuống 33MiB
  • Để có thể truy cập MITMProxy từ LAN, đã gắn virtual IP 127.0.1.1 vào localhost và tạm thời forward [Private IPs]:8080 tới 127.0.1.1:8080 bằng NAT rule
  • File CA PEM do MITMProxy tự động tạo là ~/.mitmproxy/mitmproxy-ca-cert.pem, và đã cài CA cert này vào Trusted Root Store của thiết bị thử nghiệm
  • mitmproxy dùng nhiều CPU ngay cả khi idle, và cho rằng việc tạo TLS certificate theo thời gian thực cho từng request cùng lượng logging quá mức đã làm tốc độ chậm đi đáng kể
    • mitmdump được cho là giảm tải CPU hơn vì bỏ qua UI và logging quá mức

Loại bỏ quảng cáo JSON trên web YouTube

  • Certificate Pinning là kỹ thuật trong đó server hoặc client biết trước fingerprint của certificate dự kiến, khiến việc giả mạo certificate của MITMProxy không có tác dụng
  • Có thể cho host có vấn đề đi vòng qua proxy bằng tùy chọn --ignore-hosts
    • Ví dụ đã ignore apple.com:443, icloud.com:443
  • Khi truy cập YouTube, page ads xuất hiện trong MITMProxy cùng các header không được mã hóa, và đã xem xét khả năng chặn bằng regex đơn giản
  • Để áp dụng script chặn quảng cáo YouTube, đã thêm --scripts "youtube.py" vào mitmdump
  • Smoke-test filter chặn request quảng cáo dựa trên substring trong URL
    • youtube.com: /pagead/, /log_event?, /stats/ads, /stats/qoe?, /ptracking?, /generate_204, el=adunit, adformat=, /activeview?
    • google.com, google.ca: /pagead/
    • ggpht.com: .
  • Các request định chặn trông như đã thực sự bị chặn trong MITMProxy và panel Network của DevTools, nhưng ads vẫn xuất hiện, đôi khi ads tự skip hoặc phát thất bại
  • Sau đó phát hiện khá nhiều URL liên quan đến quảng cáo bên trong JSON payload
  • Sau khi phân tích UI YouTube và HTTP workflow đến cả cookies và service workers, họ nói rằng đã có thể loại bỏ toàn bộ quảng cáo pre-roll, post-roll và mid-video
  • Ở giai đoạn này, router đã có thể loại bỏ ads khỏi JSON payload của YouTube web ads

YouTube iOS và vấn đề Protobuf

  • Ứng dụng YouTube iOS hiển thị dữ liệu rất giống với phiên bản web trong phiên bản Protobuf của cùng các lệnh gọi API
  • Trong Protobuf, key là số và có thể thay đổi, nên không thể dùng cách tìm phần quảng cáo bằng JSONPath
  • YouTube gửi trong payload một danh sách lớn các quảng cáo sẽ xem sắp tới, và khi dùng hết danh sách đó thì một danh sách lớn khác sẽ sớm được gửi đến
  • Trong payload Protobuf có thể thấy các chuỗi như “Telus,” “Samsung TV,” “Boxing Week,” “Buy now”
  • Giao thức YouTube trên iOS khác với traffic web
    • Ở phiên bản web, có thể phần nào phân biệt video quảng cáo và video muốn xem bằng cách nhìn vào URL và tham số truy vấn range
    • Giao thức iOS không dùng tham số truy vấn range cũng như header Range, mà dùng các bộ đếm như &nr=2, &nr=3 trong chunk video
    • Để chặn quảng cáo trên iOS, cần reverse-engineer response Protobuf
  • Trong message Protobuf đã decode, tác giả phát hiện các mục has_unlimited_entitlement: False, has_premium_lite_entitlement: False, nhưng thay vì toggle chúng thì quay lại dùng heuristics
  • Decode khoảng 500KiB Protobuf thô bằng pure implementation Python rất chậm
    • Trên desktop i7-6700, kết quả Python khoảng 2,06~2,11 giây
    • Trên router pfSense, kết quả Python khoảng 22,8~24,2 giây
    • C++ protoc --decode_raw trên desktop khoảng 0,017~0,022 giây, và trên router pfSense khoảng 0,12~0,14 giây

Decode Protobuf và thử trích xuất schema

  • Vì Python không hỗ trợ decode Protobuf thô, thay vì dùng trực tiếp C++ libprotobuf.so, tác giả chọn cách giao tiếp với binary C++ protoc bằng subprocess.Popen
  • Khi fuzzing response video quảng cáo, tác giả thử response 200 rỗng, 404, 503, body response bị cắt ngắn, xử lý null một phần video quảng cáo, v.v., nhưng ứng dụng iOS sau khi chậm đi thì crash hoặc kẹt ở màn hình quảng cáo
  • Chặn URL kích hoạt hành vi phản ứng của ứng dụng, và chunk response video cũng chứa session metadata
  • blackboxprotobuf cho Burp Suite cho phép decode raw Protobuf wire message, chèn nội dung rồi encode lại để kiểm tra hành vi của endpoint Protobuf
    • Nên dùng bản Burp Suite gốc, không phải fork trên PyPI
    • Một số fork gặp vấn đề stack overflow hoặc infinite recursion do đệ quy sâu
    • Nếu dùng C++ bindings, có thể transcode khoảng 500KiB Protobuf thô chỉ trong vài giây
  • Schema được tạo ra không hoàn hảo, lớn và lồng nhau sâu, việc pretty-print chậm, nhưng đủ để tìm thông tin chi tiết về quảng cáo
  • Tác giả thử PBTK, Apktool, dex2jar, Java Decompiler để trích xuất file .proto hoặc schema thực tế từ APK YouTube Android
    • Thứ PBTK trích xuất được chỉ là một file proto 59 byte
    • Trong Java có các class Protobuf và getter/setter, nhưng không lấy được true schema files nên dừng lại

Bước ngoặt cuối cùng: thay đổi 1 byte field tag của Protobuf

  • Từ traffic mạng đã giải mã và kết quả fuzzing Protobuf, quảng cáo được quan sát là có cấu trúc đăng ký vào các slot của một video cụ thể
    • Các loại slot gồm pre-roll, mid-roll, end-roll, full-page, ad pods
    • Nếu chặn URL quảng cáo, lỗi kiểu “một quảng cáo không tồn tại đã giữ chỗ slot” sẽ xảy ra và UI panic
  • Nếu decode, chỉnh sửa rồi encode lại khi không có schema gốc, encoding sau chỉnh sửa sẽ khác; vì không biết có dùng ZigZag hay không, cũng như không biết các kiểu số như int32, int64, sint32/64, varint, và thứ tự field của object thường cũng nondeterministic, nên tác giả xem đây là vấn đề
  • Tác giả tìm thấy khả năng bypass trong backward compatibility của Protobuf và hành vi UnknownFieldSet
    • Khi phần mềm cũ đọc message có field mới được thêm vào, unknown field có thể xuất hiện
    • Nếu đổi một field key cụ thể sang giá trị khác, toàn bộ sub-structure chứa thông tin quảng cáo và tracking có thể trở thành trạng thái unavailable
  • Ví dụ, tác giả đề xuất ý tưởng đổi field key 49399797 thành 49399796 để biến sub-structure quảng cáo/tracking đó thành như một unknown field
  • Không thể tìm field key 49399797 chỉ bằng tìm kiếm hex đơn giản, mà phải xét varint/tag encoding
    • Wire type là 2, nghĩa là nested string/message dạng length-delimited
    • Chuỗi byte tag của target field key 49399797 trở thành AA FF B8 BC 01
    • Dịch phải 395198378 >> 3 để loại bỏ 3 bit wire type sẽ thu được field key gốc 49399797
  • Trong bytes Protobuf, tác giả tìm signature URL quảng cáo cổ điển như /pagead/ để khoanh vùng tìm field, rồi từ vị trí đó lùi lại để tìm field tag và field key cần thay đổi
  • Trong log intercept ví dụ, ở response application/x-protobuf 1,87MiB của yêu cầu POST youtubei.googleapis.com:443/youtubei/v1/browse?key=..., key 49399797 được tìm thấy tại vị trí 4465, key 50195462 tại vị trí 4477
  • Trong O(n) smoke test, tác giả scan dữ liệu Protobuf 1,8MiB một lần mà không dùng thêm memory
    • Target được tìm thấy ở byte thứ 30.593 trong 1,8MiB
    • Dùng backtracking khoảng 600 byte để tìm field key cần denature
  • Khi phương pháp này hoạt động, không còn cần chặn các URL chứa *.googleadservices.com hoặc /pagead/ nữa, và những request đó ngay từ đầu đã không còn phát sinh

Cấu trúc script add-on MITMProxy

  • Script add-on MITMProxy được cung cấp như một proof of concept để chặn quảng cáo YouTube trên Apple device nối mạng
    • Tên file là youtube.py
    • Ví dụ chạy: mitmdump --listen-port 8080 --listen-host 127.0.0.1 -s "youtube.py"
    • FreeBSD prerequisite là pkg install protobuf, pkg install py38-pip, pip install jsonpath-ng
  • Script có bao gồm fairness function cho phép 5% quảng cáo nhằm hỗ trợ nhà sáng tạo nội dung
    • in_allowed_ads_window() bỏ qua việc chặn quảng cáo nếu thời gian hiện tại nằm trong khoảng từ phút 0 đến phút 2 của mỗi giờ
  • YouTubeAdBlocker intercept các domain liên quan đến YouTube và chỉnh sửa JSON hoặc Protobuf response để loại bỏ thông tin quảng cáo
    • Regex host mục tiêu intercept là \.youtube\.com|google\.(com|ca)|googleapis\.com|googleadservices\.com|googlevideo\.com
    • Chuỗi dùng để phát hiện quảng cáo Protobuf là b"/pagead/"
    • Giới hạn tìm kiếm là 80_000 byte
    • Target field tag là 50195462
  • Danh sách chặn ở giai đoạn request bao gồm pagead/, log_event?, stats/ads, stats/qoe?, ptracking?, generate_204, error_204, adformat=, activeview?, _ad_, ai?, sw.js v.v. trên host YouTube
  • JSON replacement cho YouTube web loại bỏ hoặc vô hiệu hóa các field liên quan đến quảng cáo
    • yt_ad được đổi thành "0"
    • adPlacements được đổi thành []
    • adPlacementRenderer, adPlacementConfig, playerAdParams, gutParams được đổi thành {}
    • adVideoId được đổi thành ""
    • showCompanion, showInstream, useGut được đổi thành False
  • Hook load() vô hiệu hóa HTTP/2 và đặt anticomp=True, mode="transparent"
  • Hook running() cập nhật allow_hosts để việc intercept chỉ áp dụng cho các domain liên quan đến YouTube
  • Hook response() nếu content-typeprotobuf thì tìm /pagead/ trong 80.000 byte đầu của body response
    • Nếu tìm thấy, tạo target tag bytes bằng TagBytes(self.target_field_tag, WIRETYPE_LENGTH_DELIMITED)
    • Tạo tag bytes của target_field_tag - 1 thành bytes mới
    • Reverse search phía trước vị trí /pagead/ để tìm target tag
    • Thay thế bytes tại vị trí đó bằng bytes tương ứng với target_field_tag - 1
    • Đưa nội dung Protobuf đã sửa trở lại bằng flow.response.set_content(bytes(body))
  • Chú thích trong code cho biết PoC này đã chặn được 90% quảng cáo, đồng thời nói thêm rằng trong các section khác cũng có các field key khác và có thể có nhiều section quảng cáo cần vô hiệu hóa

Hiệu năng, giới hạn và người dùng mục tiêu

  • Kỹ thuật cuối cùng tận dụng việc Protobuf cho phép unknown field để backward-compatible với schema change, cùng độ nhạy với chỉnh sửa một byte của compact format
  • Nếu đổi 1 byte tại critical spot để khiến một section lồng sâu trông như thuộc về future schema version, Protobuf có thể ignore nó và loại bỏ thông tin quảng cáo
  • Google trả về một Protobuf response lớn, bao gồm cả layout app iOS; payload ví dụ là 1,8 MiB
  • Để parse toàn bộ payload cần native code như C++/Swift, còn Python decoding được cho là chậm hơn nhiều bậc và gây connection timeout
  • JSON nền web phải parse, edit rồi re-serialize toàn bộ payload, nhưng kỹ thuật Protobuf chỉ cần linear scan và backtrack nhanh nên xử lý ở mức microsecond, phù hợp với real-time adblocking và không cần blocklist
  • Tất cả URL *.googleadservices.com/pagead/* trên Apple device đều đến từ Protobuf payload; khi ad data biến mất khỏi payload, các request đó cũng tự động biến mất
  • YouTube app không cố fetch URL quảng cáo nên cảm giác nhanh hơn, và vì quảng cáo không được đăng ký vào video slot nên content phát ngay lập tức
  • Cách này được giới thiệu như một highly specialized technique để chặn Apple-device YouTube ads hoặc tracker traffic của Instagram, WhatsApp, Facebook
  • Nhu cầu CPU để decrypt/re-encrypt HTTPS traffic được cho là vượt xa đáng kể hiệu năng của Raspberry Pi
  • Vì nhắm đến Apple-device owner không muốn compromise OS, nhóm người dùng được xem là hẹp hơn

YouTube Premium và thử nghiệm chi phí quảng cáo

  • Tác giả cho rằng chưa chắc YouTube Premium có hợp lý hay không khi giá là CAD $9.99/mo hoặc CAD $11.99/mo, tính thuế khoảng CAD $13.43/mo
  • Tác giả thực hiện thử nghiệm mức độ hiển thị quảng cáo bằng một laptop sạch và private browsing, xem YouTube không liên tục trong một ngày
    • Theo lịch sử xem, số video đã “xem” chỉ là 10
    • Trong lúc xem một phần của 10 video, tác giả thấy 8 quảng cáo
    • Chỉ có 2 quảng cáo có thể bỏ qua và cả hai đều được bỏ qua
  • Nếu giả định CPV xấp xỉ USD $0.15, 8 quảng cáo mỗi ngày tương đương chi phí nhà quảng cáo 8 x $0.15 = $1.20, ngoại suy theo tháng là khoảng USD $36/mo
  • Tác giả cũng đưa ra phép tính dựa trên dữ liệu Statista, lấy chi tiêu quảng cáo tại Mỹ chia cho tổng lượt xem
    • Năm 2019, nhà quảng cáo Mỹ đã chi $15.1 billion trên YouTube
    • Người dân Mỹ được cho là đã xem 916 billion video
    • Trung bình là $15.1B / 916B = USD $0.0165 per view
    • Với trường hợp của tác giả, con số này tương ứng chi phí nhà quảng cáo khoảng USD $0.13 mỗi ngày, khoảng USD $3.96 mỗi tháng
  • Vì trong lúc thử nghiệm quảng cáo tác giả bật tắt tiếng bằng phần cứng và thường xuyên nhìn sang chỗ khác, tác giả cho rằng tiền quảng cáo nhắm vào mình đã bị lãng phí
  • Dù vậy, tác giả vẫn muốn hỗ trợ nhà sáng tạo và cho biết sẽ dùng thử 3 tháng Premium trial, đồng thời tiếp tục theo dõi Google đang tracking gì về mình
  • Tác giả lo ngại rằng từ thời điểm DMCA claim được tiếp nhận, toàn bộ doanh thu quảng cáo có thể chuyển tới claimant thay vì nhà sáng tạo, và nói thêm rằng việc nhiều nhà sáng tạo chuyển sang Patreon không có gì đáng ngạc nhiên

Tổng kết cuối cùng

  • Thiết lập hardware router từ đầu và tách LAN thành trusted/untrusted zone
  • Thiết lập chặn quảng cáo DNS truyền thống
  • Thêm transparent MITM proxy
  • Cuối cùng, tác giả cho biết đã có thể chặn quảng cáo YouTube với hiệu năng tốt trên các thiết bị Apple nối mạng
  • Tác giả viết rằng vì phần khó đã xong nên sẽ cân nhắc trả tiền YouTube Premium, nhưng nói thêm rằng tracker vẫn sẽ bị chặn mạnh tay

1 bình luận

 
GN⁺ 2025-03-19
Ý kiến trên Hacker News
  • Có vẻ không hẳn là khiếm khuyết của định dạng Protobuf, mà là tác giả đã đổi số field sang một số lớn chưa dùng
    Cách làm là tìm chữ ký URL quảng cáo như /pagead/ trong các byte Protobuf để xác định phạm vi field, rồi đi lùi lại từ đó để tìm tag field mục tiêu và key field nhằm vô hiệu hóa nó; việc này gần với hành vi có chủ đích hơn là một lỗ hổng
    Nếu đã bỏ công đến mức tìm tag, thì việc đọc độ dài varint ngay bên cạnh và bỏ qua các byte tương ứng cũng không phải là thêm nhiều việc. Có thể sẽ phải sao chép buffer hoặc dịch chuyển byte, nhưng script PoC cũng đã phải sao chép rồi vì bytes mà API mitmproxy trả về là bất biến

    • Ở cấp độ giao thức thì nó hoạt động đúng như dự kiến, nhưng điểm yếu có vẻ là khi có field không xác định trong cấu trúc dữ liệu quảng cáo, Google không báo lỗi mà xử lý như thể không có quảng cáo
      Google hẳn sẽ phát hành ứng dụng mới trước khi thay đổi giao thức đến mức làm toàn bộ quảng cáo không hiển thị trên các phiên bản ứng dụng cũ, nên chỉ cần pin chứng chỉ cơ bản hoặc giải mã ít khoan dung hơn khi không trích xuất được thông tin quảng cáo là có thể chặn ngay cách này. Nếu là đội YouTube, tôi nghĩ họ sẽ xem phần này là lỗi
    • Đối tượng bytes là bất biến, nhưng đối tượng bytearray thì không
  • Một proxy C++/Go nhỏ cũng có thể làm cùng việc với overhead thấp hơn nhiều. Những tác vụ được định nghĩa rõ như thế này sẽ ổn định hơn và đỡ mất công hơn so với vật lộn với mitmproxy
    Nếu đưa toàn bộ lưu lượng qua proxy thì hiệu năng sẽ giảm, ngay cả khi dùng chặn bắt SNI. pfSense cũng tương tự; một máy chủ Linux đơn giản cùng vài quy tắc iptables đơn giản là có thể xử lý mà không phải đánh vật với các lớp trừu tượng của pfSense
    Chỉ cần viết vào file .proto đúng phần cần thiết trong các proto field đã reverse-engineer, tự động sinh code rồi đổi flag là được. Cách này rẻ hơn bản triển khai Python và cũng dễ cập nhật hơn khi proto thay đổi. Bỏ qua các tag field không xác định là một tính năng quan trọng của Protobuf, cho phép thay đổi schema tương thích mà không phá vỡ các bản đã triển khai

    • Cũng có thể cố tình làm trải nghiệm YouTube chậm hơn và việc chuyển video ì ạch hơn lại là điều tốt. Đặc biệt có vẻ sẽ giảm đáng kể tính gây nghiện của Shorts
    • Tôi sẽ mong có một bài blog chia sẻ chi tiết cách làm như vậy
    • Sẽ rất hay nếu bạn tự viết một hướng dẫn chỉ ra phần kém hiệu quả nằm ở đâu và có thể giảm nhẹ bằng phần mềm đơn giản hơn như thế nào
      Có vẻ tác giả đã nhận thức được phần lớn những điểm trong bình luận, và bài viết cũng khá kỹ lưỡng. Họ đã benchmark bằng Python và C++, còn bản triển khai cuối thậm chí không giải mã Protobuf. Họ cũng đã thử nhiều giải pháp mitm, và dùng pfSense không phải như một router bảo mật đơn giản mà để nhắm riêng lưu lượng Apple TV bằng VLAN và VPN
      Bình luận này nghe quá rẻ tiền và hạ thấp người khác. Bài gốc thì không như vậy, nên nếu muốn nói thế, bạn nên tự chứng minh cho cộng đồng thấy
    • Tôi tò mò không biết có đề xuất nào về một proxy nhẹ chạy trên macOS và cũng phục vụ được các thiết bị khác trong nhà không
  • Nếu trả tiền YouTube Premium thì có hỗ trợ creator không? Nếu có thì tôi tò mò mức độ ra sao so với tài trợ trực tiếp kiểu Patreon

    • Chắc là không nhiều bằng Patreon, nhưng cũng khó kỳ vọng rằng chỉ vì xem nhiều YouTuber mà người ta sẽ đăng ký Patreon của tất cả họ
      Khoản doanh thu mà một gói YouTube Premium đem lại cho từng creator có thể rất nhỏ, nhưng vẫn tốt hơn việc xem video trong khi chặn quảng cáo
    • Người ta nói creator nhận được phần lớn hơn từ lượt xem YouTube Premium so với lượt xem quảng cáo thông thường. Vì nếu bỏ qua quảng cáo thì không có doanh thu. Tuy nhiên vì số người dùng Premium ít nên vẫn có giới hạn
    • Thông tin gần đây khá hiếm, nhưng khi mới ra mắt dưới tên Youtube Red thì nhìn chung nó cao hơn nhiều so với doanh thu quảng cáo trên mỗi lượt xem
    • Nhiều hơn quảng cáo và ít hơn Patreon
      Vì tính theo thời lượng xem chứ không phải lượt hiển thị quảng cáo, các creator làm nội dung dài sẽ có lợi hơn
  • Tài khoản YouTube của bạn gái tôi kỳ lạ là đăng nhập trên thiết bị nào cũng không có quảng cáo. Kể cả Apple TV, không phải Premium và cũng chưa từng là Premium
    Tôi tò mò không biết nội bộ có flag nào được đặt khiến quảng cáo bị tắt không

    • Gửi DM tên người dùng và email của tài khoản cho tôi, tôi có thể kiểm tra và sửa giúp
    • Có vẻ bạn gái bạn thực tế nằm trong nhóm đối chứng của quảng cáo. Nó có thể được dùng để so sánh với hành vi của những người xem quảng cáo nhằm hiểu quảng cáo ảnh hưởng đến người dùng như thế nào
    • Cũng có thể cô ấy nằm trong một thử nghiệm giữ lại (holdback experiment). Người ta thường đưa một số người dùng vào nhóm giữ lại để xem các tính năng như chạy quảng cáo ảnh hưởng ra sao đến chỉ số, và khi làm ở Google tôi cũng từng làm những thử nghiệm như vậy
    • Trước đây nếu có gói đăng ký Google Music thì quảng cáo YouTube sẽ bị tắt. Ngay cả sau khi dịch vụ ngừng hoặc hủy đăng ký, hơn 6 tháng sau quảng cáo YouTube vẫn không quay lại
      Đến lúc đó tôi mới có khoảnh khắc hiểu ra vì sao mọi người phàn nàn
    • Tôi đang có trải nghiệm tương tự trên Twitch
      Dù không dùng trình chặn quảng cáo, chỉ cần đăng nhập là tôi không thấy quảng cáo ở cả website lẫn ứng dụng di động. Tôi không có Twitch Turbo và cũng không còn Amazon Prime. Tôi cũng không có các quyền lợi Turbo khác, nên không phải tài khoản bị gắn hoàn toàn là Turbo
      Không rõ có phải do hồi trước làm bug bounty, tôi nghịch đủ thứ rồi vô tình làm hỏng hồ sơ tài khoản hay không, nhưng nếu họ để tôi giữ quyền lợi này thì tôi cũng có thể cung cấp thêm thông tin chi tiết
      Điều lạ là tôi nhớ hồi trước ở bệnh viện, đang phê thuốc và đau đớn chỉ muốn xem TV, nhưng quảng cáo Twitch quá kinh khủng khiến tôi gần như suy sụp. Rồi 1–2 năm sau, chợt nhận ra mình đã không thấy quảng cáo suốt nhiều năm
      Có lẽ đang tồn tại một A/B test không quảng cáo đã bị lãng quên từ lâu, và không đáng công dọn dẹp nên vẫn còn. Nhờ vậy tôi đã hưởng lợi nhiều năm và xem Twitch nhiều hơn bất kỳ nền tảng nào khác. Twitch Turbo ở Anh là £12/tháng, khoảng $15,50, thuộc loại đắt trên toàn cầu, và so với mức $12/€12 ở Mỹ và châu Âu thì là một mức giá khá thiệt
  • Việc có thể giải mã lưu lượng HTTPS bằng cách đặt một proxy trung gian giữa Apple TV và Internet bên ngoài khá đáng ngạc nhiên
    Tôi cứ nghĩ bình thường nó không nên hoạt động, rồi sau đó lại ngạc nhiên theo một cách khác khi biết có thể thêm CA vào kho chứng chỉ của Apple TV. Đây là một bài viết rất chặt chẽ, lướt qua toàn bộ stack

    • Nếu đoán lý do Apple hỗ trợ thêm chứng chỉ, rất có thể là để phù hợp với yêu cầu IT và quản lý thiết bị trong môi trường doanh nghiệp hoặc giáo dục, nơi Apple TV được dùng như một hộp AirPlay
      Ví dụ ở trường đại học, để kết nối thiết bị vào Wi-Fi thì phải đưa địa chỉ MAC vào danh sách cho phép hoặc cài chứng chỉ
    • Google có thể dễ dàng chặn cách này chỉ bằng cách kiểm tra CA đã ký chứng chỉ SSL trong ứng dụng YouTube
      Tuy nhiên nếu làm vậy, YouTube có thể bị hỏng trong nhiều môi trường doanh nghiệp nên không rõ họ có thực sự làm không. Dù vậy, đáng tiếc là việc chặn rất dễ
    • Tôi không ngờ có thể thêm CA vào Apple TV. Có lẽ vì tôi chưa từng thử truy cập bằng Apple TV vào tài nguyên không có chuỗi chứng chỉ hợp lệ nên không biết
    • Hầu hết thiết bị đều cho phép thêm CA, nhưng ngày nay gần như mọi ứng dụng đều dùng certificate pinning nên bỏ qua kho chứng chỉ hệ thống. Việc YouTube không làm vậy thật sự rất đáng ngạc nhiên
    • Trớ trêu là Android TV, ít nhất ở bản 7.x, không cho phép việc này. Tôi đã vất vả phát hiện ra khi cố vượt qua một chứng chỉ Let's Encrypt không được tin cậy
  • Tôi đã thử triển khai vài lần trên Apple TV nhưng hoàn toàn không thành công. Có vẻ YouTube giờ đã đưa certificate pinning vào ứng dụng hoặc gì đó tương tự. Tôi tò mò không biết gần đây có ai làm cho cách này chạy được không

    • Nếu sẵn sàng bỏ thời gian, có thể đào sâu Frida [0]. Chứng chỉ bị pin cũng không thành vấn đề
      [0] https://frida.re/docs/home/
  • Tôi thích mọi nỗ lực chặn trên toàn mạng các dịch vụ online tệ hại mà ta bị ép phải dùng
    Chặn quảng cáo cũng tốt, nhưng tôi ước có cách dễ hơn và nhiều hơn để chặn trên toàn mạng các dạng cuộn vô hạn hung hãn như YouTube Shorts hay Instagram Reels
    Trên Instagram, tôi chỉ muốn xem bài đăng và story của những người mình theo dõi, chứ không muốn bị gợi ý mấy video ngớ ngẩn được thiết kế để cướp sự chú ý. Có thể điều này cho thấy tôi thiếu ý chí, nhưng tôi thường xuyên xem vài cái rồi mất 15 phút cuộc đời

    • Không ai ép dùng cả. Bạn có thể không dùng, hoặc có thể trả tiền
      Người dùng Internet nhìn chung đã chọn hướng không muốn trả tiền, nên sẽ có ai đó phải gánh chi phí. Nhìn tổng thể, người dùng Internet không thưởng cho phía không hiển thị quảng cáo. Họ muốn nội dung, nhưng đa phần muốn miễn phí
    • Chỉ cần xóa ứng dụng, dùng trang web và dùng trình duyệt cho phép user script
      Tôi tìm thấy một script biến trang Instagram gần như thành các thẻ ảnh, để chỉ xem ảnh: https://greasyfork.org/en/scripts/5014-un-instagram
    • Tôi cho rằng các chiến thuật này khai thác sự tò mò tự nhiên của chúng ta và tính thẩm mỹ xung quanh nó
      Vì vậy có vẻ không hẳn là thiếu ý chí, mà giống sự chai lì mà chúng ta đã tích lũy hơn, và điều đó khá tệ. Nỗ lực và sự sáng tạo nhằm đưa mọi thứ trở lại trạng thái chúng ta dùng nền tảng, thay vì nền tảng bắt chúng ta dùng nó, là đáng tôn trọng
    • Ở góc độ phụ huynh, tôi đặc biệt đồng cảm. Rất khó khi nhìn con cái bị cuốn vào thuật toán
      Tôi thường xuyên nói chuyện với bọn trẻ, chúng cũng đồng ý rằng điều đó có hại nhưng lại quá khó để chống lại. Ngay cả tôi đôi khi cũng bị kéo vào doomscrolling
      Ở những nơi có thể, tôi đã thiết lập lọc quảng cáo bằng Pi-hole, nhưng không muốn chặn toàn bộ YouTube. Dù vậy, để bảo vệ gia đình, có lẽ về sau tôi sẽ phải nghiêm túc cân nhắc
    • Ứng dụng này rất phù hợp để chặn cuộn vô hạn của Instagram: https://www.distractionfreeapps.com/index.html
  • Phần kỹ thuật thì hay, nhưng hơi buồn khi phải đi xa đến mức này chỉ để có cảm giác mình sở hữu phần nào phần cứng hay phần mềm của chính mình

    • Trong trường hợp này thì bạn sở hữu thiết bị. Chỉ là có vẻ không có cơ sở để nói rằng bạn cũng sở hữu YouTube hay nội dung của nó
    • Việc này đã khả thi gần 10 năm nay bằng cách cài NewPipe APK lên một Android box 30 đô la
  • YouTube có quảng cáo à? Trình duyệt chặn tốt quá nên tôi không biết
    Vấn đề thật sự là trải nghiệm Apple TV tệ hơn nhiều so với trải nghiệm trình duyệt web thông thường. Apple khóa phần cứng quá chặt, khiến cấu trúc này có lợi cho doanh thu quảng cáo của YouTube hơn là cho người tiêu dùng cuối đã bỏ tiền mua thiết bị

    • Trên Linux, Windows, Android tôi hoàn toàn không thấy quảng cáo. Thỉnh thoảng khi thử xem YouTube trên iPad, tôi lại ngạc nhiên vì quảng cáo xuất hiện dày và khó chịu đến mức nào
      Khi dùng iPad lướt web bên ngoài mạng Pi-hole ở nhà cũng vậy. Tôi không hiểu mọi người chịu đựng chuyện này hằng ngày như thế nào
      iPad là thiết bị công ty cấp nên tôi không dùng cho mục đích cá nhân thường xuyên, nhưng mỗi lần dùng lại được nhắc nhớ nó khó chịu đến mức nào
      Kỳ lạ là trước khi nhận iPad, tôi cứ nghĩ nó chỉ hữu ích để tiêu thụ nội dung, nhưng thực tế nó rất tiện để truy cập nhanh từ xa vào tài nguyên công việc, còn với duyệt web thông thường và streaming media thì nó lại là một thiết bị bị kẹt trong vùng đất hoang phủ đầy quảng cáo
  • Nếu cần YouTube không quảng cáo, có thể dùng https://yewtu.be hoặc một instance Invidious khác https://docs.invidious.io/instances/
    Giữa YouTube và Invidious có một cuộc chạy đua vũ trang, và đôi khi Invidious không hoạt động, nhưng đội ngũ luôn tìm được cách mới để vượt qua YouTube và truyền video không quảng cáo

    • Có lý do tiêu đề có cụm “on AppleTV”. Client hoặc frontend thay thế không chạy được ở đó
    • Ở những nơi như Roku TV thì không có trình duyệt, nên cách này không dùng được