2 คะแนน โดย GN⁺ 2023-08-28 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • ทดลองตั้งแต่ pfSense, การบล็อก DNS, การทำ VPN routing, Squid, MITMProxy ไปจนถึง การแก้ไข response ของ Protobuf เพื่อบล็อกโฆษณา YouTube บน Apple TV และ iPhone ในระดับเครือข่าย
  • โฆษณา YouTube ถูกส่งมาจากโดเมนเดียวกับวิดีโอปกติ จึงแยกคอนเทนต์กับโฆษณาอย่างเสถียรได้ยากด้วยแค่ การบล็อก DNS อย่าง Pi-hole หรือ pfBlockerNG
  • หลังถอดรหัส TLS traffic ด้วย MITMProxy แล้ว ลบฟิลด์โฆษณาใน JSON ของ YouTube บนเว็บ และในแอป iOS ก็ค้นหาและแก้ไขโครงสร้างโฆษณาภายใน response แบบ application/x-protobuf โดยตรง
  • การถอดรหัส Protobuf ทั้งหมดด้วย Python ใช้เวลาประมาณ 23 วินาทีบนเราเตอร์ pfSense แต่เมื่อใช้วิธี linear scan รอบ ๆ /pagead/ ก็ทำให้ payload ขนาด 1.8MiB ประมวลผลแบบเรียลไทม์ได้
  • วิธีนี้ต้องติดตั้ง CA ที่เชื่อถือได้และต้องมี CPU ที่แรงพอ และแม้จะบล็อกโฆษณาบนอุปกรณ์ Apple ที่เชื่อมต่อกับเครือข่ายได้ แต่ภายหลังก็ทำให้เริ่มพิจารณาจ่ายเงินสมัคร YouTube Premium

เราเตอร์ pfSense และการแยกเครือข่าย

  • เป้าหมายคือสร้างเราเตอร์ที่ใช้ FreeBSD และ pfSense เพื่อบล็อกโฆษณา YouTube แบบ pre-roll, mid-roll, end-roll บน Apple TV และ iPhone ทั่วทั้งเครือข่าย
  • ฮาร์ดแวร์ที่ใช้คือ mini PC รุ่น J4125 ที่มีชุดคำสั่ง AES-NI, RAM DDR4, SSD mSATA และไดรฟ์ USB สำหรับติดตั้ง pfSense
    • ตัวอย่างสเปกคือ RAM 32GiB และ SSD mSATA 128GB
    • มองว่าพื้นที่เก็บข้อมูล 128GB มีประโยชน์สำหรับ log, ลดการสึกหรอของ SSD, packet capture และพื้นที่ edge cache
  • หลังติดตั้ง pfSense ตั้งค่า LAN 1 เป็น IP แบบ static 192.168.1.3 ที่อยู่นอกช่วง DHCP เดิม และเข้าเว็บพอร์ทัลผู้ดูแลระบบด้วยบัญชี admin/pfsense
  • หลังตรวจดูข้อความ AES-NI CPU Crypto: Yes (inactive) บนแดชบอร์ด pfSense แล้ว จึงเปิดใช้ AES-NI เองที่ System › Advanced › Miscellaneous
  • ใช้ RAM 32GiB โดยจัดสรร RAM disk ให้ /var และ /tmp ไว้ค่อนข้างมาก และตั้งค่าให้สำรองข้อมูล RAM-disk ทุกชั่วโมง

การบล็อก DNS และการแยกเครือข่ายทางกายภาพ

  • แทนที่จะใช้ Pi-hole เดิม ได้ติดตั้ง pfBlockerNG-devel ซึ่งเป็นแพ็กเกจของ pfSense เพื่อบล็อกโฆษณาและคอนเทนต์อันตราย รวมถึงตั้งค่าการบล็อกตามภูมิภาค
    • พื้นที่ติดตั้งเพิ่มขึ้นประมาณ 20MiB
    • หาก service pfb_dnsbl ไม่เริ่มทำงาน หรือเห็นข้อความ [ Missing CRON task ] ให้ลองลบไฟล์เปล่า /var/run/booting
  • พอร์ต Gigabit 3 พอร์ตของเราเตอร์ pfSense ถูกใช้สำหรับ การแยก LAN ทางกายภาพ แทน VLAN
    • นำอุปกรณ์ที่มักโทรกลับบ้านอย่าง Alexa และ Apple TV ไปไว้ใน LAN ฮาร์ดแวร์แยกต่างหาก
    • ต้องการแยก LAN สำคัญออกจากอุปกรณ์ smart device และ Wi‑Fi เพื่อปกป้องอุปกรณ์ที่ใช้ทำธุรกรรมธนาคาร ซื้อขายหุ้น และใช้ crypto wallet
  • เครือข่ายสำหรับ smart device ถูกแยกเป็น 172.31.1.0/24 ส่วน LAN ที่เชื่อถือมากกว่ายังคงไว้ที่ 192.168/16
    • มองว่าหากไม่มี route ระหว่างเครือข่าย ก็ช่วยลดผลกระทบบางส่วนจากกฎ iptables ที่ตั้งค่าผิดได้
    • ต้องเปิดใช้ DHCP resolver บน NIC ทางกายภาพ เพื่อให้อุปกรณ์เครือข่ายใหม่ได้รับ address
  • AC1200 Archer C5 ถูกเลิกใช้เพราะไม่มี AP mode, มีปัญหา remote access, stock firmware เก่า และ chipset Broadcom รองรับ OpenWRT/DD-WRT/Tomato ได้ไม่ดี
  • หลังจากนั้นใช้ Nighthawk R7000 เป็น AP สำหรับ Apple/Amazon/TV และเป็น AP สำหรับ Trusted Wireless Network
    • ใน Trusted Wireless Network ตัดสินใจปิด 2.4GHz และใช้เฉพาะ 5GHz
    • มองว่า 5GHz ถูกผนังและคอนกรีตบังได้ง่ายกว่า จึงช่วยหลีกเลี่ยงการ snooping ระยะกลางได้ดีกว่า

บังคับให้ DNS ทั้งหมดไปที่ pfSense

  • เพิ่มกฎ NAT เพื่อให้ client ทั้งหมดหลัง pfSense ใช้เซิร์ฟเวอร์ Unbound DNS ในเครื่อง
    • จุดประสงค์คือไม่ให้แอปและ home assistant หลบเลี่ยงไปใช้ DNS server ของตัวเองหรือ DNS server ที่ hardcode ไว้
    • เพื่อให้ pfBlockerNG แทรกแซงคำขอ DNS ได้ ต้องบล็อก DNS over TLS
  • เดิมสร้างกฎ NAT ในแต่ละ interface ยกเว้น WAN ก่อนจะทำให้ง่ายขึ้นด้วย firewall alias ชื่อ Non_WAN
    • redirect local DNS query ที่พอร์ต 53 ไปยัง localhost ทั้ง IPv4 และ IPv6
    • ต้องปิด NAT reflection เพื่อไม่ให้อินเทอร์เน็ตภายนอกเข้าถึง local DNS server ได้
  • เพิ่ม server: log-queries: yes ใน Services › DNS Resolver › Display Custom Options เพื่อ log คำขอ DNS ที่ถูกดักไว้
  • ใน DNS log พบว่า Windows พยายามเข้าถึง Google Tag Manager และคำขอนั้นถูก blackhole ไปยัง IP ที่ไม่มีอยู่จริง 10.10.10.1

