2 điểm bởi GN⁺ 2023-08-28 | 2 bình luận | Chia sẻ qua WhatsApp
  • Để chặn quảng cáo YouTube trên Apple TV và iPhone ở cấp mạng, tác giả đã thử nghiệm qua pfSense, chặn DNS, định tuyến VPN, Squid, MITMProxy, rồi đến chỉnh sửa phản hồi Protobuf
  • Quảng cáo YouTube được phân phối từ cùng tên miền với video thông thường, nên chỉ dùng chặn DNS như Pi-hole hay pfBlockerNG thì khó tách nội dung và quảng cáo một cách ổn định
  • Sau khi giải mã lưu lượng TLS bằng MITMProxy, tác giả loại bỏ các trường quảng cáo JSON của YouTube web; với ứng dụng iOS, tác giả trực tiếp tìm và sửa cấu trúc quảng cáo bên trong phản hồi application/x-protobuf
  • Việc giải mã Protobuf toàn phần bằng Python mất khoảng 23 giây trên router pfSense, nhưng bằng cách quét tuyến tính quanh /pagead/, payload 1,8MiB cũng có thể được xử lý thời gian thực
  • Cách này cần cài CA tin cậy và CPU đủ mạnh; có thể chặn quảng cáo trên các thiết bị Apple kết nối vào mạng, nhưng về sau tác giả cũng cân nhắc trả phí YouTube Premium

Router pfSense và tách mạng

  • Mục tiêu là tạo một router dựa trên FreeBSD·pfSense để chặn quảng cáo YouTube pre-roll, mid-roll, end-roll trên toàn mạng cho Apple TV và iPhone
  • Phần cứng sử dụng gồm mini PC J4125 có tập lệnh AES-NI, RAM DDR4, SSD mSATA và USB drive để cài pfSense
    • Cấu hình ví dụ là 32GiB RAM và SSD mSATA 128GB
    • Dung lượng lưu trữ 128GB được xem là hữu ích cho log, giảm hao mòn SSD, bắt gói tin và không gian edge cache
  • Sau khi cài pfSense, LAN 1 được đặt thành IP tĩnh 192.168.1.3 nằm ngoài dải DHCP hiện có, rồi truy cập cổng quản trị web bằng tài khoản admin/pfsense
  • Sau khi xác nhận trên dashboard pfSense có hiển thị AES-NI CPU Crypto: Yes (inactive), tác giả bật thủ công AES-NI trong System › Advanced › Miscellaneous
  • Tận dụng 32GiB RAM, tác giả cấp phát RAM disk rộng rãi cho /var/tmp, đồng thời thiết lập sao lưu RAM-disk mỗi giờ

Chặn DNS và tách mạng vật lý

  • Thay cho Pi-hole hiện có, tác giả cài gói pfSense pfBlockerNG-devel để cấu hình chặn quảng cáo, nội dung độc hại và chặn theo địa lý
    • Dung lượng cài đặt tăng thêm khoảng 20MiB
    • Nếu dịch vụ pfb_dnsbl không khởi động hoặc thấy [ Missing CRON task ], tác giả khuyên thử xóa tệp rỗng /var/run/booting
  • 3 cổng Gigabit của router pfSense được dùng để tách LAN vật lý thay vì VLAN
    • Các thiết bị thường xuyên “gọi về nhà” như Alexa và Apple TV được đặt trong LAN phần cứng riêng
    • Tác giả muốn tách LAN quan trọng khỏi thiết bị thông minh và thiết bị Wi‑Fi để bảo vệ các thiết bị dùng cho ngân hàng, giao dịch chứng khoán và crypto wallet
  • Mạng dành cho thiết bị thông minh được tách thành 172.31.1.0/24, còn LAN đáng tin cậy hơn được giữ trong 192.168/16
    • Khi không có route giữa các mạng, ảnh hưởng của các quy tắc iptables cấu hình sai cũng được cho là giảm phần nào
    • Cần bật DHCP resolver trên NIC vật lý để thiết bị trong mạng mới có thể nhận địa chỉ
  • AC1200 Archer C5 bị loại bỏ vì không có AP mode, vấn đề truy cập từ xa, stock firmware cũ và chipset Broadcom ít được OpenWRT/DD-WRT/Tomato hỗ trợ
  • Sau đó, tác giả dùng Nighthawk R7000 làm AP cho Apple/Amazon/TV và AP cho Trusted Wireless Network
    • Trong Trusted Wireless Network, tác giả quyết định tắt 2,4GHz và chỉ dùng 5GHz
    • 5GHz được cho là dễ bị tường và bê tông chặn hơn, có lợi cho việc tránh snooping ở khoảng cách trung bình

