Descriptografando e removendo anúncios em Protobuf (2022) para bloquear anúncios do YouTube na Apple TV
(ericdraken.com)- Trata-se de um PoC que coloca um proxy MITM baseado em pfSense entre a Apple TV e a internet, descriptografa HTTPS e depois modifica as respostas Protobuf enviadas pelo YouTube para impedir que slots de anúncios sejam registrados em dispositivos Apple
- Os métodos existentes de bloqueio por DNS e roteamento via VPN esbarravam em limitações como TTL de DNS, divergência de IP, erros 403 e vazamento de ASN, porque os anúncios do YouTube e o vídeo principal usam o mesmo domínio e a mesma infraestrutura
- Os testes com Squid foram abandonados por questões de desempenho e configuração; depois disso, a abordagem mudou para descriptografar o tráfego TLS com mitmproxy/mitmdump em um jail do FreeBSD e alterar diretamente respostas JSON e Protobuf
- No YouTube web, era possível remover
adPlacements,playerAdParamse URLspageaddo JSON, mas o app do YouTube no iOS carregava slots de anúncios e informações de rastreamento em respostasapplication/x-protobuf, exigindo lidar com a estrutura Protobuf - O método final faz uma varredura linear com modificação de 1 byte: procura o field tag de trás para frente perto da string
/pagead/e troca tags como50195462portarget_field_tag - 1, obtendo desempenho adequado para processamento em tempo real sem decodificação completa
Objetivo e arquitetura inicial de rede
- O objetivo era criar um roteador baseado em FreeBSD e pfSense para bloquear, em toda a rede, anúncios pre-roll, mid-roll e end-roll do YouTube na Apple TV e no iPhone
- Colocar um proxy man-in-the-middle entre a Apple TV e a internet externa permitia descriptografar o tráfego HTTPS e ler os dados Protocol Buffer que o Google usa para preencher anúncios do YouTube
- Depois de implementar o bloqueio de anúncios do YouTube por alguns meses, o autor passou a assinar o YouTube Premium e afirma que “ser capaz” e “dever fazer” são coisas diferentes
- Os motivos para bloquear anúncios e rastreamento incluíam monitoramento de privacidade, desperdício de banda, clickbait e cryptojacking
- Ele estimava que 25% a 40% do tráfego de rede poderia ser composto por anúncios, scripts de rastreamento, fingerprint.js, googletagmanager.js e loaders de analytics em tempo real como Hotjar
- Também explica que JavaScript de mineração de cripto como CoinHive.js pode superaquecer o computador ou ser explorado para gerar pequenas quantias de dinheiro
Hardware do pfSense e configuração básica
- Para proteger toda uma rede SMB, ele considerava que VM, imagem Docker e Raspberry Pi não tinham desempenho suficiente, então seria necessário hardware dedicado apenas para roteamento, descriptografia e monitoramento de pacotes
- O hardware do roteador usado incluía um mini PC com conjunto de instruções AES-NI, RAM DDR4, SSD mSATA e um pendrive USB para gravar o pfSense
- Um exemplo de configuração era mini PC J4125, 32GiB de RAM DDR4 e SSD mSATA de 128GiB
- Ele considerava 128GB de armazenamento suficientes para logs, redução de desgaste do SSD, captura de pacotes e cache de borda para NPM e Docker
- A imagem de instalação do pfSense tem cerca de 360MB e pode ser gravada em um pendrive com o Etcher AppImage
- Após a configuração inicial, AES-NI aparecia como “Yes (inactive)” e foi ativado manualmente em
System › Advanced › Miscellaneous - Para aproveitar os 32GiB de RAM, ele alocou bastante RAM disk em
/vare/tmp, e configurou o SSD de 128GiB esperando wear-leveling, com backup do RAM disk a cada hora - No Dashboard, adicionou o widget S.M.A.R.T. para detectar problemas no SSD
Bloqueio por DNS, separação de rede e pfBlockerNG
- Antes, ele usava o Pi-hole em um Raspberry Pi como bloqueador de anúncios em nível de DNS e, no pfSense, instalou o pfBlockerNG-devel para testar bloqueio de anúncios, conteúdo malicioso e geo-blocking
- Se o serviço pfb_dnsbl não iniciar ou a aba de status mostrar
[ Missing CRON task ], ele recomenda tentar apagar o arquivo vazio/var/run/booting - Aproveitando as 3 portas Gigabit do mini PC, ele criou redes físicas em vez de VLANs e separou do restante da rede principal dispositivos que “ligam para casa”, como Alexa e Apple TV
- Dispositivos não confiáveis foram colocados na rede privada
172.31.1.0/24 - A LAN confiável permaneceu em
192.168/16 - A LAN física para IoT passava pelo adblocker, e ele queria interceptar consultas DNS hard-coded como
1.1.1.1e9.9.9.9para que o YouTube não pudesse contornar o bloqueador por DNS
- Dispositivos não confiáveis foram colocados na rede privada
- Ele configurou regras de NAT para que todos os clientes atrás do pfSense usassem o servidor local Unbound DNS
- Considerava necessário bloquear primeiro DNS over TLS para poder interceptar consultas DNS
- O iPhone pode exibir um Privacy Warning sobre bloqueio de tráfego DNS criptografado, mas as consultas DNS upstream continuariam criptografadas para a Cloudflare
- A reflexão de NAT deveria ser desativada para impedir que a internet externa acessasse o servidor DNS
- Foi criado um alias de firewall
Non_WANpara redirecionar para localhost a porta 53 das consultas DNS locais em interfaces que não fossem WAN - Como o YouTube entrega anúncios e vídeo principal a partir do mesmo domínio, era difícil filtrar apenas anúncios com bloqueadores baseados em nome de domínio como pfBlockerNG ou Pi-hole
Experimentos com bypass via VPN e pontos de falha
- Ele também fez experimentos para, em vez de bloquear anúncios, enganar o algoritmo de anúncios do YouTube e parecer um usuário menos atraente para anunciantes
- A ideia era usar o roteador pfSense para rotear, via VPN, o tráfego de rastreamento de localização do YouTube por uma região com menos espectadores
- O objetivo era fazer com que a conta do YouTube fosse vista como “homem de 70 anos, morando na Itália”
- No pfSense, em vez de OpenVPN, ele usou WireGuard para um teste-base que enviava todo o tráfego da Apple TV pela VPN
- Instalou o pacote WireGuard do FreeBSD e adicionou/ativou o túnel
- Para a configuração do NordLynx, verificou a private key em uma VM Linux com
sudo wg showconf nordlynxe a transferiu para o pfSense
- Nos testes, o Google no notebook passou a aparecer em italiano, e o YouTube da Apple TV também mudou para italiano
- Os anúncios ainda apareciam em parte, mas em menor quantidade
- Netflix e Amazon Prime tiveram problemas, e parecia que arquivos CSS ou fontes eram bloqueados ou que thumbnails não carregavam
- Ele alerta para não enviar todo o tráfego da Apple TV pela VPN e considera que Netflix e Prime detectam muito bem provider de VPN e geofencing
- Depois, para enviar apenas o tráfego do YouTube da Apple TV pela VPN, ele configurou regras de política no firewall para
www.youtube.com,youtube.com,googlevideo.com,accounts.google.com,googleapis.com,gstatic.cometc.- Como resultado, o YouTube via o usuário como estando em Milão, enquanto Netflix e Prime Video o viam como estando no Canadá
- Os anúncios caíram para algo no nível de “few and far between”
- Um dia depois, surgiu uma race condition de DNS
- O alias de hostname do pfSense é resolvido por padrão a cada 300 segundos
- O TTL de DNS do YouTube pode ser de 1.440 segundos, ou seja, 24 minutos
- Se o IP resolvido pelo Alias Daemon diferir do IP que o cliente realmente recebeu, a política pode deixar de tunelar o tráfego do YouTube
- Alguns vídeos do YouTube não reproduziam e retornavam
403 Forbidden- O YouTube supostamente embute o IP do usuário em cada requisição para
googlevideo.com - Se um domínio modificado como
r5---sn-hpa7kn76.googlevideo.comnão fosse tunelado, a requisição sairia com o IP errado e causaria o problema - O necessário seria tunelamento com wildcard para
*.googlevideo.com, mas regras de NAT e firewall operam com IP, não com hostname wildcard
- O YouTube supostamente embute o IP do usuário em cada requisição para
PoC de rastreamento de IP com base em consultas DNS
- Foi concebida uma abordagem de sequestro de consultas DNS do Google Video para rotear
*.googlevideo.compela VPN- O método consistia em rastrear periodicamente o log de consultas DNS e adicionar consultas
*.googlevideo.comà lista de aliases - Se cada vídeo usasse um domínio único e modificado, concluiu-se que esse método não funcionaria sem atualizar a cada vídeo
- O método consistia em rastrear periodicamente o log de consultas DNS e adicionar consultas
- O novo objetivo passou a ser monitorar consultas DNS com Python 3 e a API REST do pfSense para capturar IPs, segurar brevemente a resposta, adicionar o IP à regra de tunelamento VPN e então liberar a resposta DNS
- A API REST do pfSense foi instalada, e uma requisição GET para
https://pfsense/api/v1/firewall/aliasfoi enviada para consultar o aliasVPN_domains - Ao explorar o módulo Python do Unbound DNS Resolver, conseguiu-se registrar mensagens de consulta DNS
- A versão atual do Python era 3.8
- Como os exemplos do módulo Python do Unbound eram baseados em Python 2.4, considerou-se que
2to3ou formatação poderiam ser necessários
- O script PoC extraía IPs de registros A/AAAA da resposta DNS e os adicionava ao alias do pfSense
- O registro A era tratado com
ipaddress.IPv4Address(d.rr_data[j][2:]).exploded - O registro AAAA era tratado com
ipaddress.IPv6Address(d.rr_data[j][2:]).exploded - O TTL do alias foi definido como 1 hora, e a capacidade como 500
- O registro A era tratado com
- No dia seguinte, o Unbound DNS Resolver sofreu segfault e, como era preciso recarregar a regra do pfSense toda vez que um IP era adicionado, o pfSense ficou muito lento
Migração do Squid para o mitmproxy
- O novo objetivo mudou para investigar e instalar um proxy da família Squid, criar um certificado de CA falsa confiável e descriptografar o tráfego TLS
- Nos testes com Squid, foi verificado se o proxy
squid3, fornecido como pacote do pfSense, atendia aos requisitos- Foi criada uma pasta exclusiva
/squid_cachee o tamanho do cache foi configurado para 8GiB - Esperava-se suporte a HTTPS transparente
- Foi criada uma pasta exclusiva
- Após um dia configurando Squid e SquidGuard, a tentativa foi abandonada
- A velocidade era muito lenta
- A configuração de ACL era trabalhosa
- Havia um problema relacionado a
https://http/* - A atualização da lista de filtros de URL do SquidGuard demorava muito
- A interface do Squid era insuficiente
- Depois disso, decidiu-se usar o mitmproxy, escrito em Python
- O mitmproxy foi escolhido no lugar do
SSLSplitpor causa da extensibilidade via hooks em Python e da interface - A versão do FreeBSD do pfSense era
12.2-Stable, build 64-bit
- O mitmproxy foi escolhido no lugar do
- No ambiente padrão do pfSense, jail vinha desativado, então o
ezjailfoi instalado manualmente e um jail para omitmproxyfoi criado- O jail foi criado com
ezjail-admin create mitmproxy 'lo0|127.0.1.1' - Para o modo de proxy transparente, foi definido
allow.raw_sockets=1 - Foi observado que, se raw sockets estivessem bloqueados, poderiam ocorrer erros como
Transparent mode failureouCannot open connection, no hostname given.
- O jail foi criado com
- A execução do binário Linux tarball falhou no FreeBSD
- O erro
ELF interpreter /lib64/ld-linux-x86-64.so.2 not foundocorreu - Também não foi possível encontrar
libdl.so.2,libz.so.1,libpthread.so.0,libc.so.6
- O erro
- Dentro do jail, foi executado
pkg install mitmproxy, e a instalação exigiu 50 pacotes, 206MiB de espaço adicional e 33MiB de download - Para permitir acesso ao MITMProxy pela LAN, o IP virtual
127.0.1.1foi anexado ao localhost e uma regra NAT encaminhou temporariamente[Private IPs]:8080para127.0.1.1:8080 - O arquivo PEM da CA gerada automaticamente pelo MITMProxy fica em
~/.mitmproxy/mitmproxy-ca-cert.pem, e esse certificado de CA foi instalado no Trusted Root Store do dispositivo de teste - O
mitmproxyusava muita CPU mesmo em estado ocioso, e concluiu-se que a geração em tempo real de certificados TLS por requisição e o logging excessivo reduziam muito a velocidade- Considerou-se que o
mitmdumpimpunha menos carga à CPU por dispensar a interface e o logging excessivo
- Considerou-se que o
Remoção de anúncios JSON do YouTube na web
- Certificate Pinning é uma técnica em que o servidor ou cliente conhece antecipadamente a fingerprint esperada do certificado, de modo que a falsificação de certificado pelo MITMProxy não funciona
- Hosts problemáticos podem ser configurados para contornar o proxy com a opção
--ignore-hosts- Como exemplo,
apple.com:443eicloud.com:443foram ignorados
- Como exemplo,
- Durante o acesso ao YouTube, anúncios de página apareceram no MITMProxy com cabeçalhos não criptografados, e foi avaliada a possibilidade de bloqueio com regex simples
- Para aplicar o script de bloqueio de anúncios do YouTube, foi adicionado
--scripts "youtube.py"aomitmdump - O filtro de smoke test bloqueava requisições de anúncios com base em substrings de URL
youtube.com:/pagead/,/log_event?,/stats/ads,/stats/qoe?,/ptracking?,/generate_204,el=adunit,adformat=,/activeview?google.com,google.ca:/pagead/ggpht.com:.
- As requisições que se pretendia bloquear de fato pareciam bloqueadas no MITMProxy e no painel Network do DevTools, mas os anúncios ainda apareciam, e às vezes eram pulados sozinhos ou falhavam na reprodução
- Depois disso, foram encontradas várias URLs relacionadas a anúncios dentro do payload JSON
- Incluíam seções
playerAdseplaybackTracking youtubeRemarketingUrlcontinhahttps://www.youtube.com/pagead/viewthroughconversion/...googleRemarketingUrlcontinhahttps://www.google.com/pagead/1p-user-list/...
- Incluíam seções
- Após analisar a UI do YouTube e o fluxo HTTP, incluindo cookies e service workers, afirmou-se que foi possível remover anúncios pre-roll, post-roll e no meio do vídeo
- Nesta etapa, já era possível remover anúncios do payload JSON dos anúncios do YouTube web pelo roteador
Problemas de Protobuf no YouTube para iOS
- O app do YouTube para iOS mostra dados muito parecidos na versão Protobuf da mesma chamada de API da versão web
- No Protobuf, as chaves são números e podem mudar, então não é possível usar uma abordagem de JSONPath para localizar a seção de anúncios
- O YouTube envia uma grande lista de anúncios futuros no payload e, quando essa lista se esgota, outra grande lista chega logo em seguida
- No payload Protobuf, foram vistas strings como “Telus”, “Samsung TV”, “Boxing Week” e “Buy now”
- O protocolo do YouTube no iOS era diferente do tráfego web
- na versão web, era possível distinguir até certo ponto o vídeo de anúncio e o vídeo desejado olhando a URL e o parâmetro de query
range - o protocolo do iOS não usa nem o parâmetro de query
rangenem o headerRange, e usa contadores como&nr=2e&nr=3nos chunks de vídeo - para bloquear anúncios no iOS, foi necessário fazer engenharia reversa da resposta Protobuf
- na versão web, era possível distinguir até certo ponto o vídeo de anúncio e o vídeo desejado olhando a URL e o parâmetro de query
- Na mensagem Protobuf decodificada, foram encontrados os campos
has_unlimited_entitlement: Falseehas_premium_lite_entitlement: False, mas em vez de alterná-los, voltou-se ao uso de heurísticas - Decodificar cerca de 500 KiB de Protobuf bruto com uma implementação pura em Python era muito lento
- em um desktop com i7-6700, o resultado em Python foi de cerca de 2,06~2,11 segundos
- em um roteador pfSense, o resultado em Python foi de cerca de 22,8~24,2 segundos
- o C++
protoc --decode_rawlevou cerca de 0,017~0,022 segundo no desktop e cerca de 0,12~0,14 segundo no roteador pfSense
Tentativas de decodificação de Protobuf e extração de schema
- Como o Python não oferece suporte a decodificação bruta de Protobuf, em vez de usar diretamente
libprotobuf.soem C++, optou-se por se comunicar com o binário C++protocviasubprocess.Popen - Ao fazer fuzzing das respostas de vídeo de anúncio, foram tentados
200,404e503vazios, body de resposta truncado e nulificação parcial do vídeo do anúncio, mas o app do iOS apenas ficava mais lento, travava ou congelava na tela do anúncio - Bloquear URLs disparava reações do app, e os chunks de resposta de vídeo também continham metadados de sessão
- O blackboxprotobuf para Burp Suite permite decodificar mensagens wire Protobuf brutas, injetar conteúdo e depois reencodar para verificar o comportamento do endpoint Protobuf
- recomenda-se usar a versão original do Burp Suite, não o fork do PyPI
- alguns forks têm problemas de stack overflow ou recursão infinita por causa de recursão profunda
- usando bindings em C++, é possível transcodificar cerca de 500 KiB de Protobuf bruto em alguns segundos
- O schema gerado não era perfeito, era grande e profundamente aninhado, e o pretty-print era lento, mas foi suficiente para encontrar detalhes dos anúncios
- Foram testados PBTK, Apktool, dex2jar e Java Decompiler para tentar extrair os arquivos
.protoreais ou arquivos de schema do APK do YouTube para Android- o PBTK extraiu apenas um arquivo proto de 59 bytes
- havia classes Protobuf e getter/setter em Java, mas como não foi possível obter os arquivos de schema reais, essa linha foi abandonada
Ponto de virada final: alteração de 1 byte na tag de campo Protobuf
- A partir do tráfego de rede descriptografado e dos resultados do fuzzing de Protobuf, observou-se que os anúncios eram registrados em slots de um vídeo específico
- os tipos de slot incluem pre-roll, mid-roll, end-roll, full-page e ad pods
- ao bloquear a URL do anúncio, ocorria um erro como “um anúncio inexistente reservou o slot”, causando pânico na UI
- Sem o schema original, ao decodificar, editar e reencodar, sai uma codificação modificada; isso é problemático porque não dá para saber se há uso de ZigZag, nem tipos numéricos como
int32,int64,sint32/64evarint, e a ordem dos campos do objeto geralmente também é não determinística - Encontrou-se uma possibilidade de contorno na compatibilidade retroativa do Protobuf e no comportamento de UnknownFieldSet
- quando um software antigo lê uma mensagem à qual foram adicionados novos campos, podem surgir campos desconhecidos
- ao trocar uma determinada chave de campo por outro valor, toda a subestrutura que contém anúncios e informações de rastreamento pode ficar indisponível
- Como exemplo, propõe-se a ideia de mudar a chave de campo
49399797para49399796, fazendo essa subestrutura de anúncio/rastreamento parecer um campo desconhecido - A chave de campo
49399797não pode ser encontrada com uma simples busca em hex, e é preciso considerar a codificação varint/tag- o wire type é
2, indicando string/mensagem aninhada delimitada por comprimento - a sequência de bytes da tag para a chave de campo alvo
49399797éAA FF B8 BC 01 - removendo os 3 bits do wire type com
395198378 >> 3, obtém-se a chave de campo original49399797
- o wire type é
- Nos bytes do Protobuf, usa-se uma assinatura clássica de URL de anúncio como
/pagead/para delimitar a faixa de busca do campo e, a partir dessa posição, volta-se para encontrar a tag de campo e a chave de campo a serem alteradas - Em um log de interceptação de exemplo, na resposta
application/x-protobufde 1,87 MiB de uma requisição POST parayoutubei.googleapis.com:443/youtubei/v1/browse?key=..., a chave49399797foi encontrada na posição4465e a chave50195462na posição4477 - Em um smoke test O(n), os 1,8 MiB de dados Protobuf foram varridos uma única vez sem memória adicional
- o alvo foi encontrado no byte de número 30.593 entre 1,8 MiB
- com cerca de 600 bytes de backtracking, foi encontrada a chave de campo a ser desnaturada
- Quando esse método passou a funcionar, não foi mais necessário bloquear URLs contendo
*.googleadservices.comou/pagead/, e essas requisições deixaram de ocorrer desde a origem
Estrutura do script add-on do MITMProxy
- O script add-on do MITMProxy é fornecido como uma prova de conceito para bloquear anúncios do YouTube em dispositivos Apple conectados à rede
- O nome do arquivo é
youtube.py - Exemplo de execução:
mitmdump --listen-port 8080 --listen-host 127.0.0.1 -s "youtube.py" - Os pré-requisitos no FreeBSD são
pkg install protobuf,pkg install py38-pip,pip install jsonpath-ng
- O nome do arquivo é
- O script inclui uma função de fairness que permite 5% dos anúncios para apoiar criadores de conteúdo
in_allowed_ads_window()ignora o bloqueio de anúncios quando o horário atual está entre 0 e 2 minutos de cada hora
YouTubeAdBlockerintercepta domínios relacionados ao YouTube e modifica respostas JSON ou Protobuf para remover informações de anúncios- A regex de host interceptado é
\.youtube\.com|google\.(com|ca)|googleapis\.com|googleadservices\.com|googlevideo\.com - A string usada para detectar anúncios em Protobuf é
b"/pagead/" - O limite de busca é
80_000bytes - A tag de campo alvo é
50195462
- A regex de host interceptado é
- A lista de bloqueio na etapa de requisição inclui
pagead/,log_event?,stats/ads,stats/qoe?,ptracking?,generate_204,error_204,adformat=,activeview?,_ad_,ai?,sw.jse outros em hosts do YouTube - A substituição de JSON para o YouTube na web remove ou desativa campos relacionados a anúncios
yt_adé alterado para"0"adPlacementsé alterado para[]adPlacementRenderer,adPlacementConfig,playerAdParams,gutParamssão alterados para{}adVideoIdé alterado para""showCompanion,showInstream,useGutsão alterados paraFalse
- O hook
load()desativa HTTP/2 e defineanticomp=True,mode="transparent" - O hook
running()atualizaallow_hostspara que a interceptação se aplique apenas a domínios relacionados ao YouTube - O hook
response()procura/pagead/nos primeiros 80.000 bytes do corpo da resposta quandocontent-typecontémprotobuf- Se encontrar, cria os bytes da tag alvo com
TagBytes(self.target_field_tag, WIRETYPE_LENGTH_DELIMITED) - Cria novos bytes de tag para
target_field_tag - 1 - Faz uma busca reversa antes da posição de
/pagead/para localizar a tag alvo - Substitui os bytes nessa posição pelos bytes correspondentes a
target_field_tag - 1 - Reinsere o conteúdo Protobuf modificado com
flow.response.set_content(bytes(body))
- Se encontrar, cria os bytes da tag alvo com
- Os comentários no código afirmam que esse PoC já bloqueia 90% dos anúncios e acrescentam que outras seções também podem ter outras chaves de campo e várias seções de anúncios a serem neutralizadas
Desempenho, limitações e público-alvo
- A técnica final aproveita o fato de o Protobuf permitir campos desconhecidos para manter compatibilidade retroativa em mudanças de schema, além da sensibilidade a edição de um único byte do formato compacto
- Ao alterar 1 byte em um ponto crítico para que uma seção profundamente aninhada pareça pertencer a uma versão futura do schema, o Protobuf a ignora e assim pode remover as informações de anúncios
- O Google retorna uma grande resposta Protobuf que inclui até o layout do app iOS, e o payload de exemplo tem 1.8MiB
- Para fazer parse do payload inteiro seria necessário código nativo como C++/Swift, e a decodificação em Python seria várias ordens de magnitude mais lenta, causando timeout de conexão
- O JSON baseado na web exige parse, edição e reserialização do payload inteiro, mas a técnica com Protobuf faz apenas uma varredura linear e um backtrack rápido, então processa em microssegundos, sendo adequada para bloqueio de anúncios em tempo real e sem precisar de blocklist
- Todas as URLs
*.googleadservices.come/pagead/*em dispositivos Apple vêm do payload Protobuf, então, quando os dados de anúncios desaparecem do payload, essas requisições também desaparecem automaticamente - O app do YouTube não tenta buscar as URLs de anúncios, então parece mais rápido, e como o anúncio não é registrado no slot de vídeo, o conteúdo começa a reproduzir imediatamente
- Esse método é apresentado como uma técnica altamente especializada para bloquear anúncios do YouTube em dispositivos Apple ou tráfego de rastreamento do Instagram, WhatsApp e Facebook
- Diz-se que a carga de CPU para descriptografar e recriptografar tráfego HTTPS supera em muito a capacidade de um Raspberry Pi
- Como o alvo são donos de dispositivos Apple que não querem comprometer o sistema operacional, considera-se que o público é ainda mais restrito
YouTube Premium e experimento sobre o custo dos anúncios
- O autor considera incerto se o preço do YouTube Premium, de CAD $9.99/mês ou CAD $11.99/mês e cerca de CAD $13.43/mês com impostos, é razoável
- Foi feito um experimento de exposição a anúncios assistindo YouTube de forma intermitente durante um dia com um notebook limpo e navegação privada
- No histórico de exibição, havia apenas 10 vídeos “assistidos”
- Durante a visualização de partes desses 10 vídeos, houve exposição a 8 anúncios
- Apenas 2 anúncios eram puláveis, e ambos foram pulados
- Assumindo um CPV aproximado de USD $0.15, 8 anúncios por dia representam um custo para os anunciantes de
8 x $0.15 = $1.20; extrapolando para um mês, isso dá cerca de USD $36/mês - Também é apresentado um cálculo com base em dados da Statista, dividindo o gasto com publicidade nos EUA pelo total de visualizações
- Em 2019, anunciantes dos EUA gastaram $15.1 billion no YouTube
- Residentes dos EUA teriam assistido a 916 billion vídeos
- A média é
$15.1B / 916B = USD $0.0165 per view - No caso do autor, isso equivaleria a cerca de USD $0.13 por dia e cerca de USD $3.96 por mês em custo para anunciantes
- Durante o experimento com anúncios, o autor deixou o hardware no mudo e desviou o olhar com frequência, então considera que o dinheiro gasto com anúncios exibidos para ele foi desperdiçado
- Ainda assim, diz querer apoiar os criadores e que vai testar o trial de 3 meses do Premium, enquanto continua monitorando o que o Google rastreia sobre ele
- Ele também manifesta preocupação de que, a partir do momento em que uma reivindicação DMCA é registrada, toda a receita de anúncios possa ir para o reclamante em vez do criador, acrescentando que não surpreende que muitos criadores migrem para o Patreon
Resumo final
- Configurou um roteador de hardware desde o início e separou a LAN em zonas confiáveis/não confiáveis
- Configurou o bloqueio tradicional de anúncios por DNS
- Adicionou um proxy MITM transparente
- Por fim, conseguiu bloquear anúncios do YouTube com bom desempenho em dispositivos Apple conectados à rede
- Escreve que, como a parte difícil acabou, vai considerar assinar o YouTube Premium, embora os rastreadores continuem sendo fortemente bloqueados
1 comentários
Opiniões no Hacker News
Mais do que uma falha no formato Protobuf, parece que o autor mudou o número do campo para um número alto não usado
O método consiste em procurar, nos bytes Protobuf, assinaturas de URLs de anúncios como
/pagead/para delimitar o intervalo do campo e, dali, voltar para encontrar a tag do campo-alvo e a chave do campo para neutralizá-lo; isso parece mais um comportamento intencional do que uma falhaSe você vai fazer o esforço de encontrar a tag, ler o comprimento varint logo ao lado e pular aqueles bytes também não é um grande trabalho extra. Seria preciso copiar o buffer ou deslocar bytes, mas o script PoC também já precisa copiar, porque os
bytesretornados pela API do mitmproxy são imutáveisAntes de mudar o protocolo a ponto de fazer anúncios deixarem de aparecer em todas as versões antigas do app, o Google vai distribuir um app novo primeiro; então apenas uma fixação de certificado básica ou uma decodificação menos tolerante a falhas na extração de informações de anúncios já bastaria para bloquear esse método imediatamente. A equipe do YouTube provavelmente veria isso como uma falha
bytessão imutáveis, mas objetosbytearraynão sãoUm pequeno proxy em C++/Go também conseguiria fazer a mesma coisa com muito menos overhead. Para uma tarefa tão bem definida, é mais estável e dá menos trabalho do que brigar com o mitmproxy
Enviar todo o tráfego pelo proxy degrada o desempenho, mesmo usando interceptação de SNI. O pfSense também; com um servidor Linux simples e algumas regras simples de iptables, dá para resolver sem lutar contra as camadas de abstração do pfSense
Basta escrever em um arquivo
.protosó o necessário dos campos proto obtidos por engenharia reversa, gerar o código automaticamente e mudar a flag. É mais barato que uma implementação em Python e mais fácil de atualizar se o proto mudar. Ignorar tags de campos desconhecidos é um recurso importante do Protobuf e permite mudanças de schema compatíveis sem quebrar implantações existentesO autor parece já ter percebido boa parte do que está nos comentários, e o texto é bem minucioso. Ele fez benchmarks em Python e C++, e a implementação final nem sequer decodifica Protobuf. Também testou várias soluções mitm, e o pfSense é usado não como um simples roteador de segurança, mas para mirar apenas o tráfego da Apple TV com VLAN e VPN
Este comentário soa barato e depreciativo demais. O post original não é assim; se vai falar desse jeito, deveria provar por conta própria em benefício da comunidade
Se eu pagar pelo YouTube Premium, estou apoiando os criadores? Se sim, queria saber quanto, em comparação com um apoio direto como Patreon
A receita que uma assinatura do YouTube Premium gera para um criador individual deve ser pequena, mas ainda é melhor do que assistir aos vídeos com bloqueador de anúncios
Como o critério é tempo de exibição, e não impressões de anúncios, criadores que fazem conteúdo de formato longo levam vantagem
A conta do YouTube da minha namorada, estranhamente, não mostra anúncios em nenhum dispositivo em que ela faça login. Inclui Apple TV; ela não tem Premium e nunca teve
Fico curioso se alguma flag interna foi definida e desativou os anúncios
Só então veio aquele momento de entender por que as pessoas reclamavam
Mesmo sem usar bloqueador de anúncios, quando faço login não aparecem anúncios em lugar nenhum, nem no site nem no app móvel. Não tenho Twitch Turbo e também não tenho mais Amazon Prime. Também não tenho outros benefícios do Turbo, então não é como se minha conta estivesse totalmente marcada como Turbo
Talvez, quando eu fazia bug bounty e mexia em várias coisas, o perfil da conta tenha sido corrompido por acaso; não sei. Mas, se mantiverem esse benefício, posso até fornecer mais detalhes
O estranho é que eu me lembro de uma vez, no hospital, dopado de remédios e com dor, só querendo ver TV, e fiquei quase em colapso porque os anúncios do Twitch eram insuportáveis. Então, um ou dois anos depois, percebi de repente que não via anúncios havia anos
Provavelmente existe um teste A/B sem anúncios esquecido há muito tempo, que ficou porque não vale a pena limpar. Isso me beneficiou por anos, e assisto ao Twitch mais do que qualquer outra plataforma. O Twitch Turbo no Reino Unido custa £12 por mês, cerca de US$ 15,50, o que é caro até em escala global; comparado aos US$ 12/€12 dos EUA e da Europa, é um preço bem desvantajoso
Foi bem surpreendente perceber que, ao colocar um proxy man-in-the-middle entre a Apple TV e a internet externa, dá para descriptografar o tráfego HTTPS
Eu achava que isso normalmente não deveria funcionar, e depois fiquei surpreso de novo ao descobrir que era possível adicionar uma CA ao repositório de certificados da Apple TV. Foi um texto minucioso, cobrindo a pilha inteira
Por exemplo, em universidades, para conectar um dispositivo ao Wi-Fi era preciso colocar o endereço MAC em uma lista de permissões ou instalar um certificado
Só que, se fizesse isso, o YouTube poderia quebrar em muitos ambientes corporativos, então não sei se realmente fariam. Ainda assim, infelizmente, seria muito fácil bloquear
Tentei implementar isso algumas vezes na Apple TV, mas nunca consegui. Parece que agora o YouTube colocou certificate pinning no app, ou algo do tipo. Fico curioso se alguém conseguiu fazer isso funcionar recentemente
[0] https://frida.re/docs/home/
Gosto de qualquer tentativa de bloquear na rede inteira serviços online ruins que somos meio forçados a usar
Bloquear anúncios é ótimo, mas eu gostaria que houvesse formas mais fáceis e mais amplas de bloquear na rede inteira aqueles scrolls infinitos agressivos, como YouTube Shorts ou Instagram Reels
No Instagram, eu só quero ver posts e stories das pessoas que sigo, sem receber recomendações de vídeos idiotas projetados para capturar minha atenção. Talvez isso revele falta de força de vontade, mas com frequência acabo vendo alguns e perco 15 minutos da minha vida
Usuários da internet, em geral, escolheram o lado de não querer pagar, então alguém acaba arcando com o custo. No geral, usuários da internet não recompensam quem não mostra anúncios. Querem conteúdo, mas geralmente querem de graça
Encontrei um script que transforma a página do Instagram em algo parecido com uma simples tag de imagem, permitindo ver só as fotos: https://greasyfork.org/en/scripts/5014-un-instagram
Então, mais do que falta de força de vontade, parece algo mais próximo de uma dessensibilização que fomos acumulando, e isso é bem ruim. O esforço e a criatividade para fazer com que nós voltemos a usar as plataformas, em vez de as plataformas nos fazerem usá-las, merecem respeito
Converso regularmente com meus filhos, e eles também concordam que é prejudicial, mas acham difícil demais resistir. Até eu às vezes sou puxado para o doomscrolling
Configurei filtragem de anúncios com Pi-hole onde é possível, mas não quero bloquear o YouTube inteiro. Ainda assim, para proteger a família, acho que vou considerar isso seriamente daqui para frente
A engenharia é boa, mas é um pouco triste ter que ir tão longe só para usar seu próprio hardware ou software como se você o possuísse em alguma medida
O YouTube tem anúncios? O navegador bloqueia tão bem que eu nem sabia
O verdadeiro problema é que a experiência na Apple TV é muito pior do que a de um navegador web comum. A Apple tranca tanto o hardware que a estrutura acaba beneficiando mais a receita de anúncios do YouTube do que o consumidor final que pagou pelo aparelho
O mesmo vale quando navego na web pelo iPad fora da rede com Pi-hole de casa. Não sei como as pessoas suportam isso todos os dias
O iPad é um dispositivo fornecido pelo trabalho, então não o uso muito para fins pessoais, mas toda vez que uso, lembro como isso é irritante
Curiosamente, antes de receber o iPad, eu achava que ele só seria útil para consumo de conteúdo; na prática, ele é muito conveniente para acessar rapidamente recursos de trabalho remotamente, mas, para navegação web comum e mídia em streaming, virou um aparelho preso em um deserto coberto de anúncios
Se você precisa de YouTube sem anúncios, pode usar https://yewtu.be ou outra instância do Invidious: https://docs.invidious.io/instances/
Há uma corrida armamentista entre YouTube e Invidious, e às vezes o Invidious não funciona, mas a equipe sempre encontrou novas formas de contornar o YouTube e entregar vídeos sem anúncios