ทดลองเลี่ยงการกำหนดเป้าหมายโฆษณา YouTube ด้วย VPN

  • เพราะโฆษณา YouTube มาจากโดเมนเดียวกับวิดีโอปกติ จึงยากที่จะเลือกบล็อกเฉพาะโฆษณาด้วยตัวบล็อกโดเมนอย่าง pfBlockerNG หรือ Pi-hole
    • มองว่าการบล็อก googleadservices.com จะมีความหมายก็ต่อเมื่อดูวิดีโอโฆษณาแล้วคลิกโฆษณานั้นภายหลัง
    • บนเบราว์เซอร์ uBlock Origin แทรกแซง JavaScript ได้ แต่ในแอป YouTube บน iPhone มองว่าจำกัดโฆษณาได้ยากหากไม่ jailbreak
  • แทนที่จะบล็อกโฆษณาโดยตรง ได้ทดลองทำให้อัลกอริทึมโฆษณาของ YouTube มองผู้ใช้เป็นเป้าหมายโฆษณาที่ไม่น่าสนใจนัก
    • แนวคิดคือส่ง traffic ของ Apple TV ผ่าน VPN และใช้ VPN endpoint ในภูมิภาคที่มีผู้ชม YouTube น้อย
    • เป้าหมายคือทำให้ผู้ใช้ดูเหมือนผู้ชายอายุ 70 ปีที่อาศัยอยู่ในอิตาลี
  • ตั้งค่า WireGuard บน pfSense และนำ private key ของ NordLynx/WireGuard มาจาก Linux VM เพื่อตั้งค่า
    • ระบุว่าหากใส่ 1.0.0.0 และ subnet mask 0 ตอนป้อน tunnel address ผลลัพธ์ใน UI จะแสดงเป็น 0.0.0.0/0
  • เมื่อส่ง traffic ทั้งหมดของ Apple TV ผ่าน VPN YouTube แสดงเป็นภาษาอิตาลีและจำนวนโฆษณาลดลง แต่เกิดปัญหากับ Netflix และ Amazon Prime
    • ดูเหมือน CSS หรือไฟล์ font ถูกบล็อก และ thumbnail ไม่โหลด
    • เตือนว่า Netflix และ Prime ทำ geofencing กับผู้ให้บริการ VPN ได้ดี
  • หลังจากนั้นพยายาม route เฉพาะ FQDN ที่เกี่ยวกับ YouTube ผ่าน VPN โดยเลือก www.youtube.com, youtube.com, googlevideo.com, accounts.google.com, googleapis.com, gstatic.com เป็นต้นเป็น candidate
    • หลังตั้งค่า YouTube มองว่าผู้ใช้อยู่ใน Milan ส่วน Netflix และ Prime Video มองว่าอยู่ใน Canada
    • โฆษณาพบน้อยลง และเมื่อมีโฆษณาก็เป็นโฆษณาภาษาอิตาลี

ปัญหา DNS race condition และโดเมน wildcard

  • หลังจากผ่านไปหนึ่งวัน พบ DNS race condition ที่ pfSense hostname alias กับ DNS cache ของไคลเอนต์มองเห็นชุด IP ของ YouTube ต่างกัน
    • ค่า resolve interval เริ่มต้นของ pfSense hostname alias คือ 300 วินาที
    • สังเกตพบว่า YouTube DNS TTL อยู่ที่ 1,440 วินาที
  • หาก IP ที่ Alias Daemon resolve จาก FQDN ไม่ตรงกับ IP ที่ Apple TV ได้รับภายหลัง ทราฟฟิกอาจไม่ผ่านอุโมงค์ VPN
    • วิธีบรรเทาคือทำให้ pfSense เพิกเฉยต่อ TTL ของปลายทาง และ cache alias entry ไว้นานขึ้น
  • subdomain รูปแบบต่าง ๆ ของ googlevideo.com จำเป็นต้องใช้การ routing แบบ wildcard แต่ NAT และ firewall rule ทำงานบนพื้นฐานของ IP และไม่สามารถจัดการ wildcard hostname ได้โดยตรง
  • เขียน PoC โดยใช้ Unbound Python module และ pfSense REST API เพื่อดักจับ IP ใน DNS response แล้วเพิ่มเข้าไปใน alias VPN_wildcards แบบไดนามิก
    • ตั้งค่า TTL ของ VPN_wildcards เป็น 1 ชั่วโมง และ capacity เป็น 500
    • parse A record ด้วย ipaddress.IPv4Address และ AAAA record ด้วย ipaddress.IPv6Address
  • เมื่อตรวจสอบตอนเช้า พบว่า Unbound DNS Resolver อยู่ในสถานะ segfault และทุกครั้งที่เพิ่ม IP ต้อง reload rule ของ pfSense ทำให้ pfSense ช้ามาก

ถอดรหัส HTTPS ด้วย Squid และ MITMProxy

  • เป้าหมายใหม่คือการติดตั้ง proxy คล้าย Squid และเพิ่ม fake-but-trusted CA certificate ลงในอุปกรณ์ เพื่อทำ การถอดรหัสทราฟฟิก TLS
  • ติดตั้ง Squid เป็นแพ็กเกจของ pfSense และทำ SSL Filtering smoke test สำเร็จ แต่ก็เลิกใช้
    • ประสิทธิภาพช้ามาก
    • การตั้งค่า ACL ยุ่งยาก
    • มี issue เกี่ยวกับ https://http/*
    • การ update SquidGuard URL filter list ใช้เวลานานมาก
    • มองว่า Squid UI ยังไม่เพียงพอ
  • หลังจากนั้นเลือก MITMProxy
    • มองว่ามี Python scripting และ UI และสามารถขยายให้เหมาะกับการบล็อกโฆษณา YouTube ได้
    • mitmproxy 7.0.4 Linux tarball ไม่สามารถรันบน FreeBSD ได้ เนื่องจาก ELF interpreter /lib64/ld-linux-x86-64.so.2 not found และขาด library
  • ติดตั้งในสภาพแวดล้อม FreeBSD jail ของ pfSense ด้วย pkg install mitmproxy
    • แพ็กเกจเป้าหมายที่จะติดตั้งมี 50 รายการ ใช้พื้นที่เพิ่ม 206MiB และปริมาณดาวน์โหลด 33MiB
    • เมื่อรัน mitmproxy ภายใน jail จะเปิด UI ขึ้นมา
  • เพื่อทดลอง MITMProxy ได้ผูก virtual IP 127.0.1.1 เข้ากับ localhost ใน pfSense และใช้ NAT rule ส่งต่อ [Private IPs]:8080 ไปยัง 127.0.1.1:8080
    • เมื่อตั้งค่า proxy ของโน้ตบุ๊กที่ใช้เป็นเหยื่อเป็น 192.168.20.1:8080 คำขอจากเบราว์เซอร์ก็แสดงใน log ของ MITMProxy UI
  • ไฟล์ MITMProxy CA PEM คือ ~/.mitmproxy/mitmproxy-ca-cert.pem
    • ให้บริการ cert.pem ด้วยเว็บเซิร์ฟเวอร์ Python 3
    • MITMProxy ให้บริการ CA certificate เดียวกันผ่าน mitm.it ด้วย
    • เพิ่ม certificate ลงในโน้ตบุ๊กสะอาดและ iPhone