Ép toàn bộ DNS đi qua pfSense

  • Tác giả thêm quy tắc NAT để mọi client phía sau pfSense dùng máy chủ Unbound DNS cục bộ
    • Mục đích là ngăn ứng dụng và home assistant né tránh bằng máy chủ DNS riêng hoặc DNS hard-code
    • Để pfBlockerNG can thiệp vào yêu cầu DNS, cần chặn DNS over TLS
  • Ban đầu quy tắc NAT được tạo trên từng interface trừ WAN, sau đó được đơn giản hóa bằng firewall alias Non_WAN
    • Trên cả IPv4 và IPv6, các truy vấn DNS cục bộ ở cổng 53 được chuyển hướng về localhost
    • Cần tắt NAT reflection để từ Internet bên ngoài không thể truy cập máy chủ DNS cục bộ
  • Trong Services › DNS Resolver › Display Custom Options, tác giả thêm server: log-queries: yes để ghi log các yêu cầu DNS bị chặn bắt
  • Trong log DNS, Windows được thấy đang cố truy cập Google Tag Manager, và yêu cầu đó bị blackhole về IP không tồn tại 10.10.10.1

Thử né nhắm mục tiêu quảng cáo YouTube bằng VPN

  • Vì quảng cáo YouTube đến từ cùng tên miền với video thông thường, rất khó dùng trình chặn theo tên miền như pfBlockerNG hay Pi-hole để chỉ lọc riêng quảng cáo
    • Việc chặn googleadservices.com được xem là chỉ có ý nghĩa sau khi đã xem video quảng cáo rồi bấm vào quảng cáo
    • Trên trình duyệt, uBlock Origin có thể can thiệp vào JavaScript, nhưng với ứng dụng YouTube trên iPhone thì khó hạn chế quảng cáo nếu không jailbreak
  • Thay vì chặn trực tiếp quảng cáo, tác giả thử khiến thuật toán quảng cáo YouTube xem người dùng là mục tiêu quảng cáo kém hấp dẫn hơn
    • Ý tưởng là đưa lưu lượng Apple TV qua VPN và dùng điểm cuối VPN ở khu vực có ít người xem YouTube
    • Mục tiêu là làm người dùng trông như một nam giới 70 tuổi sống ở Italy
  • Tác giả cấu hình WireGuard trên pfSense và lấy private key NordLynx/WireGuard từ Linux VM để thiết lập
    • Khi nhập địa chỉ tunnel là 1.0.0.0 và subnet mask 0, kết quả UI sẽ hiển thị là 0.0.0.0/0
  • Khi đưa toàn bộ lưu lượng Apple TV qua VPN, YouTube hiển thị bằng tiếng Ý và số lượng quảng cáo giảm, nhưng Netflix và Amazon Prime gặp vấn đề
    • Có vẻ như CSS hoặc file font bị chặn và thumbnail không tải được
    • Tác giả cảnh báo rằng Netflix và Prime thực hiện geofencing rất tốt với các nhà cung cấp VPN
  • Sau đó, tác giả cố định tuyến chỉ các FQDN liên quan đến YouTube qua VPN, với các ứng viên như www.youtube.com, youtube.com, googlevideo.com, accounts.google.com, googleapis.com, gstatic.com
    • Sau khi cấu hình, YouTube xem người dùng ở Milan, còn Netflix và Prime Video xem người dùng ở Canada
    • Quảng cáo trở nên hiếm hơn, và quảng cáo xuất hiện cũng là quảng cáo tiếng Ý

Vấn đề DNS race condition và tên miền wildcard

  • Sau một ngày, phát hiện DNS race condition khi alias hostname của pfSense và bộ nhớ đệm DNS của client nhìn thấy các tập hợp IP YouTube khác nhau
    • Resolve interval mặc định của alias hostname trong pfSense là 300 giây
    • TTL DNS của YouTube được quan sát là 1.440 giây
  • Nếu IP mà Alias Daemon resolve từ FQDN không khớp với IP mà Apple TV nhận được sau đó, lưu lượng có thể không đi qua đường hầm VPN
    • Cách giảm thiểu là để pfSense bỏ qua TTL của đích và cache alias entry lâu hơn
  • Các subdomain biến thể của googlevideo.com cần định tuyến wildcard, nhưng NAT và firewall rule hoạt động dựa trên IP và không thể xử lý trực tiếp wildcard hostname
  • Đã viết một PoC dùng Unbound Python module và pfSense REST API để bắt các IP trong phản hồi DNS rồi thêm động vào alias VPN_wildcards
    • TTL của VPN_wildcards được đặt là 1 giờ, capacity là 500
    • Bản ghi A được parse bằng ipaddress.IPv4Address, bản ghi AAAA bằng ipaddress.IPv6Address
  • Kiểm tra vào buổi sáng cho thấy Unbound DNS Resolver đã bị segfault, và mỗi lần thêm IP đều cần pfSense rule reload nên pfSense trở nên rất chậm

