
Laboratorio di ricerca sulla sicurezza: riproduzione di CVE-2025-61584 (GHSA-9g7x-737f-5xpc) — iniezione di comandi tramite github.head_ref nel workflow pull_request_target (.github/workflows/pr.yml)
Artefatto di ricerca automatizzato — non il progetto upstream.
Questo repository è un laboratorio usa e getta costruito da un sistema automatizzato per una tesi magistrale presso l'Université Laval sulla riproduzione di vulnerabilità pubblicate nei workflow di GitHub Actions. È uno snapshot integrale di
serverless-dns/serverless-dnsal commitb0b1a1538aeb1991b5bc13dfe4e18e686913b12e(2025-04-26), ridistribuito sotto la licenza di quel progetto, il cui file è incluso invariato in questo snapshot.Il progetto upstream non è coinvolto, non è mai preso di mira, e la vulnerabilità studiata qui è già pubblica. Ogni segreto e variabile in questo repository è un valore fittizio generato casualmente — nessuna credenziale reale è presente. I riferimenti alle action e le immagini dei runner sono bloccati a ciò a cui risolvevano il 2025-04-26; vedi
pinning.mdnell'output del sistema per ogni modifica apportata allo snapshot.Domande o obiezioni: [email protected]
serverless-dns è un resolver DNS-over-HTTPS (DoH) e DNS-over-TLS (DoT) stub, serverless, con blocco dei contenuti stile Pi-Hole. Funziona out-of-the-box su Cloudflare Workers, , e . I piani gratuiti di tutti questi servizi dovrebbero essere sufficienti a coprire il traffico DNS di 10-20 dispositivi al mese.
RethinkDNS esegue serverless-dns in produzione su questi endpoint:
L'elaborazione lato server richiede da 0 millisecondi (ms) a 2ms (mediana), e la latenza end-to-end (varia in base a regioni e reti) è tra 10ms e 30ms (mediana).
Il resolver Rethink DNS su Fly.io è sponsorizzato da FOSS United.
Cloudflare Workers è la piattaforma più semplice su cui configurare serverless-dns:
Per istruzioni passo-passo, fai riferimento a:
| Piattaforma | Difficoltà | Runtime | Documentazione |
|---|---|---|---|
| ⛅ Cloudflare | Facile | v8 Isolates | Hosting su Cloudflare Workers |
| 🦕 Deno.com | Moderata | Deno Isolates | Hosting su Deno.com |
| ⏱️ Fastly Compute@Edge | Facile | Fastly JS | Hosting su Fastly Compute@Edge |
| 🪂 Fly.io | Difficile | Node MicroVM | Hosting su Fly.io |
Per configurare le blocklist, visita https://<my-domain>.tld/configure dal tuo browser (dovrebbe caricare qualcosa di simile alla pagina configure di RethinkDNS).
Per aiuto o assistenza, sentiti libero di aprire un issue o inviare una patch.
Codice:
# navigate to work dir
cd /my/work/dir
# clone this repository
git clone https://github.com/serverless-dns/serverless-dns.git
# navigate to serverless-dns
cd ./serverless-dns
Node:
# install node v22+ via nvm, if required
# https://github.com/nvm-sh/nvm#installing-and-updating
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install --lts
# download dependencies
npm i
# (optional) update dependencies
npm update
# run serverless-dns on node
./run n
# run a clinicjs.org profiler
./run n [cpu|fn|mem]
Deno:
# install deno.land v2+
# https://github.com/denoland/deno/#install
curl -fsSL https://deno.land/install.sh | sh
# run serverless-dns on deno
./run d
Fastly:
# install node v22+ via nvm, if required
# install the Fastly CLI
# https://developer.fastly.com/learning/tools/cli
# run serverless-dns on Fastly Compute@Edge
./run f
Wrangler:
# install Cloudflare Workers (cli) aka Wrangler
# https://developers.cloudflare.com/workers/cli-wrangler/install-update
npm i wrangler --save-dev
# run serverless-dns on Cloudflare Workers (cli)
# Make sure to setup Wrangler first:
# https://developers.cloudflare.com/workers/cli-wrangler/authentication
./run w
# profile wrangler with Chrome DevTools
# blog.cloudflare.com/profiling-your-workers-with-wrangler
I commit su questo repository applicano la guida allo stile JavaScript di Google (rif: .eslintrc.cjs).
Un hook git pre-commit esegue il linter (eslint) e il formatter (prettier) sui file .js. Usa git commit --no-verify
per bypassare questo hook.
Le pull request vengono anche controllate per violazioni dello stile del codice e corrette automaticamente dove possibile.
Configura env.js se devi modificare le impostazioni predefinite.
Per Cloudflare Workers, configura le variabili d'ambiente in wrangler.toml, invece.
Per Fastly Compute@Edge, configura le variabili d'ambiente in fastly.toml, invece.
serverless-dns supporta l'autenticazione con un token bearer alfanumerico sia per DoH che per DoT. Per un token, msg-key (segreto), aggiungi l'output di hex(hmac-sha256(msg-key|domain.tld), msg) alla variabile d'ambiente ACCESS_KEYS in formato csv. Nota: msg è attualmente fisso su sdns-public-auth-info.
msg-key alla fine del blockstamp, in questo modo:
1:1:4AIggAABEGAgAA:<msg-key> (qui, 1 è la versione, 1:4AIggAABEGAgAA
è il blockstamp, <msg-key> è il segreto di autenticazione, e : è il delimitatore).msg-key alla fine dell'SNI (nome di dominio) contenente il blockstamp:
1-4abcbaaaaeigaiaa-<msg-key> (qui 1 è la versione, 4abcbaaaaeigaiaa
è il blockstamp, <msg-key> è il segreto di autenticazione, e - è il delimitatore).Se l'intenzione è usare l'autenticazione anche con DoT, mantieni il msg-key più corto (da 8 a 24 caratteri), poiché i sottodomini possono essere lunghi al massimo 63 caratteri in totale.
Puoi generare le chiavi di accesso per il tuo fork da max.rethinkdns.com, in questo modo:
msgkey="ShortAlphanumericSecret"
domain="my-serverless-dns-domain.tld"
curl 'https://max.rethinkdns.com/genaccesskey?key='"$msgkey"'&dom='"$domain"
# output
# {"accesskey":["my-serverless-dns-domain.tld|deadbeefd3adb33fa2bb33fd3eadf084beef3b152beefdead49bbb2b33fdead83d3adbeefdeadb33f"],"context":"sdns-public-auth-info"}
serverless-dns può essere configurato per caricare i log tramite Cloudflare Logpush.
CF_ACCOUNT_ID=<hex-cloudflare-account-id>
CF_API_KEY=<api-key-with-logs-edit-permission-at-account-level>
R2_BUCKET=<r2-bucket-name>
R2_ACCESS_KEY=<r2-access-key-for-the-bucket>
R2_SECRET_KEY=<r2-secret-key-with-read-write-permissions>
# optional, setup a filter such that only logs form this worker ends up being pushed; but if you
# do not need a filter on Worker name (script-name), edit the "filter" field below accordingly.
SCRIPT_NAME=<name-of-the-worker-as-in-wrangler-toml>
# for more options, ref: developers.cloudflare.com/logs/get-started/api-configuration
# Logpush API with cURL: developers.cloudflare.com/logs/tutorials/examples/example-logpush-curl
# Available Logpull fields: developers.cloudflare.com/logs/reference/log-fields/account/workers_trace_events
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/logpush/jobs" \
-H "Authorization: Bearer ${CF_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"name": "dns-logpush",
"logpull_options": "fields=EventTimestampMs,Outcome,Logs,ScriptName×tamps=rfc3339",
"destination_conf": "r2://'"$R2_BUCKET"'/{DATE}?access-key-id='"${R2_ACCESS_KEY}"'&secret-access-key='"${R2_SECRET_KEY}"'&account-id='"{$CF_ACCOUNT_ID}"',
"dataset": "workers_trace_events",
"filter": "{\"where\":{\"and\":[{\"key\":\"ScriptName\",\"operator\":\"contains\",\"value\":\"'"${SCRIPT_NAME}"'\"},{\"key\":\"Outcome\",\"operator\":\"eq\",\"value\":\"ok\"}]}}",
"enabled": true,
"frequency": "low"
}'
logpush = true in wrangler.toml, che abilita Logpush.LOG_LEVEL = "logpush", che alza il livello di log in modo che vengano emessi solo i log di richiesta e di errore.LOGPUSH_SRC = "csv,of,subdomains", che fa sì che log-pusher.js emetta log di richiesta solo se l'hostname dei Workers contiene uno dei sottodomini.I log pubblicati su R2 possono essere recuperati usando le R2 Workers, l'API R2, o l'API Logpush.
Workers Analytics, se abilitato, viene inviato contro una log-key, lid, che se non specificata è impostata all'hostname della distribuzione serverless con i punti, ., sostituiti da underscore, _. L'autenticazione deve essere configurata quando si interrogano le Analytics tramite l'API che restituisce un json; es: https://max.rethinkdns.com/1:<optional-stamp>:<msg-key>/analytics?t=<time-interval-in-mins>&f=<field-name>. I possibili fields sono ip (ip del client), qname (nome della query DNS), region (regione del resolver), qtype (tipo di query DNS), dom (domini di primo livello), ansip (ip delle risposte DNS) e cc (codici paese degli ip delle risposte).
La cattura dei log e le analytics non sono ancora implementate per Fly e Deno Deploy.
Deno Deploy (cloud) e Deno (il runtime) non espongono la stessa superficie API (per esempio, Deno Deploy supporta solo listener HTTP/S; mentre Deno supporta TCP/UDP/TLS grezzi oltre a HTTP semplice e HTTP/S).
Tranne su Node, serverless-dns usa upstream DoH definiti dalle variabili d'ambiente CF_DNS_RESOLVER_URL / CF_DNS_RESOLVER_URL_2.
Su Node, l'upstream DNS predefinito è 1.1.1.2 (rif) o il resolver DNS ricorsivo su fdaa::3 quando si esegue su Fly.io.
Gli entrypoint per Node e Deno sono rispettivamente src/server-node.js e src/server-deno.ts,
ed entrambi ascoltano connessioni TCP-over-TLS e HTTP/S; mentre l'entrypoint per Cloudflare Workers, che ascolta solo su HTTP (cli) o
su HTTP/S (prod), è src/server-workers.js; e per Fastly è src/server-fastly.js.
Le configurazioni locali (non-prod) su Node, i file key (privata) e cert (catena pubblica), per impostazione predefinita, vengono letti dai
percorsi definiti nelle variabili d'ambiente TLS_KEY_PATH e TLS_CRT_PATH.
Mentre per la configurazione di produzione su Node (su Fly.io), TLS_OFFLOAD deve essere impostato su true oppure key e cert devono essere
codificati in base64 nella variabile d'ambiente TLS_CERTKEY (rif), in questo modo:
# EITHER: offload tls to fly.io and set tls_offload to true
TLS_OFFLOAD="true"
# OR: base64 representation of both key (private) and cert (public chain)
TLS_CERTKEY="KEY=b64_key_content\nCRT=b64_cert_content"
Per Deno, i file key e cert vengono letti dai percorsi definiti nelle variabili d'ambiente TLS_KEY_PATH e TLS_CRT_PATH (rif).
L'avvio del processo è diverso per ciascuno di questi runtime: per Node, src/core/node/config.js governa l'avvio;
mentre per Deno è src/core/deno/config.ts, e per Workers è src/core/workers/config.js.
src/system.js pub-sub coordina la fase di avvio tra i vari moduli.
Su Node e Deno, la cache DNS in-process è supportata da @serverless-dns/lfu-cache; Cloudflare Workers è supportato sia dalla Cache Web API che
dalle cache lfu in-process. Per disabilitare completamente la cache su tutte e tre le piattaforme, imposta la variabile d'ambiente PROFILE_DNS_RESOLVES=true.
Cloudflare Workers e Deno Deploy sono effimeri, nel senso che il "processo" che serve le richieste dei client non è di lunga durata, e infatti due richieste consecutive possono essere servite da due isolates ("processi") diversi. Fastly Compute@Edge è anch'esso effimero ma non usa isolates; invece Fastly crea e distrugge una sandbox wasmtime per ogni richiesta. Il resolver su Fly.io, che esegue Node, è supportato da VM persistenti ed è quindi di durata più lunga, come gli ambienti tradizionali "serverfull".
Per Deno Deploy, il code-base viene raggruppato in un singolo file javascript con deno bundle e poi consegnato
a Deno.com.
Le configurazioni di build-time e runtime di Cloudflare Workers sono definite in wrangler.toml.
Webpack5 raggruppa i file in un modulo ESM che viene poi caricato su Cloudflare da Wrangler.
Le configurazioni di build-time e runtime di Fastly Compute@Edge sono definite in fastly.toml.
Webpack5 raggruppa i file in un modulo ESM che viene poi compilato in WASM da npx js-compute-runtime
e successivamente impacchettato e pubblicato su Fastly Compute@Edge con la Fastly CLI.
Per Fly.io, che esegue Node, le direttive runtime sono definite in fly.toml (usato dai tipi di distribuzione dev e live),
mentre le direttive di deploy sono in node.Dockerfile. flyctl configura di conseguenza
serverless-dns sull'infrastruttura di Fly.io.
# build and deploy for cloudflare workers.dev
npm run build
# usually, env-name is prod
npx wrangler publish [-e <env-name>]
# bundle, build, and deploy for fastly compute@edge
# developer.fastly.com/reference/cli/compute/publish
fastly compute publish
# build and deploy to fly.io
npm run build:fly
flyctl deploy --dockerfile node.Dockerfile --config <fly.toml> [-a <app-name>] [--image-label <some-uniq-label>]
Per i deploy che scaricano la terminazione TLS su Fly.io (tipo di distribuzione B1), le direttive runtime sono invece definite in
fly.tls.toml, che configura HTTP2 Cleartext e HTTP/1.1 sulla porta 443, e DNS su TCP sulla porta 853.
Rif: github/workflows.
190+ blocklist sono compresse in un Succinct Radix Trie (basato sull'implementazione di Steve Hanov) con modifiche
per velocizzare la ricerca di stringhe (lookup) a scapito della "succintness". Le blocklist sono versionate
con timestamp unix (definito in src/basicconfig.json scaricato da pre.sh), che viene generato una volta a settimana, ma vorremmo generarlo quotidianamente / ogni ora,
se possibile vedi), e ospitate su Cloudflare R2 (variabile d'ambiente: CF_BLOCKLIST_URL).
serverless-dns scarica 3 file di blocklist
necessari per configurare il radix-trie durante l'avvio del runtime oppure li scarica lazily,
quando serve una richiesta DNS.
serverless-dns compila circa ~13M di voci (a gennaio 2023) da circa 190+ blocklist. Queste sono definite nel repository serverless-dns/blocklists.