การใช้งาน MITMProxy และการรับมือ certificate pinning

  • บนเราเตอร์ mitmproxy ใช้ CPU สูงแม้ขณะว่าง โดยมองว่าสาเหตุมาจากงานสร้าง TLS certificate แบบทันทีต่อคำขอ และการ logging มากเกินไปของ UI
  • มองว่า mitmdump ลดภาระ CPU ได้ เพราะตัด UI และการ logging แบบสุดโต่งออก
    • ตอนรันใช้ตัวเลือก เช่น --anticomp, --mode regular, --listen-port 8080, --listen-host 127.0.1.1
  • Certificate Pinning คือเทคนิคที่เซิร์ฟเวอร์หรือไคลเอนต์รู้ fingerprint ของ certificate ที่คาดไว้ล่วงหน้า ทำให้การปลอม certificate ของ MITMProxy ใช้ไม่ได้
    • วิธีเลี่ยงคือใช้ --ignore-hosts เพื่อให้โฮสต์อย่าง apple.com:443, icloud.com:443 ข้าม proxy ไป
  • patch next_layer.py ของ MITMProxy 7.0.4 เพื่อให้ --allowed-hosts ใน Transparent Proxy Mode ทำงานตาม SNI ได้ดีขึ้น
    • เดิมมองว่าหลายกรณีใช้เฉพาะ server IP ในการ match
    • patch เพิ่ม server.sni เข้าไปเป็น hostname candidate นอกเหนือจาก server.address[0]
  • หลัง patch ระบุว่าสามารถดักจับบางโฮสต์ได้อย่างเสถียร และปล่อยโฮสต์ที่เหลือให้ผ่านไปได้

ลบโฆษณา JSON ของ YouTube บนเว็บ

  • ใน smoke test ของ MITMProxy บล็อก URL โฆษณาและติดตามของ YouTube ด้วยสคริปต์ขนาดเล็ก
    • บน youtube.com บล็อก /pagead/, /log_event?, /stats/ads, /stats/qoe?, /ptracking?, /generate_204, el=adunit, adformat=, /activeview? เป็นต้น
    • สำหรับ google.com และ google.ca บล็อก /pagead/
  • ในการทดสอบช่วงแรก คำขอที่อยู่ในเป้าหมายการบล็อกถูกบล็อกจริงแม้ใน DevTools Network panel
    • รายการ (failed) เกิดจากสคริปต์
    • มองว่าความล้มเหลว 502 เป็นผลจาก pfBlockerNG จัดการคำขอแบบ black-hole
    • ปิดใช้งาน HTTP/2 เพื่อไม่ให้คำขอถัดไปใน channel เดียวกันผ่านไปได้
  • การบล็อก URL อย่างเดียวไม่ได้ทำให้โฆษณาหายไปทั้งหมด จึงตรวจสอบ YouTube HTML·JavaScript และ filter ของ uBlock Origin เพื่อไล่ดูความเป็นไปได้ที่ข้อมูลโฆษณาอยู่ใน body ของ JSON response
  • ใน JSON response ที่ MITMProxy capture ได้ พบข้อมูลโฆษณาและการติดตามในโครงสร้าง playerAds และ playbackTracking
    • playerAds มี playerLegacyDesktopWatchAdsRenderer, playerAdParams, gutParams.tag, showCompanion, showInstream, useGut เป็นต้น
    • playbackTracking มี videostatsPlaybackUrl, ptrackingUrl, qoeUrl, atrUrl เป็นต้น
    • youtubeRemarketingUrl อยู่ในรูปแบบ www.youtube.com/pagead/viewthroughconversion/...
  • บน YouTube เว็บ สามารถลบข้อมูลโฆษณาออกจาก JSON payload เพื่อกำจัดโฆษณาบนเว็บผ่านเราเตอร์ได้

การวิเคราะห์ iOS YouTube และ Protobuf

  • แอป YouTube บน iOS ใช้ข้อมูลในรูปแบบ Protocol Buffer(Protobuf) แทน JSON สำหรับการเรียก API ที่คล้ายกับเวอร์ชันเว็บ
    • ใน Protobuf คีย์เป็นตัวเลขและอาจเปลี่ยนได้ จึงหา section โฆษณาด้วยวิธีแบบ JSONPath ได้ยาก
    • พบสตริงโฆษณาอย่าง “Telus”, “Samsung TV”, “Boxing Week”, “Buy now” ใน payload
  • ทราฟฟิกเครือข่ายของ iOS YouTube แตกต่างจากทราฟฟิกเว็บ
    • ในเวอร์ชันเว็บ สามารถประมาณผู้เข้าข่ายเป็นโฆษณาได้ระดับหนึ่งจากพารามิเตอร์ range หรือ clen ของ chunk วิดีโอ
    • โปรโตคอล iOS ไม่ใช้พารามิเตอร์ query range หรือเฮดเดอร์ Range แต่ใช้ตัวนับอย่าง &nr=2, &nr=3
  • เมื่อถอดรหัส response Protobuf แล้ววิเคราะห์แบบออฟไลน์ พบรายการอย่าง has_unlimited_entitlement: False, has_premium_lite_entitlement: False
    • วิธีเปลี่ยนค่าเหล่านี้รู้สึกเหมือนเป็น “cheating” จึงกลับไปใช้แนวทาง heuristic อีกครั้ง
  • การทดลองบล็อก URL โฆษณาทำให้แอป iOS เกิดลูปไม่สิ้นสุด, UI ผิดพลาด และแครช
    • การคืน 200 พร้อม body ว่าง, 404, 503, response body ที่ถูกตัดทอน, หรือการทำให้บางส่วนของ ad video เป็น null ทำให้แอปช้าลงหรืออยู่ในสภาพเสียแล้วแครช
    • endpoint รายงานข้อผิดพลาด /error_204/ แสดง “dev assertion failed” จึงบล็อกไว้
  • ดูเหมือนว่าโฆษณาจะถูกลงทะเบียนไว้ใน slot ภายในวิดีโอบางตัว
    • ประเภทของ slot มี pre-roll, mid-roll, end-roll, full-page และ ad pod
    • หากบล็อกเฉพาะ URL โฆษณา จะเกิดข้อผิดพลาดทำนองว่า “โฆษณาที่ไม่มีอยู่ได้จอง slot ไว้” และ UI จะเข้าสู่สถานะ panic