Giải mã HTTPS bằng Squid và MITMProxy

  • Mục tiêu mới là cài một proxy tương tự Squid và thêm fake-but-trusted CA certificate vào thiết bị để thực hiện giải mã lưu lượng TLS
  • Squid được cài dưới dạng package của pfSense và đã thành công đến bước smoke test SSL Filtering, nhưng sau đó bị bỏ
    • Hiệu năng rất chậm
    • Thiết lập ACL phiền phức
    • Có issue liên quan đến https://http/*
    • Việc update SquidGuard URL filter list mất rất lâu
    • Giao diện Squid bị đánh giá là thiếu sót
  • Sau đó chọn MITMProxy
    • Có Python scripting và UI, và được cho là có thể mở rộng phù hợp với chặn quảng cáo YouTube
    • Linux tarball của mitmproxy 7.0.4 không chạy được trên FreeBSD do lỗi ELF interpreter /lib64/ld-linux-x86-64.so.2 not found và thiếu thư viện
  • Cài trong môi trường FreeBSD jail của pfSense bằng pkg install mitmproxy
    • Số package cần cài là 50, dung lượng bổ sung 206MiB, dung lượng tải xuống 33MiB
    • Khi chạy mitmproxy bên trong jail, UI mở ra
  • Để thử nghiệm MITMProxy, gắn virtual IP 127.0.1.1 vào localhost trên pfSense, rồi dùng NAT rule chuyển [Private IPs]:8080 đến 127.0.1.1:8080
    • Khi đặt proxy của laptop làm vật thử nghiệm thành 192.168.20.1:8080, các request trình duyệt xuất hiện trong log UI của MITMProxy
  • File MITMProxy CA PEM là ~/.mitmproxy/mitmproxy-ca-cert.pem
    • Cung cấp cert.pem bằng web server Python 3
    • MITMProxy cũng cung cấp cùng CA certificate tại mitm.it
    • Đã thêm certificate vào một laptop sạch và iPhone

Vận hành MITMProxy và đối phó certificate pinning

  • Trên router, mitmproxy dùng nhiều CPU ngay cả khi idle; nguyên nhân được cho là việc tạo TLS certificate tức thời cho từng request và UI ghi log quá mức
  • mitmdump được cho là giảm tải CPU vì bỏ qua UI và logging cực đoan
    • Khi chạy, sử dụng các tùy chọn như --anticomp, --mode regular, --listen-port 8080, --listen-host 127.0.1.1
  • Certificate Pinning là kỹ thuật trong đó server hoặc client biết trước fingerprint của certificate mong đợi, khiến việc giả mạo certificate của MITMProxy không hiệu quả
    • Cách vượt qua là dùng --ignore-hosts để các host như apple.com:443, icloud.com:443 đi vòng qua proxy
  • Trong Transparent Proxy Mode, đã patch next_layer.py của MITMProxy 7.0.4 để --allowed-hosts hoạt động tốt hơn dựa trên SNI
    • Trước đó, trong nhiều trường hợp chỉ IP server được dùng để matching
    • Bản patch thêm cả server.sni vào danh sách hostname candidate, không chỉ server.address[0]
  • Sau khi patch, một số host có thể được chặn bắt ổn định, còn phần còn lại có thể cho đi qua

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

  • Trong smoke test MITMProxy, chặn các URL quảng cáo/theo dõi của YouTube bằng một script nhỏ
    • Trên youtube.com, chặn /pagead/, /log_event?, /stats/ads, /stats/qoe?, /ptracking?, /generate_204, el=adunit, adformat=, /activeview?, v.v.
    • Với google.comgoogle.ca, chặn /pagead/
  • Trong thử nghiệm ban đầu, các request thuộc diện chặn cũng thực sự bị chặn trong DevTools Network panel
    • Các mục (failed) phát sinh từ script
    • Lỗi 502 được cho là kết quả của việc pfBlockerNG black-hole request
    • HTTP/2 được vô hiệu hóa để các request tiếp theo trên cùng kênh không đi qua
  • Chỉ chặn URL đơn giản không làm quảng cáo biến mất hoàn toàn; khi xem HTML/JavaScript của YouTube và bộ lọc uBlock Origin, đã lần theo khả năng thông tin quảng cáo nằm trong thân phản hồi JSON
  • Trong phản hồi JSON mà MITMProxy bắt được, xác nhận có thông tin quảng cáo/theo dõi trong cấu trúc playerAdsplaybackTracking
    • playerAds chứa playerLegacyDesktopWatchAdsRenderer, playerAdParams, gutParams.tag, showCompanion, showInstream, useGut, v.v.
    • playbackTracking chứa videostatsPlaybackUrl, ptrackingUrl, qoeUrl, atrUrl, v.v.
    • youtubeRemarketingUrl có dạng www.youtube.com/pagead/viewthroughconversion/...
  • Trên web YouTube, có thể loại bỏ thông tin quảng cáo khỏi JSON payload để xóa quảng cáo web thông qua router

Phân tích iOS YouTube và Protobuf

  • Ứng dụng iOS YouTube sử dụng dữ liệu dạng Protocol Buffer (Protobuf) thay vì JSON trong các lệnh gọi API tương tự phiên bản web
    • Trong Protobuf, khóa là số và có thể thay đổi, nên khó tìm các phần quảng cáo theo kiểu JSONPath
    • Trong payload thấy các chuỗi quảng cáo như “Telus”, “Samsung TV”, “Boxing Week”, “Buy now”
  • Lưu lượng mạng của iOS YouTube khác với lưu lượng web
    • Ở phiên bản web, có thể phần nào suy đoán ứng viên quảng cáo bằng tham số range hoặc clen của chunk video
    • Giao thức iOS không dùng tham số truy vấn range hay header Range, mà dùng các bộ đếm như &nr=2, &nr=3
  • Khi giải mã phản hồi Protobuf để phân tích offline, phát hiện các mục như has_unlimited_entitlement: False, has_premium_lite_entitlement: False
    • Cách thay đổi các giá trị này có cảm giác như “gian lận”, nên quay lại hướng tiếp cận heuristic
  • Thử nghiệm chặn URL quảng cáo gây ra vòng lặp vô hạn, lỗi UI và crash trên ứng dụng iOS
    • 200 với body rỗng, 404, 503, response body bị cắt, xử lý null một phần video quảng cáo làm ứng dụng chậm lại hoặc crash trong trạng thái hỏng
    • Endpoint báo lỗi /error_204/ cho thấy “dev assertion failed” và bị chặn
  • Có vẻ quảng cáo được đăng ký vào một slot trong một video cụ thể
    • Các loại slot gồm pre-roll, mid-roll, end-roll, full-page, ad pod
    • Nếu chỉ chặn URL quảng cáo, sẽ phát sinh lỗi kiểu “một quảng cáo không tồn tại đã đặt trước slot”, khiến UI rơi vào trạng thái panic