ปัญหาประสิทธิภาพของ Protobuf และ blackboxprotobuf

  • การถอดรหัส raw Protobuf ขนาดประมาณ 500KiB ให้เป็นข้อความที่มนุษย์อ่านได้ด้วย Python เพียงอย่างเดียวนั้นช้ามาก
    • บนเดสก์ท็อป CPU i7-6700 ใช้เวลาประมาณ 2.06~2.11 วินาที
    • บนเราเตอร์ pfSense ใช้เวลาประมาณ 22.8~24.2 วินาที
  • C++ protoc --decode_raw เร็วกว่ามาก
    • บนเดสก์ท็อป CPU i7-6700 ใช้เวลาประมาณ 0.017~0.022 วินาที
    • บนเราเตอร์ pfSense อยู่ที่ประมาณ 0.12~0.14 วินาที
  • เนื่องจาก Python ไม่รองรับ raw decoding จึงเลือกวิธีสื่อสารโดยตรงกับไบนารี C++ protoc ผ่าน subprocess.Popen
  • blackboxprotobuf สำหรับ Burp Suite สามารถ decode raw Protobuf wire message, ฉีดค่า แล้ว re-encode ได้
    • แนะนำให้ใช้เวอร์ชัน Burp Suite ต้นฉบับ ไม่ใช่ fork บน PyPI
    • fork บางตัวอาจทำให้เกิด stack overflow จาก deep recursion
    • หากตั้งค่า os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp" ก่อน import protobuf จะใช้ implementation C++ libprotobuf.so เมื่อเป็นไปได้
  • protobuf_to_json(data) ของ blackboxprotobuf สามารถสร้าง schema .proto แบบคาดเดาที่ดีที่สุดได้ แต่ผลลัพธ์มีขนาดใหญ่มาก ซ้อนลึก และไม่สมบูรณ์แบบ
    • dump schema ใน Python มีความยาวประมาณ 250,000 ตัวอักษรขึ้นไป
    • มองว่าเพียงพอสำหรับดึงรายละเอียดโฆษณาออกมา

ทำให้ section โฆษณาไร้ผลด้วยการเปลี่ยน 1 ไบต์

  • หาก decode/edit/re-encode Protobuf Wire Format โดยไม่มี schema ต้นฉบับ encoding อาจเปลี่ยนไปได้
    • สาเหตุที่ยกมาคือ การใช้ ZigZag encoding หรือไม่, การไม่สามารถจำแนกชนิดตัวเลขได้ และความไม่แน่นอนของลำดับ object field
  • วิธีแก้คือใช้ backward compatibility ของ Protobuf เพื่อทำให้ section โฆษณาดูเหมือน field ที่ไม่รู้จัก
    • ใช้พฤติกรรมที่ซอฟต์แวร์เก่าเพิกเฉยต่อ field ที่ไม่รู้จักเมื่ออ่าน field ใหม่
    • หากเปลี่ยน 1 ไบต์ในจุดสำคัญ ทำให้ section ที่ซ้อนลึกดูเหมือนเป็นของ future schema version, Protobuf จะเพิกเฉยต่อส่วนนั้น
  • ต้องหา target field key 49399797 ด้วย varint tag scanning ไม่ใช่การค้นหาสตริงแบบง่าย
    • wire type คือ 2 หมายถึง nested string/message แบบ length-delimited
    • target tag คำนวณได้เป็น AA FF B8 BC 01
    • เมื่อ shift out บิต wire type 3 บิต จะได้ field key 49399797 กลับมา
  • การค้นหาจริงเริ่มจากการหา signature ของ URL โฆษณาอย่าง /pagead/ ใน raw Protobuf bytes ก่อน แล้วถอยกลับไปแถว ๆ นั้นเพื่อหา target field tag และ field key
    • ตัวอย่างเป้าหมายสำหรับ intercept คือ POST youtubei.googleapis.com:443/youtubei/v1/browse?key=...
    • response คือ 200, application/x-protobuf, 1.87m
    • ใน log ตัวอย่างพบ 49399797 ที่ position 4465 และ 50195462 ที่ position 4477
  • ใน smoke test แบบ O(n) สแกน Protobuf data ขนาด 1.8MiB หนึ่งครั้งโดยไม่ใช้หน่วยความจำเพิ่ม แล้วการลบโฆษณาทำงานได้
    • พบ target ที่ byte ลำดับที่ 30,593
    • ใช้การ backtracking ประมาณ 600 byte เพื่อหา field key ที่จะทำให้ผิดรูป
    • ไม่จำเป็นต้องบล็อก URL ที่มี *.googleadservices.com หรือ /pagead/ อีกต่อไป และ request ดังกล่าวจะไม่ถูกสร้างขึ้นตั้งแต่แรก

โครงสร้างแอดออน MITMProxy

  • สคริปต์ PoC บันทึกเป็น youtube.py และรันด้วย mitmdump --listen-port 8080 --listen-host 127.0.0.1 -s "youtube.py"
    • ระบุ prerequisite สำหรับ FreeBSD คือ pkg install protobuf, pkg install py38-pip, pip install jsonpath-ng
  • สคริปต์ประกอบด้วยคลาส Logger, trunc, KilledError, JSONPathReplacement, ProtobufDebugParser, YouTubeAdBlocker
  • host regex ที่ YouTubeAdBlocker ใช้เป็นเป้าหมายในการ intercept คือ \.youtube\.com|google\.(com|ca)|googleapis\.com|googleadservices\.com|googlevideo\.com
    • search string ของ URL โฆษณา Protobuf คือ b"/pagead/"
    • search limit คือ 80_000
    • target field tag คือ 50195462
  • rule สำหรับบล็อก request จะตรวจสอบสตริง partial URL แยกตาม host แล้ว kill flow
    • สำหรับ youtube.com มี pagead/, log_event?, stats/ads, stats/qoe?, ptracking?, generate_204, error_204, adformat=, activeview?, _ad_, ai?, sw.js เป็นต้น
    • มีคอมเมนต์ที่ sw.js ว่าเป็นการปฏิเสธ service workers
  • ใน JSON response จะใช้ JSONPath replacement หลายรายการ
    • $.responseContext.serviceTrackingParams[*].params[?(@.key == 'yt_ad')].value ถูกเปลี่ยนเป็น "0"
    • $..adPlacements ถูกเปลี่ยนเป็น []
    • $..adPlacementRenderer, $..adPlacementConfig, $..playerAdParams, $..gutParams ถูกเปลี่ยนเป็น {}
    • $..adVideoId ถูกเปลี่ยนเป็นสตริงว่าง
    • $..showCompanion, $..showInstream, $..useGut ถูกเปลี่ยนเป็น False
  • ใน Protobuf response เมื่อ content type มีคำว่า protobuf จะสร้าง body เป็น bytearray แล้วค้นหา /pagead/ ภายใน 80,000 ไบต์แรก
    • สร้าง target tag bytes ด้วย TagBytes(self.target_field_tag, WIRETYPE_LENGTH_DELIMITED) และสร้าง bytes ใหม่ของ target_field_tag - 1
    • ค้นหาย้อนกลับจนถึงตำแหน่งก่อนหน้า /pagead/ เพื่อหา target tag bytes
    • หากพบ จะเขียนทับ byte เหล่านั้นด้วย bytes ใหม่ แล้วแทนที่ response body ด้วย flow.response.set_content(bytes(body))
  • ในคอมเมนต์ระบุว่า PoC นี้บล็อกโฆษณาได้ 90%
    • section อื่นก็มี field key อื่น ๆ และอาจมี ad section หลายจุดที่ต้องทำให้เสียรูป