Vấn đề hiệu năng Protobuf và blackboxprotobuf

  • Chỉ dùng Python để giải mã khoảng 500KiB Protobuf thô thành văn bản con người đọc được là rất chậm
    • Trên desktop CPU i7-6700 mất khoảng 2,06~2,11 giây
    • Trên router pfSense mất khoảng 22,8~24,2 giây
  • C++ protoc --decode_raw nhanh hơn nhiều
    • Trên desktop CPU i7-6700 mất khoảng 0,017~0,022 giây
    • Trên router pfSense ở mức khoảng 0,12~0,14 giây
  • Vì Python không hỗ trợ raw decoding, tác giả chọn cách giao tiếp trực tiếp với binary C++ protoc qua subprocess.Popen
  • blackboxprotobuf dành cho Burp Suite có thể decode raw Protobuf wire message, chèn giá trị rồi re-encode
    • Khuyến nghị dùng bản Burp Suite gốc, không phải fork trên PyPI
    • Một số fork có thể gây stack overflow do deep recursion
    • Nếu đặt os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp" trước khi import protobuf, khi có thể sẽ dùng triển khai C++ libprotobuf.so
  • protobuf_to_json(data) của blackboxprotobuf có thể tạo schema .proto theo best-guess, nhưng kết quả rất lớn, lồng nhau sâu và không hoàn hảo
    • Python schema dump dài khoảng hơn 250.000 ký tự
    • Được cho là đủ để trích xuất chi tiết quảng cáo

Vô hiệu hóa phần quảng cáo bằng thay đổi 1 byte

  • Với Protobuf Wire Format, nếu decode/edit/re-encode mà không có schema gốc, encoding có thể thay đổi
    • Nguyên nhân được cho là việc có dùng ZigZag encoding hay không, không thể phân biệt kiểu số, và tính không xác định trong thứ tự object field
  • Giải pháp là tận dụng backward compatibility của Protobuf để biến section quảng cáo thành field không xác định
    • Tận dụng hành vi phần mềm cũ bỏ qua field không xác định khi đọc field mới
    • Nếu đổi 1 byte ở điểm trọng yếu để làm cho section lồng sâu trông như thuộc về future schema version, Protobuf sẽ bỏ qua nó
  • Field key mục tiêu 49399797 phải được tìm bằng varint tag scanning, không phải tìm kiếm chuỗi đơn giản
    • Wire type là 2, nghĩa là nested string/message dạng length-delimited
    • Target tag được tính là AA FF B8 BC 01
    • Khi shift out 3 bit wire type, field key 49399797 được khôi phục
  • Việc tìm kiếm thực tế bắt đầu bằng cách tìm signature URL quảng cáo như /pagead/ trong raw Protobuf bytes, rồi đi lùi quanh đó để tìm target field tag và field key
    • Ví dụ đối tượng intercept là POST youtubei.googleapis.com:443/youtubei/v1/browse?key=...
    • Phản hồi là 200, application/x-protobuf, 1.87m
    • Trong log ví dụ, 49399797 được tìm thấy ở position 4465, 50195462 ở position 4477
  • Trong smoke test O(n), việc quét một lần 1,8MiB dữ liệu Protobuf mà không cần bộ nhớ bổ sung đã loại bỏ quảng cáo thành công
    • Target được tìm thấy tại byte thứ 30.593
    • Tìm được field key cần làm biến dạng bằng cách backtracking khoảng 600 byte
    • Không còn cần chặn URL chứa *.googleadservices.com hay /pagead/, và request tương ứng ngay từ đầu không được tạo ra

Cấu trúc addon MITMProxy

  • Script PoC được lưu dưới tên youtube.py và chạy bằng mitmdump --listen-port 8080 --listen-host 127.0.0.1 -s "youtube.py"
    • Các điều kiện tiên quyết trên FreeBSD được nêu gồm pkg install protobuf, pkg install py38-pip, pip install jsonpath-ng
  • Script gồm các lớp Logger, trunc, KilledError, JSONPathReplacement, ProtobufDebugParser, YouTubeAdBlocker
  • Regex host mà YouTubeAdBlocker intercept là \.youtube\.com|google\.(com|ca)|googleapis\.com|googleadservices\.com|googlevideo\.com
    • Chuỗi tìm kiếm URL quảng cáo Protobuf là b"/pagead/"
    • Giới hạn tìm kiếm là 80_000
    • Tag field mục tiêu là 50195462
  • Rule chặn request kiểm tra chuỗi URL một phần theo từng host rồi kill flow
    • Với đích youtube.com, gồm pagead/, log_event?, stats/ads, stats/qoe?, ptracking?, generate_204, error_204, adformat=, activeview?, _ad_, ai?, sw.js, v.v.
    • Với sw.js có chú thích rằng sẽ từ chối service workers
  • Trong phản hồi JSON, áp dụng nhiều JSONPath replacement
    • $.responseContext.serviceTrackingParams[*].params[?(@.key == 'yt_ad')].value được đổi thành "0"
    • $..adPlacements được đổi thành []
    • $..adPlacementRenderer, $..adPlacementConfig, $..playerAdParams, $..gutParams được đổi thành {}
    • $..adVideoId được đổi thành chuỗi rỗng
    • $..showCompanion, $..showInstream, $..useGut được đổi thành False
  • Trong phản hồi Protobuf, khi content type chứa protobuf, body được chuyển thành bytearray và tìm /pagead/ trong 80.000 byte đầu
    • Tạo target tag bytes bằng TagBytes(self.target_field_tag, WIRETYPE_LENGTH_DELIMITED), rồi tạo bytes mới của target_field_tag - 1
    • Tìm ngược từ ngay trước vị trí /pagead/ để tìm target tag bytes
    • Nếu tìm thấy, ghi đè các byte đó bằng bytes mới và thay thế phần thân phản hồi bằng flow.response.set_content(bytes(body))
  • Theo chú thích, PoC này chặn được 90% quảng cáo
    • Các section khác cũng có field key khác, và có thể có nhiều ad section cần làm sai lệch

Phạm vi áp dụng và hạn chế

  • Kỹ thuật này được tóm tắt là một kỹ thuật highly specialized để chặn quảng cáo YouTube trên thiết bị Apple hoặc chặn tracker traffic như Instagram, WhatsApp, Facebook
  • Nhu cầu CPU để decrypt/re-encrypt HTTPS traffic được cho là vượt xa mức Raspberry Pi có thể đảm đương
  • Sau khi jailbreak Apple TV và thêm pfSense root certificate, pfSense gateway có thể giải mã traffic của Apple TV rồi kiểm tra hostname quảng cáo trong request header để chặn
    • Tuy nhiên, cách này vẫn không áp dụng cho quảng cáo trên iPhone; jailbreak iPhone khó hơn và banking app có thể phát hiện rồi không hoạt động
    • Bản thân việc jailbreak được đánh giá là quá cực đoan
  • Nếu có thể dùng fake trusted CA, có thể giải mã TLS packet thành plaintext và áp dụng URL blocking
    • Ví dụ URL bị chặn là các đường dẫn /pagead/viewthroughconversion/.../pagead/conversion/... của YouTube
  • Cuối cùng, thiết lập router phần cứng từ đầu, chia LAN thành vùng tin cậy và không tin cậy, thêm chặn quảng cáo DNS và proxy MITM trong suốt, rồi chặn quảng cáo YouTube với hiệu năng tốt trên các thiết bị Apple kết nối vào mạng

YouTube Premium và hỗ trợ nhà sáng tạo

  • Sau vài tháng chặn quảng cáo YouTube, tác giả muốn hỗ trợ nhà sáng tạo nội dung nên bắt đầu trả phí YouTube Premium
    • Kèm theo lưu ý “không phải cứ làm được là nên làm”
  • Giá YouTube Premium được nêu là từ CAD $9.99/mo lên $11.99/mo, khoảng $13.43/mo gồm thuế
  • Trong thử nghiệm xem quảng cáo, tác giả dùng một laptop sạch và chế độ duyệt riêng tư để xem YouTube ngắt quãng trong một ngày
    • Theo ghi nhận, số video đã xem là 10
    • Đã thấy 8 quảng cáo, trong đó chỉ có 2 quảng cáo có thể bỏ qua
  • Nếu giả định CPV là USD $0.15, chi phí quảng cáo trong một ngày là $1.20, ngoại suy một tháng là khoảng USD $36/mo
  • Trong một phép tính khác dùng số liệu Statista, năm 2019 các nhà quảng cáo Mỹ đã chi $15.1 billion cho YouTube và cư dân Mỹ đã xem 916 billion video, suy ra trung bình USD $0.0165 mỗi lượt xem
    • Áp dụng phép tính này thì chi phí một ngày là khoảng USD $0.13, ngoại suy một tháng là khoảng USD $3.96
    • Con số này được cho là không gần mức USD $10 của Premium
  • Nếu bị claim DMCA, doanh thu quảng cáo có thể đến tay bên khiếu nại như Sony hoặc Viacom thay vì nhà sáng tạo
    • Vì vậy, người xem có thể vô tình chẳng đóng góp gì cho kênh mình yêu thích
    • Tác giả đánh giá rằng việc nhiều nhà sáng tạo chuyển sang Patreon là điều không đáng ngạc nhiên

2 bình luận

 
xguru 2023-08-29