ขอบเขตการใช้งานและข้อจำกัด

  • เทคนิคนี้ถูกสรุปว่าเป็น highly specialized technique สำหรับบล็อกโฆษณา YouTube บนอุปกรณ์ Apple หรือ tracker traffic อย่าง Instagram, WhatsApp, Facebook
  • มองว่าความต้องการ CPU สำหรับ decrypt/re-encrypt HTTPS traffic นั้นเกินกว่าที่ Raspberry Pi จะรับไหวอย่างมาก
  • หลัง jailbreak Apple TV แล้วเพิ่ม pfSense root certificate จะทำให้ pfSense gateway ถอดรหัสทราฟฟิกของ Apple TV และตรวจสอบ hostname โฆษณาใน request header เพื่อบล็อกได้
    • อย่างไรก็ตาม ยังใช้กับโฆษณาบน iPhone ไม่ได้ และการ jailbreak iPhone ทำได้ยากกว่า อีกทั้ง banking app อาจตรวจพบแล้วไม่ทำงาน
    • ประเมินว่าการ jailbreak เองเป็นวิธีที่สุดโต่งเกินไป
  • หากทำ fake trusted CA ได้ ก็สามารถถอดรหัส TLS packet เป็นข้อความล้วนและใช้ URL blocking ได้
    • ยกตัวอย่าง URL ที่บล็อกเป็นเส้นทาง /pagead/viewthroughconversion/... และ /pagead/conversion/... ของ YouTube
  • สุดท้าย ตั้งค่า hardware router ตั้งแต่ต้น แบ่ง LAN เป็นโซนที่เชื่อถือและไม่เชื่อถือ เพิ่ม DNS ad blocking และ transparent MITM proxy แล้วบล็อกโฆษณา YouTube บนอุปกรณ์ Apple ที่เชื่อมต่อเครือข่ายได้ด้วยประสิทธิภาพดี

YouTube Premium และการสนับสนุนครีเอเตอร์

  • หลังจากบล็อกโฆษณา YouTube อยู่หลายเดือน ก็เริ่มจ่ายเงิน YouTube Premium เพราะอยากสนับสนุนผู้สร้างคอนเทนต์
    • ระบุเงื่อนไขไว้ว่า “แค่ทำได้ ไม่ได้แปลว่าควรทำ”
  • ราคา YouTube Premium ถูกกล่าวถึงว่าเพิ่มจาก CAD $9.99/mo เป็น $11.99/mo และรวมภาษีแล้วประมาณ $13.43/mo
  • ในการทดลองดูโฆษณา ใช้แล็ปท็อปสะอาดและโหมด private browsing ดู YouTube เป็นครั้งคราวตลอดหนึ่งวัน
    • ตามบันทึกมีวิดีโอที่ดู 10 รายการ
    • พบโฆษณา 8 รายการ และในนั้นมีเพียง 2 รายการที่กดข้ามได้
  • หากสมมติ CPV เป็น USD $0.15 ต้นทุนโฆษณาต่อวันคือ $1.20 และเมื่อนำไปประมาณทั้งเดือนจะอยู่ที่ราว USD $36/mo
  • ในการคำนวณอีกแบบที่ใช้ตัวเลขจาก Statista ระบุว่าในปี 2019 ผู้ลงโฆษณาในสหรัฐฯ ใช้เงินกับ YouTube $15.1 billion และผู้อยู่อาศัยในสหรัฐฯ ดูวิดีโอ 916 billion รายการ ทำให้เฉลี่ยต่อการรับชมเป็น USD $0.0165
    • หากใช้การคำนวณนี้ ต้นทุนต่อวันจะอยู่ที่ประมาณ USD $0.13 และเมื่อนำไปประมาณทั้งเดือนจะอยู่ที่ราว USD $3.96
    • มองว่าค่านี้ไม่ได้ใกล้เคียงกับ Premium ที่ประมาณ USD $10
  • หากมี DMCA claim รายได้โฆษณาอาจไปยังผู้ยื่น claim อย่าง Sony หรือ Viacom แทนที่จะเป็นครีเอเตอร์
    • ด้วยเหตุนี้ คุณอาจไม่ได้ให้อะไรแก่ช่องที่ชอบเลยโดยไม่รู้ตัว
    • ประเมินว่าไม่น่าแปลกใจที่ครีเอเตอร์จำนวนมากย้ายไป Patreon

2 ความคิดเห็น

 
xguru 2023-08-29

ต้นฉบับยาวมาก แต่กระบวนการก็น่าสนใจ โดยประเด็นสำคัญคือสุดท้ายผู้เขียนก็ลงเอยด้วยการจ่าย YouTube Premium แล้วใช้งานอยู่ดี

 
GN⁺ 2023-08-28
ความคิดเห็นจาก Hacker News
  • โดยรวมเป็นการแฮ็กที่เจ๋ง แต่บางคำอธิบายเกี่ยวกับ Protobuf ฟังดูแปลก ๆ
    สิ่งที่ทำคือจงใจทำให้แท็กของฟิลด์บางตัวใน Protobuf เสียหาย และการที่มันมองข้ามหมายเลขแท็กที่ไม่รู้จักนั้นไม่ใช่ “ข้อบกพร่อง” แต่เป็นการออกแบบหลักเพื่อความสามารถในการขยาย
    1.87MiB ก็ไม่ได้ใหญ่ขนาดนั้น และข้อความแบบนี้ก็คงไม่ได้ถูกสตรีมต่อเนื่องตลอดเวลา ดังนั้นคำอธิบายว่าเป็นกำแพงด้านประสิทธิภาพจึงยังไม่ค่อยน่าเชื่อ
    การเข้ารหัสของ Protobuf ไม่ได้ถูกออกแบบมาให้ถอดรหัสแพงขึ้น แต่ตรงกันข้าม ถูกออกแบบมาให้ถอดรหัสได้อย่างมีประสิทธิภาพ และแม้ไม่มีสคีมา .proto ต้นฉบับ ก็ยังถอดรหัสเองได้ด้วย UnknownFieldSet
    วิธีที่ดีกว่าน่าจะเป็นการใช้สคีมา .proto ปลอมที่มีเฉพาะฟิลด์เดียวที่ต้องการลบออก วิธีสแกนสตริงมีโอกาสผิดพลาดง่ายกว่า เพราะลำดับไบต์เดียวกันอาจบังเอิญไปปรากฏในข้อมูลอื่นได้
    หากลำดับฟิลด์เปลี่ยน ผลลัพธ์ไบต์หลังเข้ารหัสใหม่อาจต่างออกไป แต่ฝั่งรับควรต้องประมวลผลเป็นข้อความเดียวกัน และดูไม่น่าเป็นไปได้ที่แอป YouTube จะตรวจจับการเปลี่ยนลำดับฟิลด์
    จากมุมมองของคนที่เคยทำงานกับ Protobuf มาก่อน ดูเหมือนผู้เขียนจะเข้าใจส่วนนี้ผิด

    • เป็นการวิเคราะห์ที่ดี แต่คงเห็นด้วยยากนิดหน่อยกับการบอกว่า 1.87MB เล็ก
      ผมใช้ชีวิตส่วนใหญ่มาตลอดในพื้นที่ชนบท และถ้าไม่ใช่ Wi‑Fi ของผมเอง ขนาดเท่านี้ก็ถือเป็นการดาวน์โหลดที่ใหญ่ในทางปฏิบัติแล้ว บนมือถืออาจมีวิธีเลี่ยงได้บ้าง แต่ Wi‑Fi ในชนบทยังรับมือกับโครงสร้างแบบ Web 2.0 ได้ลำบาก และมักใช้งานกันที่ความเร็วระดับ 2~4G
      ในเขตเมืองที่มีประชากรพอรองรับโครงสร้างพื้นฐาน 1.87MB โดยทั่วไปอาจกลายเป็นไฟล์เล็กไปแล้ว แต่ช่วงประมาณ 6 โมงเย็นที่คนบนสายเคเบิลพากันสตรีมก็อาจเป็นข้อยกเว้นได้
    • ขอโปรโมตเล็กน้อยเกี่ยวกับ without the C++ source proto files ผมทำโปรเจกต์ชื่อ protodump ที่สร้างไฟล์ซอร์ส .proto จากไบนารีได้
      มันสร้างคำจำกัดความของ message และ field ขึ้นมาใหม่ พร้อมชื่อเดิมด้วย ขอแค่ดึงไบนารีออกมาจากกล่อง Apple TV ก็พอ
      https://github.com/arkadiyt/protodump
    • คำว่า “เคยทำงานกับ Protobuf มาก่อน” นี่เป็นการพูดอย่างถ่อมตัวสุด ๆ สำหรับคนที่ไม่รู้ Kenton คือคนที่ทำให้ Protobuf กลายเป็นแบบที่เป็นอยู่ในปัจจุบัน
      Protobuf เป็นเทคโนโลยีที่ทำให้ผมรู้จัก IDL เป็นครั้งแรก และในตอนนั้นมันดูเหมือนไอเดียเวทมนตร์เลย ยิ่งหลังจากผมเคยสร้าง IDL แบบลวก ๆ เองแล้วมาค้นพบ Protobuf ก็ยิ่งทึ่งเข้าไปใหญ่
    • ตอนอ่านบทความนี้ผมก็สับสนคล้าย ๆ กัน หลักการออกแบบของ Protobuf ไม่ใช่ความลับอะไร และทั้งหมดก็มีเอกสารอธิบายไว้อย่างชัดเจน
    • ส่วนที่ยากที่สุดเวลาถอดรหัส Protobuf โดยไม่มีสคีมาคือ embedded message กับสตริงใช้ชนิดแท็กเดียวกัน แต่ถึงอย่างนั้นก็ยังจัดการได้ค่อนข้างง่าย
      ถ้าไม่อยากลาก dependency ของ protoc ทั้งก้อนเข้ามา ก็เขียนตัวถอดรหัส Protobuf แบบง่าย ๆ ไม่กี่ร้อยบรรทัดเองได้: https://github.com/kubernetes/test-infra/blob/master/guberna... https://github.com/kubernetes/test-infra/blob/master/guberna...
  • ตั้งแต่เจอ The Proxomitron เมื่อกว่า 20 ปีก่อน ผมก็ใช้พร็อกซีแบบ man-in-the-middle จัดการทราฟฟิกมาโดยตลอด เพื่อเอาโฆษณาออกและเขียนหน้าเว็บใหม่ด้วยสิ่งอย่าง CSS ของผู้ใช้
    ที่อย่าง CloudFlare มักจัดผมเป็น “บ็อต” แต่เรื่องนั้นก็มีวิธีเลี่ยง แม้จะไม่ง่ายก็ตาม กรณีแบบนี้ยังแสดงให้เห็นด้วยว่า remote attestation อันตรายต่อเสรีภาพของผู้ใช้อย่างไร

    • ลองหา The Proxomitron ดูแล้วเหมือนการพัฒนาจะจบไปตั้งแต่ปี 2004 ถ้ามีสรุปสถานการณ์ปัจจุบันจากคนที่รู้ดีคงน่าสนใจ
      ดูเหมือนจะมีโปรเจกต์ “สืบทอด” อยู่หลายตัว และก็สงสัยด้วยว่ายังจำกัดเฉพาะ Windows หรือไม่ ผมกำลังมองหาพร็อกซีง่าย ๆ แบบเบา ๆ ที่แทรกลิงก์โลคัลเข้าไปในคอนเทนต์จากระยะไกลได้
    • การบล็อกโฆษณาระดับเครือข่าย อย่าง Privoxy หรือ pi-hole มีข้อเสียเยอะเกินไป เช่น จัดการโฆษณาแบบ inline ไม่ได้
      ตอนนี้ผมถอด pi-hole ที่เคยรันบน Pi 4 ออกแล้ว ใช้เวลาหลายชั่วโมงพยายามทำให้มันทำงานได้ดีร่วมกับหลายบริการ แต่สุดท้ายก็ยอมแพ้ และมันไม่คุ้มค่ากับเวลาที่ต้องทุ่มให้เครือข่ายในบ้าน
      สิ่งที่ใช้ได้จริงคือ ad blocker บนเบราว์เซอร์กับตัวแพตช์แอปอย่าง ReVanced พอเงินเก็บเพิ่มขึ้น ผมก็เอนเอียงไปทางจ่ายค่าบริการแบบไม่มีโฆษณาสำหรับกรณีที่สองอย่างนั้นแก้ไม่ได้ เช่น YouTube Premium, Hulu, Netflix, Max
    • รู้กันว่าพนักงาน Cloudflare แอบอ่านอยู่ที่นี่ เลยสงสัยว่า การถูก จัดเป็นบ็อต แบบนี้ถือเป็น false positive หรือถือว่าทำงานตามที่ตั้งใจไว้?
    • ผมแทบไม่ได้คิดถึง Proxomitron มาเกือบ 20 ปีแล้ว เลยสงสัยว่ายังมีคนใช้อยู่ไหม
      ผมไม่เคยใช้เพื่อวัตถุประสงค์แบบที่พูดถึงตรงนี้ แต่สำหรับใช้เป็นพร็อกซีหลังไฟร์วอลล์บริษัทนี่เยี่ยมมาก สมัยก่อนไฟร์วอลล์ต้องการข้อมูลล็อกอินสำหรับการเชื่อมต่อออกภายนอก ทำให้โปรแกรมจำนวนมากเข้าอินเทอร์เน็ตไม่ได้
    • น่าจะเป็นวิธีที่ต้องติดตั้ง ใบรับรอง CA ใหม่บนอุปกรณ์ ใช่ไหม?
  • ทำให้นึกถึง Privaxy ที่แพ็กเกจมาเป็น Docker เป็นพร็อกซีแบบคนกลางที่เข้ากันได้กับรายการบล็อกของ UBlock Origin
    พอเห็นว่าผลิตภัณฑ์อัจฉริยะ โดยเฉพาะทีวี มีโฆษณาและสคริปต์ติดตามมากแค่ไหนก็น่าตกใจ จากที่ทดสอบมาจนถึงตอนนี้ ทราฟฟิกที่ไม่จำเป็นมีเกิน 40% และการทดลองลอกโฆษณาออกจากแอปสมาร์ททีวีก็สนุกทีเดียว
    https://github.com/deetungsten/webui-privaxy เป็นฟอร์กที่ทำเป็น Docker ของ https://github.com/Barre/privaxy

    • จะทำอย่างไรให้ทีวีเชื่อถือ ใบรับรองที่เซ็นเอง?
    • ดีใจที่เห็นเรื่องนี้ที่นี่ด้วย ดีที่หยิบประเด็นปัญหา ping ของรายการฟิลเตอร์ขึ้นมา
      เคยพยายามแก้ฟอร์กไม่ให้ใช้ที่อยู่ 0.0.0.0 ที่ฮาร์ดโค้ดไว้ในฟรอนต์เอนด์ เพื่อให้แยก Docker container ได้จริง ๆ แต่ชีวิตก็แทรกเข้ามา เคยลองบน Apple TV ไหม?
    • Adguard ก็กำลังทำสิ่งคล้าย ๆ กันอยู่
      https://github.com/AdguardTeam/urlfilter
    • ใช้เวลานานเกินไปกว่าจะเข้าใจว่าคำว่าฟอร์กที่ทำเป็น Docker หมายถึง GUI ถูกเปลี่ยนเป็นเว็บ GUI
  • บทความนี้เป็นคำตอบที่ยอดเยี่ยมสำหรับคำถามที่เจอบ่อย ๆ ว่า “ถ้าอยากเป็นแฮกเกอร์ควรเรียนอย่างไร?”
    มันแสดงให้เห็นได้ดีถึง กระบวนการคิด และงานที่ต้องกัดไม่ปล่อยซึ่งอยู่เบื้องหลัง exploit ใด ๆ

  • มีส่วนที่บอกว่า “มาใช้ WireGuard กัน — มีชุดคำสั่งเข้ารหัส Intel AES-NI” แต่เท่าที่ผมรู้ WireGuard ไม่ได้ใช้ AES
    โดยรวมแล้วดูเหมือนผู้เขียนจะประเมินความต้องการ CPU ของการเข้ารหัส TLS สูงเกินไปอยู่บ้าง หรือไม่ก็ประเมินประสิทธิภาพของคอมพิวเตอร์บอร์ดเดี่ยวสมัยใหม่ต่ำเกินไป
    คำอธิบายที่ว่าความต้องการ CPU สำหรับถอดรหัสและเข้ารหัสทราฟฟิก HTTPS ใหม่บน Raspberry Pi นั้นเกินขีดจำกัดไปมากก็น่าสงสัย ถ้าการทำ TLS แบบคนกลางบน RPi 4 เป็นไปไม่ได้จริง ๆ ผมคงค่อนข้างแปลกใจ และแม้ใช้ RSA แบบซอฟต์แวร์ล้วนก็เช่นกัน
    ในบรรดามือถือ Android ที่ยังใช้อยู่ มีบางเครื่องที่มี CPU อ่อนกว่า RPi 4 และเครื่องเหล่านี้ก็ใช้ TLS

    • ดูเหมือนจะประเมินความต้องการ CPU ต่ำเกินไป
      มือถือ Android สเปกอ่อน ๆ ต่อให้จัดการทราฟฟิก TLS ได้แค่ 50Mb/s ในการใช้งานจริงก็อาจไม่ใช่ปัญหาใหญ่ เพราะมือถือที่ช้ามักเชื่อมต่อกับเครือข่ายที่ช้าอยู่แล้ว
      แต่ถ้าที่บ้านมีอินเทอร์เน็ตกิกะบิต แล้วเกิดคอขวดที่ 50Mb/s เพราะมีอุปกรณ์สเปกอ่อนคั่นอยู่ระหว่างคอมพิวเตอร์ทั้งหมดกับอินเทอร์เน็ต นั่นเป็นปัญหาใหญ่
      ความต้องการ CPU ของ TLS ขึ้นอยู่กับแบนด์วิดท์เป้าหมายอย่างมาก ที่แบนด์วิดท์สูง ๆ การ offload ไปยังตัวเร่งความเร็วแทบจะเป็นสิ่งจำเป็น ค่าใช้จ่ายของ handshake ก็ไม่ควรมองข้าม และอาจจำกัดจำนวนการเชื่อมต่อต่อวินาทีได้ บนอุปกรณ์เครื่องเดียวอาจไม่ค่อยเป็นปัญหา แต่ในเครือข่ายของอุปกรณ์ทั้งหมดอาจกลายเป็นเรื่องใหญ่ขึ้นได้
  • เป็นบทความที่ยอดเยี่ยม ผมคาดหวังว่าจะได้เห็นวิธีทำ คนกลาง กับอุปกรณ์ที่ไม่อนุญาตให้ติดตั้ง CA แบบกำหนดเอง
    ผมมีอุปกรณ์ IoT ที่ไม่เปิด local API และแสดงข้อมูลผ่านคลาวด์เท่านั้น เลยอยากดักจับทราฟฟิกระหว่างอุปกรณ์กับคลาวด์
    สุดท้ายคงไม่มีทางอื่นนอกจาก dump หน่วยความจำแฟลช เปลี่ยน CA แล้วแฟลชกลับขึ้นไปหรือเปล่า?

    • ถ้าใบรับรองถูก “ฮาร์ดโค้ด” ไว้ นั่นเรียกว่า certificate pinning ถ้าเป็นอย่างนั้น ต้องเปลี่ยนหรือลบใบรับรอง แล้วนำใบรับรองเดียวกันไปไว้ในพร็อกซีคนกลาง จึงจะถอดรหัสทราฟฟิกได้
      มีบทความดี ๆ สำหรับลองวิธีดักอุปกรณ์ IoT โดยไม่ต้องยุ่งกับฮาร์ดแวร์หรือเฟิร์มแวร์:
      https://robertheaton.com/2019/11/21/how-to-man-in-the-middle...
    • การมองหาวิธีทำคนกลางกับอุปกรณ์ที่ไม่อนุญาตให้ติดตั้ง CA แบบกำหนดเอง สุดท้ายแล้วก็คือการฝืน จุดประสงค์ของ TLS
      ถ้าทำได้ก็เท่ากับอาศัยข้อบกพร่องในการใช้งานจริง
      พูดตรง ๆ ตอนนี้แม้แต่อุปกรณ์บางรุ่นที่ยังติดตั้งใบรับรองที่เชื่อถือเองได้ ผมก็คิดว่าวันแบบนั้นคงเหลืออีกไม่นาน
  • วิธีใหม่ ๆ ในการบล็อกโฆษณาบน YouTube หรือแพลตฟอร์มใด ๆ มักจะโผล่มาเสมอ แต่ไม่กี่เดือนต่อมาก็ถูกเปลี่ยนจนใช้ไม่ได้
    ถ้าแทนที่จะทำแบบนั้น ลอง โจมตีผู้ลงโฆษณา ล่ะ? YouTube/Google ดูเหมือนจะติดตามแค่ “คลิก” แล้วติดตามไปถึงการซื้อจริงด้วยไหม?
    ในทางทฤษฎี ถ้ามีบอตปลอมจำนวนมากพอและผู้ใช้จริงคลิกโฆษณาแต่ไม่ซื้ออะไรเลย ก็สามารถเผางบโฆษณาให้หมดได้ เมื่อเวลาผ่านไป ฝ่ายการตลาดจะเห็นว่าบนแพลตฟอร์มนั้นจำนวนคลิกสูงเป็นประวัติการณ์ แต่ conversion rate เมื่อเทียบกับคลิกหรือ impression ต่ำมาก และสุดท้ายอาจถอนตัวจากแพลตฟอร์มนั้น

    • จากที่ Nauseum ถูกบล็อกจาก Chrome Store ดูเหมือนว่าวิธีนี้จะได้ผลพอสมควร
  • เป็นบทความที่น่าทึ่ง ทันทีที่เห็นขั้นตอน mitm patch ก็คิดเลยว่าน่าจะเป็นบทความพิเศษ แล้วก็เป็นอย่างนั้นจริง ๆ

  • ประทับใจกับหัวข้อในสารบัญที่ว่า “เป้าหมายใหม่: ทำให้ YouTube เชื่อว่าผมเป็นผู้ชายอายุ 70 ปีที่อาศัยอยู่ในอิตาลี”
    ไม่รู้ว่าเกิดขึ้นได้อย่างไร แต่ครั้งหนึ่งการกำหนดเป้าหมายโฆษณาเคยทำให้ระบบเชื่อว่าผมเป็นคนที่กำลังจะซื้อ ชุดนอนผ้าไหมซักได้ราคา 500 ดอลลาร์ ให้แฟน
    ตัวโฆษณาเองยอดเยี่ยมมาก แต่ก็สงสัยว่าเขาจ่ายต่อ impression เท่าไร
    หลังจากเปลี่ยนมาใช้ Apple TV ส่วนใหญ่จะได้โฆษณาท้องถิ่นที่กำหนดพื้นที่ผิด โดยเฉลี่ยแล้วบางทีแบบนั้นอาจดีกว่าก็ได้

  • นี่ไม่ใช่ “ข้อบกพร่อง” ของ Protobuf การที่เมื่อแก้ไขไบต์แล้วถูกถอดรหัสเป็นฟิลด์ในตำแหน่งอื่นนั้นคือการ ทำงานตามที่ออกแบบไว้
    Protobuf เดิมทีเป็นโปรโตคอลที่อิงหมายเลขฟิลด์และคำนำหน้าความยาว และตั้งอยู่บนสมมติฐานที่สมเหตุสมผลว่าไบต์จะไม่ถูกเปลี่ยนระหว่างส่ง ส่วนความถูกต้องสมบูรณ์ของข้อมูลปล่อยให้ฝั่งที่อ่านเป็นผู้รับผิดชอบ
    ต่อให้เรียกว่าเป็นข้อบกพร่องได้ ก็ไม่น่าจะเป็นของ Protobuf แต่เป็นของแอป YouTube สำหรับ iOS และจริง ๆ แล้วก็ไม่ใช่ข้อบกพร่อง จึงยากที่จะเรียกว่า “exploit” ได้ เว้นแต่ว่าหมายถึงกรณีที่ในการแลกเปลี่ยน Protobuf ของแอป YouTube บน iOS ไม่มีการตรวจสอบแฮชของ payload ที่ส่งกลับมา
    หลังจากบทความนี้ อาจจะมีการตรวจสอบแล้วก็ได้

    • การใช้ถ้อยคำของผู้เขียนดูแปลกไปหน่อย คำว่า “ข้อบกพร่อง” ปรากฏแค่ในชื่อเรื่อง ส่วนเนื้อหาเพียงอธิบายว่ารูปแบบนี้ทำงานอย่างไร
      มันไม่ใช่ข้อบกพร่อง แต่เป็นการทำงานตามการออกแบบ
      ส่วนที่บอกว่า “Google ทำให้การ decode, แก้ไข และ re-encode มีต้นทุนการคำนวณสูง หากไม่มีไฟล์ proto ต้นฉบับภาษา C++” ก็แปลกเช่นกัน ถ้าทำด้วยโค้ด Python ที่ไม่ได้ optimize ก็อาจจะแพง แต่ถ้าเขียนด้วย C หรือภาษา compiled อื่น ๆ การสแกน Protobuf ขนาด 1.8MB ไม่ว่าจะมีไฟล์ proto ต้นฉบับหรือไม่ ก็เป็นเรื่องเล็กน้อย
      ไม่น่าจะใช่เป้าหมายการออกแบบที่ทำให้ไฟล์ Protobuf ถอดรหัสได้ยากเมื่อไม่มี source ถ้านั่นเป็นเป้าหมายจริง ก็คงทำได้แย่มาก
    • ไม่รู้ว่า required field ใน Protobuf ทำงานอย่างไร แต่เพื่อบรรเทาการโจมตี ไคลเอนต์ YouTube ของ Google อาจถือว่าฟิลด์ดังกล่าวเป็น required field และปฏิเสธบริการหากฟิลด์นั้นไม่มีอยู่หรือเป็นค่าเริ่มต้น
    • วันที่ของบทความคือเดือนมกราคม 2022 หากหลังจากบล็อกโพสต์นี้พวกเขาต้องการทำให้โปรโตคอลแข็งแกร่งขึ้น ก็น่าจะทำไปแล้ว