Bài gốc rất dài. Quy trình thì thú vị, nhưng điểm mấu chốt là cuối cùng chính tác giả cũng chỉ dùng YouTube Premium trả phí.

 
GN⁺ 2023-08-28
Các ý kiến trên Hacker News
  • Nhìn chung đây là một màn hack rất hay, nhưng một vài cách diễn đạt về Protobuf nghe hơi lạ
    Việc họ cố ý làm hỏng tag của một trường trong Protobuf; bỏ qua số tag không nhận ra không phải là “lỗi”, mà là thiết kế cốt lõi để hỗ trợ khả năng mở rộng
    1,87MiB cũng không phải kích thước quá lớn, và có lẽ những thông điệp kiểu này cũng không được stream liên tục, nên cách giải thích rằng đây là rào cản hiệu năng cũng không thật thuyết phục
    Mã hóa Protobuf không được thiết kế để làm chi phí giải mã trở nên đắt đỏ, mà ngược lại được thiết kế để giải mã hiệu quả; ngay cả khi không có schema .proto gốc, vẫn có thể tự giải mã bằng UnknownFieldSet
    Có lẽ cách tốt hơn là dùng một schema .proto giả chỉ chứa đúng trường muốn loại bỏ. Cách quét chuỗi dễ lỗi hơn, vì cùng một chuỗi byte có thể tình cờ xuất hiện trong dữ liệu khác
    Nếu thứ tự trường thay đổi, kết quả byte sau khi mã hóa lại có thể khác, nhưng bên nhận phải xử lý đó như cùng một thông điệp; khả năng ứng dụng YouTube phát hiện thay đổi thứ tự trường có vẻ thấp
    Nhìn từ góc độ từng làm việc với Protobuf trước đây, có vẻ tác giả đã hiểu nhầm phần này

    • Phân tích hay, nhưng mình hơi khó đồng ý với việc nói 1,87MB là nhỏ
      Mình đã sống phần lớn cuộc đời ở vùng nông thôn, và nếu không phải Wi-Fi của mình thì lượng tải xuống cỡ này thực tế vẫn là lớn. Trên di động có thể có cách vòng qua, nhưng Wi-Fi nông thôn đến nay vẫn chật vật với kiến trúc Web 2.0 và thường được dùng ở tốc độ 2~4G
      Ở các khu đô thị, nơi có dân số đủ để nâng đỡ hạ tầng, 1,87MB nhìn chung đã trở thành một tệp nhỏ, nhưng khoảng 6 giờ tối, khi những người dùng chung đường cáp đều đang stream, có thể là ngoại lệ
    • Nhân tiện quảng bá nhẹ về without the C++ source proto files: mình đã tạo một dự án tên protodump để sinh các tệp .proto nguồn từ binary
      Nó tái tạo định nghĩa message và field, gồm cả tên gốc; chỉ cần lấy binary từ hộp Apple TV là được
      https://github.com/arkadiyt/protodump
    • “Từng làm việc với Protobuf trước đây” là một cách nói giảm nói tránh cực kỳ khiêm tốn. Cho ai chưa biết thì Kenton là người đã biến Protobuf thành hình dạng như ngày nay
      Protobuf là công nghệ lần đầu giúp mình biết đến IDL, và lúc đó nó trông như một ý tưởng ma thuật. Mình còn ngạc nhiên hơn vì đã tự làm một IDL sơ sài rồi mới phát hiện ra Protobuf
    • Khi đọc bài này mình cũng thấy bối rối tương tự. Các nguyên tắc thiết kế của Protobuf đâu phải bí mật, tất cả đều được tài liệu hóa rõ ràng
    • Phần khó nhất khi giải mã Protobuf không có schema là message lồng bên trong và chuỗi dùng cùng kiểu tag, nhưng vẫn có thể xử lý khá dễ
      Nếu không muốn kéo toàn bộ phụ thuộc protoc vào, có thể tự viết một decoder Protobuf đơn giản chỉ vài trăm dòng: https://github.com/kubernetes/test-infra/blob/master/guberna... https://github.com/kubernetes/test-infra/blob/master/guberna...
  • Từ khi phát hiện ra The Proxomitron hơn 20 năm trước, mình đã xử lý lưu lượng qua proxy trung gian để loại bỏ quảng cáo và viết lại trang bằng những thứ như CSS của người dùng
    Những nơi như CloudFlare có xu hướng xếp mình vào dạng “bot”, nhưng chuyện đó cũng có cách vượt qua, dù không đơn giản. Những trường hợp như thế này cũng cho thấy vì sao chứng thực từ xa nguy hiểm với tự do của người dùng

    • Mình tìm thử The Proxomitron thì có vẻ việc phát triển đã kết thúc vào năm 2004; nếu có bản tóm tắt nào nắm rõ tình hình hiện tại thì chắc sẽ thú vị
      Có vẻ có nhiều dự án “kế thừa”, và mình cũng tò mò liệu nó có chỉ dành cho Windows không. Mình đang tìm nhẹ một proxy đơn giản có thể chèn liên kết cục bộ vào nội dung từ xa
    • Chặn quảng cáo ở cấp mạng như Privoxy hay pi-hole có quá nhiều nhược điểm, chẳng hạn không xử lý được quảng cáo inline
      Hiện mình cũng đã rút pi-hole từng chạy trên Pi 4 ra. Mình đã tốn vài giờ để cố làm cho nó hoạt động đúng với nhiều dịch vụ, nhưng cuối cùng bỏ cuộc; không đáng với thời gian bỏ vào mạng gia đình
      Thứ thực sự hoạt động tốt là các trình chặn quảng cáo trên trình duyệt và các app patcher như ReVanced. Khi tiền tiết kiệm tăng lên, với những trường hợp hai cách đó không giải quyết được như YouTube Premium, Hulu, Netflix, Max, mình ngày càng nghiêng về việc cứ trả tiền cho dịch vụ không quảng cáo
    • Được biết nhân viên Cloudflare có lẩn khuất đọc ở đây, nên mình tò mò: việc bị phân loại là bot kiểu này được xem là dương tính giả, hay là hoạt động đúng như chủ đích?
    • Gần 20 năm rồi mình hầu như không nghĩ đến Proxomitron, nên không biết nó còn được dùng không
      Mình chưa từng dùng nó cho mục đích nói ở đây, nhưng dùng làm proxy sau tường lửa công ty thì rất tuyệt. Ngày xưa tường lửa yêu cầu thông tin đăng nhập cho kết nối ra ngoài, nên nhiều chương trình không thể truy cập Internet
    • Có lẽ cách này phải cài một chứng chỉ CA mới lên thiết bị, đúng không?
  • Mình nghĩ ngay đến Privaxy được đóng gói bằng Docker. Đây là proxy trung gian tương thích với danh sách chặn của UBlock Origin.
    Nhìn vào lượng quảng cáo và script theo dõi trên các sản phẩm thông minh, đặc biệt là TV, thật sự đáng ngạc nhiên. Theo những gì tôi đã thử nghiệm đến nay, lưu lượng không cần thiết vượt quá 40%, và việc thử bóc quảng cáo khỏi các ứng dụng smart TV khá thú vị.
    https://github.com/deetungsten/webui-privaxy là một fork đã được Docker hóa của https://github.com/Barre/privaxy

    • Làm thế nào để TV tin cậy chứng chỉ tự ký?
    • Thấy nó xuất hiện ở đây cũng vui. Cảm ơn vì đã nêu vấn đề ping danh sách bộ lọc.
      Tôi từng định sửa fork để phần frontend không dùng địa chỉ 0.0.0.0 hardcode, nhằm có thể cô lập container Docker thật sự, nhưng rồi cuộc sống xen vào. Bạn đã thử trên Apple TV chưa?
    • AdGuard cũng đang làm một thứ tương tự.
      https://github.com/AdguardTeam/urlfilter
    • Tôi mất quá lâu mới hiểu rằng “fork đã Docker hóa” nghĩa là GUI đã được đổi thành web GUI
  • Bài viết này là một câu trả lời rất hay cho câu hỏi thường gặp: “Muốn trở thành hacker thì nên học như thế nào?”
    Nó cho thấy rõ quá trình tư duy và công việc bền bỉ đằng sau bất kỳ exploit nào.

  • Có đoạn “Dùng WireGuard — nó có tập lệnh mã hóa Intel AES-NI”, nhưng theo tôi biết thì WireGuard không dùng AES.
    Nhìn chung, có vẻ tác giả hơi đánh giá quá cao yêu cầu CPU của mã hóa TLS, hoặc đánh giá thấp hiệu năng của các máy tính bo mạch đơn hiện đại.
    Tôi cũng thấy khó hiểu khi nói rằng yêu cầu CPU để giải mã rồi mã hóa lại lưu lượng HTTPS trên Raspberry Pi bị vượt quá đáng kể. Nếu việc xử lý TLS kiểu trung gian trên RPi 4 thật sự là bất khả thi thì tôi sẽ khá ngạc nhiên, kể cả khi dùng RSA thuần phần mềm.
    Trong số các điện thoại Android vẫn còn được sử dụng, có những máy có CPU yếu hơn RPi 4, và chúng vẫn dùng TLS.

    • Có vẻ bạn đang đánh giá thấp yêu cầu CPU.
      Một điện thoại Android yếu nếu chỉ xử lý được lưu lượng TLS 50Mb/s thì trong thực tế có thể không phải vấn đề lớn, vì điện thoại chậm thường cũng kết nối với mạng chậm.
      Ngược lại, nếu nhà bạn có Internet gigabit mà lại bị nghẽn ở 50Mb/s vì một thiết bị yếu nằm giữa mọi máy tính và Internet, thì đó là vấn đề lớn.
      Yêu cầu CPU của TLS phụ thuộc rất nhiều vào băng thông mục tiêu. Ở băng thông cao hơn, việc offload sang bộ tăng tốc trên thực tế có thể trở thành bắt buộc. Chi phí handshake cũng khó bỏ qua và có thể giới hạn số kết nối mỗi giây. Với một thiết bị đơn lẻ thì hiếm khi là vấn đề, nhưng trên cả một mạng nhiều thiết bị thì có thể trở nên nghiêm trọng hơn.
  • Bài viết rất hay. Tôi đã kỳ vọng có cách xử lý trung gian các thiết bị không cho cài CA tùy chỉnh.
    Tôi có một thiết bị IoT không mở API cục bộ mà chỉ hiển thị dữ liệu qua cloud, và muốn bắt lưu lượng giữa thiết bị và cloud.
    Rốt cuộc có lẽ không còn cách nào ngoài dump bộ nhớ flash, thay CA rồi nạp lại sao?

    • Nếu chứng chỉ được “hardcode” thì đó được gọi là certificate pinning. Khi đó bạn phải thay thế hoặc gỡ bỏ chứng chỉ, rồi chuyển chính chứng chỉ đó sang proxy trung gian để giải mã được lưu lượng.
      Có một bài viết hay về cách thử chặn thiết bị IoT mà không cần động đến phần cứng hay firmware:
      https://robertheaton.com/2019/11/21/how-to-man-in-the-middle...
    • Tìm cách xử lý trung gian một thiết bị không cho cài CA tùy chỉnh rốt cuộc là đi ngược lại mục đích của TLS.
      Nếu làm được thì tức là đang dựa vào lỗi triển khai.
      Thành thật mà nói, tôi nghĩ ngay cả một số thiết bị hiện cho phép cài chứng chỉ tin cậy riêng cũng không còn lâu nữa đâu.
  • Các cách mới để chặn quảng cáo trên YouTube hay bất kỳ nền tảng nào luôn xuất hiện, nhưng vài tháng sau lại bị thay đổi và trở nên vô dụng.
    Thay vào đó, sao không tấn công nhà quảng cáo? Có vẻ YouTube/Google chỉ theo dõi “click”, nhưng họ có theo dõi đến cả giao dịch mua thực tế không?
    Về lý thuyết, nếu có đủ nhiều bot giả và người dùng thật bấm vào quảng cáo nhưng không mua gì, ta có thể đốt sạch ngân sách quảng cáo. Theo thời gian, bộ phận marketing sẽ thấy trên một nền tảng cụ thể số lượt click đạt mức kỷ lục nhưng tỷ lệ chuyển đổi so với click hoặc lượt hiển thị lại rất thấp, và cuối cùng có thể rút khỏi nền tảng đó.

    • Nhìn việc Nauseum từng bị chặn khỏi Chrome Store thì có vẻ nó khá hiệu quả.
  • Bài viết đáng kinh ngạc. Ngay khi thấy bước patch mitm, tôi đã nghĩ đây hẳn sẽ là một bài đặc biệt, và đúng là như vậy.

  • Tôi rất ấn tượng với mục trong phần mục lục: “Mục tiêu mới: khiến YouTube tin rằng tôi là một người đàn ông 70 tuổi sống ở Ý”.
    Trước đây không hiểu vì sao hệ thống nhắm mục tiêu quảng cáo từng tin rằng tôi là người đang định mua bộ đồ ngủ lụa giặt được giá 500 đô la cho người yêu.
    Bản thân quảng cáo thì tuyệt vời, nhưng tôi tò mò không biết họ đã trả bao nhiêu cho mỗi lượt hiển thị.
    Sau khi chuyển sang Apple TV, tôi chủ yếu thấy quảng cáo địa phương bị nhắm sai khu vực. Tính trung bình thì có lẽ như vậy còn tốt hơn.

  • Đây không phải là “lỗi” của Protobuf. Việc khi sửa byte thì nó được giải mã thành trường ở vị trí khác là hoạt động đúng như thiết kế
    Ngay từ đầu Protobuf là giao thức dựa trên số hiệu trường và tiền tố độ dài, giả định hợp lý rằng byte không bị thay đổi trong quá trình truyền, và giao việc đảm bảo tính toàn vẹn cho phía đọc
    Ngay cả nếu có gọi là lỗi thì đó sẽ là lỗi của ứng dụng YouTube cho iOS chứ không phải Protobuf; thực tế cũng không phải lỗi, nên khó gọi là “exploit”. Trừ khi đang nói đến việc trong trao đổi Protobuf của ứng dụng YouTube iOS không kiểm tra hash của payload trả về
    Sau bài viết này có lẽ họ sẽ kiểm tra

    • Cách diễn đạt của tác giả hơi lạ. “Lỗi” chỉ xuất hiện trong tiêu đề, còn phần thân chỉ giải thích định dạng hoạt động như thế nào
      Đây không phải là lỗi mà là hoạt động đúng theo thiết kế
      Phần nói rằng “Google khiến việc giải mã, sửa đổi, rồi mã hóa lại trở nên tốn kém về mặt tính toán nếu không có file proto nguồn C++” cũng lạ. Nếu làm bằng mã Python chưa tối ưu thì có thể tốn kém, nhưng nếu viết bằng C hoặc ngôn ngữ biên dịch khác thì việc quét Protobuf 1,8MB là chuyện nhỏ, dù có file proto nguồn hay không
      Có lẽ việc khiến file Protobuf khó giải mã khi không có source không phải là mục tiêu thiết kế. Nếu đó là mục tiêu thì họ đã làm khá tệ
    • Tôi không biết các trường bắt buộc trong Protobuf hoạt động thế nào, nhưng để giảm thiểu kiểu tấn công này, client YouTube của Google có thể coi trường đó là trường bắt buộc, và từ chối dịch vụ nếu trường không tồn tại hoặc có giá trị mặc định
    • Ngày của bài viết là tháng 1/2022. Nếu muốn gia cố giao thức sau bài blog thì nhiều khả năng họ đã làm rồi