
Documentazione e reverse engineering di reCAPTCHA
Questo repository contiene un'analisi tecnica dell'antibot di Google (reCAPTCHA) concentrandosi su:
@g_recaptcha@lyxlobyxreCAPTCHA è uno dei sistemi anti-bot con le tecniche di offuscamento più sofisticate, impiegando una serie di trasformazioni che rendono il codice meno leggibile e più difficile da reverse engineering. La maggior parte degli offuscamenti può essere facilmente manipolata utilizzando l'Abstract Syntax Tree (AST), ma alcuni vengono elaborati a runtime, rendendo l'AST inutile in questo caso. Il polimorfismo viene anche applicato al codice per cambiarne la struttura in ogni versione dello script. Ad esempio, il codice non esegue l'azione direttamente. Invece, utilizza oggetti o funzioni che cambiano forma.
Sequence Expressions
Il codice viene appiattito convertendo ogni blocco di istruzioni in un'espressione continua separata da virgole; può apparire in istruzioni if, argomenti di funzioni e persino all'interno di oggetti.

Aritmetica booleana mista
Intreccia operazioni aritmetiche (addizione, sottrazione, moltiplicazione) con operazioni bitwise (AND, OR, XOR, NOT) per nascondere la logica originale, ad esempio -2 * ~(h & H) + -2 + (h ^ H)
Tabella di funzioni indiretta
Ogni funzione è costruita all'interno di una tabella e viene chiamata usando il suo indice, come functions[index](https://github.com/elyelysiox/recaptcha/blob/HEAD/args)
Array di costanti inline Un array letterale locale viene assegnato inline, a metà espressione; l'array raggruppa costanti (numeri, stringhe) che vengono riutilizzate in tutto il corpo della funzione tramite accesso per indice.
// b = [14, 1, "call"] assegnato inline all'interno di un'espressione sequenziale
function(Y, Q, c, l, G, X, W, J, b, P) {
(Y & 94) == Y && (b = [14, 1, "call"], ...)
W[b[2]](J, G) // W.call(J, G)
Y >> b[1] & b[0] // Y >> 1 & 14
}
Multiplexing di funzioni Più funzioni logicamente distinte vengono unite in una sola, utilizzando un parametro numerico come selettore di blocco. Il blocco attivo viene determinato valutando il parametro rispetto a condizioni bitwise. I chiamanti passano un letterale numerico come selettore.
function(N, y, U, Y, h, H, m, C, u) {
C = [26, 47, 6];
// blocco 1
if ((N - 2 ^ 14) < N && (N - C[2] | 28) >= N) {
// logica di conversione del valore in stringa
}
// blocco 2
if ((N + 4 & 40) >= N && (N + 5 & C[0]) < N) {
Y = bB();
throw Error(Y === void 0 ? "unexpected value " + U + y : Y);
}
return u;
}
Ramificazione con operatori logici Sostituisce i blocchi if e if/else con la valutazione short-circuit degli operatori logici, convertendo il flusso di controllo in espressioni. Combinato con le sequence expressions, più rami appaiono come un'unica espressione continua separata da virgole.
// if (a) { blocco }
a && (blocco)
// if (!a) { blocco }
a || (blocco)
// if (a) { x } else { y }
a ? x : y
// combinato con CFF e sequence expressions:
(Y | 1) & 14 || (c = Q.O, J = c.O.length + c.g.length),
(Y ^ 59) >> 3 == 3 && (Q.classList
? Q.classList.add(c)
: Z[31](31, Q, c) || (l = f[0](84, "string", "", Q), ...)),
Costanti di metodi nativi bind Lega i metodi nativi del browser ai loro ricevitori originali, memorizzandoli come costanti per prevenire manomissioni.
LO = (Tw = self) == null ? void 0 :
(K9 = Tw.Math) == null ? void 0 :
(v4 = K9.floor) == null ? void 0 :
(mF = v4.bind) == null ? void 0 :
mF.call(v4, Math) // Math.floor.bind(Math)
LO(x) // Math.floor(x)
U4() // Math.random()
Ge(obj, prop) // Object.defineProperty(obj, prop)
Codice morto Blocchi di codice inaccessibili o inutilizzati vengono iniettati in tutto il file, aumentandone le dimensioni a oltre 60.000 righe; questo rende difficile l'analisi statica e il reverse engineering basato su LLM.
Appiattimento del flusso di controllo (CFF) Trasforma ogni parte del codice (dichiarazioni e cicli) in una macchina a stati piatta. Nasconde la logica di esecuzione originale instradando tutti i blocchi di codice attraverso un blocco "dispatcher" centrale.
I dispatcher possono cambiare forma; alcuni hanno 2-3 variabili di stato e il tipo di ciclo/condizione cambia. Appaiono così:

Questo è un CFF con 2 variabili di stato: una gestisce il blocco catch e l'altra il blocco try.
Pool di stringhe crittate Tutti i letterali stringa (API DOM, proprietà del browser, valori CSS, messaggi di errore, ecc.) sono crittati in un unico enorme pool di stringhe. Una funzione di decifratura utilizza un seed e un cifrario XOR basato su LCG per estrarre ogni stringa a runtime.
Ci sono oltre 1990 siti di chiamata sparsi nel codice; la funzione di decifratura utilizza una chiave corrente che accumula i codepoint decodificati, rendendo ogni carattere dipendente da tutti i precedenti.
X = function(J, b, P, F, U) {
U = ["codePointAt", 127, "pool crittato di caratteri"];
for (F = (P = 0, b = "", l); P < Q; P++)
J = (U[2][U[0]](c + P) ^ F) & U[1], // XOR con chiave corrente
b += String.fromCodePoint(J),
F += J; // accumula chiave
return G = b;
}
// i siti di chiamata passano un seed per individuare e decifrare ogni stringa
Z[23](64, 4, 54961, 103)() // → "lang"
Z[23](66, 4, 54961, 103)() // → "addEventListener"
Z[23](32, 12, 20287, 852)() // → "inline-block"

Iteratore di valori stateful reCAPTCHA utilizza una funzione stateful che restituisce una sequenza di oggetti runtime e valori (come window, document.body, costanti numeriche) in un ordine fisso; ogni chiamata fa avanzare un cursore interno. Chiamarlo fuori sequenza o troppe volte corrompe tutte le letture successive. Un meccanismo di timeout invalida lo stato dopo un intervallo fisso, restituendo null per qualsiasi lettura tardiva.
// chiamate sequenziali restituiscono valori diversi:
c() // → window
c() // → document.body
c() // → 123
c() // → null (timeout scaduto)
l(c(), G[2], G[W[1]], G[1]) + l(c(), G[2], G[W[1]], 12)
// ↑ window ↑ window
10 * l(c(), G[2], G[W[1]], G[1]) + l(c(), G[2], G[W[1]], 12))
c().querySelectorAll(a[X[2]](98, X[1], X[1]))
// ↑ document.body
Tabella di funzioni calcolate
Simile a Tabella di funzioni indiretta, ma qui l'indice della funzione da ottenere viene calcolato a runtime con un seed, usando XOR e Modulo.
c = ((Q ^ no | U[1]) >> 5) + no
A = mN[(c % U[2] + U[2]) % U[2]] // mN è la tabella delle funzioni (50+ funzioni)
q[29](5, 6977) // seed=6977 → l'indice risolve nella funzione in mN[X]
q[29](53, 6187) // seed=6187 → indice diverso, funzione diversa

Crittografia runtime dei valori
Alcuni valori (parametri di configurazione del captcha, parametri dell'ancora, ecc.) non vengono mai memorizzati in testo chiaro; vengono crittati immediatamente dopo la raccolta e decifrati solo al momento dell'uso. Hanno un prefisso B all'inizio.

Offuscamento del flusso di controllo asincrono La logica sincrona viene convertita in macchine a stati basate su generatori racchiuse in catene ricorsive di Promise. Tracciare qualsiasi valore tramite il debugger costringe a passare attraverso più gestori asincroni, perdendo il contesto di esecuzione originale ad ogni confine .then().
Componenti per inizializzare reCAPTCHA``` ar: <WidgetInit?> k: co: hl: v: size: sa: anchor-ms: execute-ms: cb:
### Response
La risposta contiene:
- Design della finestra iframe del CAPTCHA
- Token anchor utilizzato per la convalida del payload (/reload)
- La configurazione principale per l'inizializzazione, eseguita nel metodo `recaptcha.anchor.Main.init` per riceverla in recaptcha_en.js
### Struttura:
Nota: Recaptcha BotGuard è stato rimosso il `04/01/2026`, puoi vedere alcuni esempi [qui](https://github.com/elyelysiox/recaptcha-payload/tree/main/botguard_scripts)```javascript
[
"ainput",
[
"bgdata",
"",
"LyogQW50aS1zcGFtLiBXYW50IHRvIHNheSBoZWxsbz8gQ29ud...", // BotGuard Script Base64-Encoded
"YWVtZ0h5MGNCWXJDQ2lidGh0RW13RmhWdlc3aU5yeVpzSmx6U...", // BotGuard VM Bytecode Double Base64-Encoded
"wrB8fsOVU8K0YAzDsyQpw7ZHw6jDnMK1AMO6SRcvw53CsGlQw6/DuMO0wqr" // VM Config Bytecode Base64-Encoded
],
null,
[
"conf",
null,
"6LfTV4gkAAAAACDVrUvp9_DalxUPvFSU7M2HJDO-", // Website Key
0,
null,
null,
null,
1,
// Indexes for fingerprinting or something else
[16, 21, 125, 63, 73, 95, 87, 41, 43, 42, 83, 102, 105, 109, 121],
[-7614991, 137],
0,
null,
null,
null,
null,
0,
null,
0,
null,
700, // Time Start for Time Variances of Fingerprint Values
1,
null,
0,
// Encoded metadata for the VM's main bytecode constructs
"CvsCEg8I8ajhFRgAOgZUOU5CNWISDwjmjuIVGAA6BlFCb29IYxIPCMfm1DgYADoGZHhkTmlkEg8Is4qgOBgBOgZMV0o1a2ISDwiB7OgVGAA6Bkh1dlBqZhIPCK6e6zcYADoGR2JpT1FkEg8I94jmNxgAOgZvaWxlRGQSDwjwzeMVGAE6BmZJVkloYhIPCOLKoDcYAToGZ0xOQ0hjEg8I3r+3NxgBOgZlYXp1NmQSDwjY0oEyGAA6BkFxNzd2ZhIOCLjllDIYAToFUUJPRDASDwio7784GAA6BkdGVU5jZhIPCLWzqzgYAToGb3JZVjZkEg8I0tuVNxgAOgZmZmFXQWUSDwiV2JQyGAE6BlBxNjBuZBIPCKuRyjgYADoGQVo0TmJiEg8IxfOINxgAOgZhWG9pYWMSDwiNyoYyGAE6Bk93TjR0ZhIOCIr9iDcYADoFTWZJSTQaJwgDEiMdJv3NgTUZp4oJGYQKGZzijAIZzPMRGa+VQBnqsCYZ5a8MGQ==",
0,
1,
null,
null,
1,
null,
null,
0,
null,
null,
0,
0,
"cf5e3c3a6ab6c494c829a7932d9577c1e6de862dd4912e55dc7fe2e40a1f7604"
],
"https://who.clickbait.team:443", // Website URL:Port
null,
[
3,
1,
1
],
null,
null,
null,
1,
3600,
[
"https://www.google.com/intl/es/policies/privacy/",
"https://www.google.com/intl/es/policies/terms/"
],
"vQWNjTpMwdevQPWmE8akDzp8jsOZfa1VqTzVHaPiQ/c=",
1,
0,
null,
1,
1777669303203, // Fingerprint Data Encryption Key
0,
0,
[203], // Config Bytecode Key
null,
[185], // Config Bytecode Key
"RC--rg1OSRnOD0ayA",
null,
null,
null,
null,
null,
// Bft Token, Used in reCAPTCHA V2
"0dAFcWeA4RepD9zDjeMQE73pAT27pXZ7Nz_419U2K36QNqzHaKtLIDkwZQLi-Ud8OvSZHbDEcxQxusBQnsF5QQErMRpJMcUplaFg",
1777752103288 // "oc" Data Encryption Key
]
I valori si basano sui valori decifrati provenienti dalla prima impronta digitale di esempio, guarda qui
Ogni sottocampo dei valori dell'impronta digitale ha un formato base:
[value, key, elapsed]
Dove key è la chiave di crittografia, e elapsed è il tempo impiegato dal collector per ottenere e crittografare il valore. Questo permette a reCAPTCHA di rilevare:
Il sistema utilizza uno scheduler interno:``` [42, 45, 53, 30, 28, 54, 29, 31, 32, 33, 34, 35, 37, 36, 38, 39, 43, 40, 41, 46, 48, 57, 58, 60, 61, 62, 63, 64, 66, 68, 69, 71, 72, 79, 55]
Questo rappresenta:
- Ordine di esecuzione
- Pipeline del collettore
- Sequenza di generazione del segnale
### Codici dei segnali delle impronte digitali e derivazione delle chiavi
Trasforma i segnali delle impronte digitali in chiavi di crittografia deterministiche attraverso una pipeline di derivazione a più stadi
Ogni valore dell'impronta digitale è:
- Normalizzato
- Codificato in un codice segnale compatto
- Convertito in una chiave di crittografia numerica
- Crittografato utilizzando la chiave derivata
Il processo è deterministico, il che significa che lo stesso valore di input genera sempre lo stesso codice segnale e la stessa chiave di crittografia```
Raw Value
↓
Signal Code Derivation
↓
Compact Signal Code
↓
Numeric Key Derivation
↓
Encryption Key
↓
Value Encryption
Segnale di ingresso``` "BUTTON,195a81c9"
***Step 1 - Derivare il Codice del Segnale***```javascript
deriveSignalCode("BUTTON,195a81c9")
// → "wg"
Il codice del segnale generato è un identificatore deterministico compatto per il valore originale.
Passaggio 2 - Derivare la Chiave Numerica```javascript deriveKey("wg") // → 3792
Il codice del segnale viene trasformato in una chiave di crittografia numerica.
***Passaggio 3 — Crittografa il valore***```javascript
encryptValueWithKey(3792, "wgia1z9pwq")
// → "bYVbh6BUsE_5pLA"
Il valore successivo verrà crittografato con la chiave derivata, seguendo l'ordine del collettore.
Tutti i codici di segnale generati vengono aggregati in una struttura serializzata compatta.
Processo``` value -> "BUTTON,195a81c9" seed code -> wg key -> 3792 value -> "wgia1z9pwq" seed code -> 21 key -> 1599 value -> 1 seed code -> p1 key -> 3521 value -> "8cc68d83" seed code -> ld key -> 3448 value -> "https://nextcaptcha.com/demo..." seed code -> 9p key -> 1879 value -> 4 seed code -> op key -> 3553 value -> false seed code -> 1r key -> 1633 value -> 7 seed code -> qf key -> 3605 value -> "jYAQSHAEAI" seed code -> 1z key -> 1641 value -> "" seed code -> 80 key -> 1784 value -> 2 seed code -> jk key -> 3393 value -> "AAAAAAAAAA" seed code -> 1z key -> 1641 value -> "h3" seed code -> 9p key -> 1879 value -> "0,BUTTON,195a81c9" seed code -> ia key -> 3352 value -> -1 seed code -> 1u key -> 1636 value -> 0 seed code -> wq key -> 3802 value -> "74,fbfbc5b3" seed code -> 6z key -> 1796 value -> 0 seed code -> wq key -> 3802 value -> 0 seed code -> wq key -> 3802 value -> 2 seed code -> jk key -> 3393 value -> 0 seed code -> wq key -> 3802 value -> "-1,-1" seed code -> 1m key -> 1628 value -> "static.cloudflareinsights.co,..." seed code -> 1g key -> 1622 value -> "" seed code -> 80 key -> 1784 value -> "https://nextcaptcha.com,https...." seed code -> pd key -> 3572 value -> "[4,"CABIBQAggA","BAgAAgAAgA"]" seed code -> 1n key -> 1629 value -> "Demostración empresarial de reCAPTCHA v3..." seed code -> 1k key -> 1626 value -> "[2,76852,77850,77351]" seed code -> 9b key -> 1865 value -> "sha384-TNm" seed code -> 23 key -> 1601 value -> "[1680,1050,876,1166,844,876]" seed code -> 13 key -> 1570 value -> "[300,null,1778502450481]" seed code -> ex key -> 3251 value -> "[null,null,"",""]" seed code -> rx key -> 3654 value -> "[2147483648,70806416,65303240]" seed code -> 2r key -> 1664 value -> "GA1.1.354395113.1778502448" seed code -> 1g key -> 1622 value -> false seed code -> 1r key -> 1633 value -> "[[[1,"wg"],..." seed code -> 85 key -> 1789
**Finale**```json
[
[
[1, "wg"], [1, "21"], [1, "p1"],
[1, "ld"], [1, "9p"], [1, "op"],
[1, "1r"], [1, "qf"], [1, "1z"],
[1, "80"], [1, "jk"], [1, "1z"],
[1, "9p"], [1, "ia"], [1, "1u"],
[1, "wq"], [1, "6z"], [1, "wq"],
[1, "wq"], [1, "jk"], [1, "wq"],
[1, "1m"], [1, "1g"], [1, "80"],
[1, "pd"], [1, "1n"], [1, "1k"],
[1, "9b"], [1, "23"], [1, "13"],
[1, "ex"], [1, "rx"], [1, "2r"],
[1, "1g"], [1, "1r"]
],
"54"
]
Idx 4 (string)
Valore: 3ccb
Hashato: true
Descrizione: Genera una chiave HMAC da window.localStorage.getItem("rc::a") + "6d" convertito in byte, calcola HMAC-SHA256(siteKey) con quella chiave e restituisce i primi 4 caratteri esadecimali del risultato.
Il valore di rc::a è un base64 generato casualmente.
Idx 5 (integer)
window.localStorage.length * 2falsewindow.localStorage lunghezza moltiplicata per 2Idx 16 (string)
Valore:
Alcuni segnali reCAPTCHA potrebbero non essere disponibili o non essere raccolti (a causa di timeout legati al debugging). In tali casi, il segnale mancante viene sostituito con un valore codificato in base64 generato casualmente. Ad esempio:``` ["CMXZyamk3ZHNjdGsyaQ==", 3249, 591]
Una volta completata la costruzione dell'impronta, viene serializzata in una stringa e crittografata utilizzando la chiave di crittografia caricata dal campo anchor (indice 18). Il risultato crittografato viene poi memorizzato nel campo dell'indice `16` del payload `/reload`.
## Segnali VM
I seguenti sono i valori del browser ottenuti dalla VM interna di reCAPTCHA, insieme alla chiave del segnale. Alcuni valori non sono mostrati nell'esempio di impronta perché la VM estrae solo determinati valori dal bytecode di configurazione. Pertanto, verranno visualizzati altri valori. Per maggiori dettagli, vedere [qui](https://github.com/elyelysiox/recaptcha-vm)
Formato base del segnale:```
[
null,
collectorElapsed,
encryptElapsed,
value
]
Dove collectorElapsed indica quanto tempo (ms) ha impiegato il collector per ottenere il valore
E encryptElapsed indica quanto tempo (ms) ha impiegato per crittografare il valore.
Questi tempi sono misurati durante l'esecuzione della VM.
[ null, 7, 0, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" ], null, null, [ null, 0, 0, "[]" ], null, null, [ null, 4, 0, "["Join And Get Free Trial!","","Captcha Solving Service","Products","Docs"]" ], [ null, 0, 0, "false" ], null, [ null, 0, 0, "0" ], [ null, 1, 0, "[null,null,null,null,"false"]" ], [ null, 3, 4, "[[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]" ], [ null, 1, 4, "[[[0,0,979]],1,0]" ], [ null, 1, 1, "[[[1,0]]]" ], [ null, 4, 1, "[886,2300,262.2099999997952,392.7600000009595,2050.2399999993577]" ], [ null, 1, 1, "[[[1123,0,0]]]" ], [ null, 1, 2, "[[[1123,0]]]" ], [ null, 1, 3, "[0,null,null,null,null,null,null]" ], [ null, 5, 9, "[1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],[28,777,858,28],0,0,25]" ], [ null, 0, 0, "" ], [ null, 0, 0, "229.6" ], [ null, 0, 0, "false" ], [ null, 1, 0, "[1,0,0,Infinity]" ], [ null, 1, 1, "["0",-1,-1,999]" ], [ null, 1, 0, "["undefined",3]" ], [ null, 1, 6, "[2,4,53324367238]" ], [ null, 12, 0, "["Google Inc. (Intel Inc.)","ANGLE (Intel Inc., Intel(R) UHD Graphics 630, OpenGL 4.1)",30]" ], [ null, 28, 2, "[1542343452,0,105002991,3556653,96784904,-731949068,-902263026,-1914850612,571474391,-1588406278,3443508,1967713171,-1249474914,-1588406278,0,918504841,-807058197]" ]
- **Key 417** (`string`)
- Value: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...`
- Descrizione: User-Agent completo del browser
- **Key 727** (`array`)
- Value: `[]`
- Descrizione: Blocchi di prezzi dei prodotti, contiene prezzi per prodotti commerciali sul sito web, questi possono apparire su marketplace come Amazon, eBay, AliExpress, ecc., [Esempio](https://github.com/elyelysiox/recaptcha/blob/main/findProductPricesBlock.js)
- **Key 150** (`array`)
- Value: `[\"Join And Get Free Trial!\",\"\",\"Captcha Solving Service\",\"Prod...`
- Descrizione: Link estratti dagli elementi `<a>` del sito web, la VM raramente estrae questi valori
- **Key 545** (`boolean`)
- Value: `false`
- Descrizione: `navigator.webdriver`
- **Key 370** (`integer`)
- Value: `0`
- Descrizione: Punti di contatto massimi del dispositivo `navigator.maxTouchPoints`
- **Key 779** (`array`)
- Value: `[null,null,null,null,"false"]`
- Descrizione: Estrae dati dai campi di spedizione/fatturazione, [Esempio](https://github.com/elyelysiox/recaptcha/blob/main/formFieldScrape.js)
`postal|postalcode|postalcode|postal_code|zip` → cerca il campo del codice postale
`ship|deliver` → sezione spedizione
`billing|payment|credit` → sezione fatturazione
`country` → selettore paese
`addr.*(match|equal)|(match|equal).*address` → checkbox "stesso indirizzo"
Legge name, id, autocomplete, className di ogni elemento
Tre fasi: input di testo, istruzioni SELECT, checkbox
- **Key 659** (`array`)
- Value: `[[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]`
- Descrizione: Contiene i dati degli elementi premuti sulla pagina nel formato `[[[count,timestamp]],[[hashedElem,tagType,type,autoComplete]],pressedCount,behaviorChecksum]`
### Tipo di elemento
| Tipo di elemento | ID |
|-------------|----|
| `""` | 1 |
| `text` | 2 |
| `button` | 3 |
| `submit` | 4 |
| `checkbox` | 5 |
| `email` | 6 |
| `password` | 7 |
| `select-one` | 8 |
| `select-multiple` | 9 |
| `radio` | 10 |
| `textarea` | 11 |
| `file` | 12 |
| `tel` | 13 |
| `number` | 14 |
| `date` | 15 |
| `reset` | 16 |
| `range` | 17 |
### Algoritmo Behavior CheckSum
Il behaviorChecksum è un punteggio comportamentale compatto derivato dai dati di interazione dell'utente raccolti.
Per ogni interazione:
- L'indice di interazione viene incrementato di uno
- Il timestamp viene combinato con l'indice di interazione aggiustato
- L'hash dell'elemento viene ridotto usando un'operazione modulo
- Il risultato viene accumulato in un punteggio progressivo
---
```javascript
function computePressedElementsChecksum(pressedElementsArray) {
let accumulator = 0;
for (const [countTimestampPair, elementInfo] of zip(
pressedElementsArray[0],
pressedElementsArray[1],
)) {
const shiftedTimestamp = countTimestampPair[0] + 1;
const baseValue = countTimestampPair[1] + shiftedTimestamp;
const remainder = elementInfo[0] % baseValue;
accumulator = remainder + accumulator;
}
const logTerm = Math.log(accumulator + 1) * 4;
const modTerm = accumulator % 10;
const behaviorChecksum = Math.floor(logTerm + modTerm);
return JSON.stringify(pressedElementsArray);
}
function zip(a, b) {
const length = Math.min(a.length, b.length);
const result = [];
for (let i = 0; i < length; i++) {
result.push([a[i], b[i]]);
}
return result;
}
```
### Esempio
```javascript
const checksum = computePressedElementsChecksum([[[0,921],[1,2053]],[[235054,1,1,1],[164277,3,4,1]],2,39]);
console.log(checksum); // → 39
```
- **Key 959** (`array`)
- Value: `[[[0,0,979]],1,0]`
- Descrizione: Contiene i movimenti di scorrimento raccolti durante la sessione della pagina
### Formato base
```
[ [ [ scrollX, scrollY, timestamp ] ], count, behaviorChecksum ]
```
- **Key 895** (`array`)
- Value: `[[[1,0]]]`
- Descrizione: `VisibilityStateEntry` tiene traccia dello stato di visibilità della pagina, indicando se l'utente sta visualizzando la pagina o se è uscito, nel formato `[[[isVisible, startTime]]]`
- **Key 1092** (`array`)
- Value: `[886,2300,262.2099999997952,392.7600000009595,2050.2399999993577]`
- Descrizione: reCAPTCHA Performance, PerformanceNavigationTiming e PerformanceEventTiming, nel formato `[vmStart,vmEnd,domContentLoadedEventEnd,loadEventEnd,firstUserInteractionTime]`
- **Key 41** (`array`)
- Value: `[[[1123,0,0]]]`
- Descrizione: ClearTimeout
- **Key 43** (`array`)
- Value: `[[[1123,0]]]`
- Descrizione: ClearTimeout
- **Key 549** (`array`)
- Value: `[0,null,null,null,null,null,null]`
- Descrizione: KeyboardEvent, tasti calcolati + timestamp
- **Key 352** (`array`)
- Value: `1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],...`
- Descrizione:
La struttura contiene:
- Tempi di movimento del mouse
- Coordinate del cursore
- Durate dei clic
- Dimensioni dell'elemento premuto
- Informazioni sul tipo di puntatore
- Metriche di pressione
- Distanza percorsa dal cursore
- Statistiche temporali comportamentali
### Formato base:
```
[
eventsCount,
mouseEvents,
[
coalescedEventsCount,
averageInterEventDelay,
timingVarianceScore
],
[
totalPoints,
clickSequenceScore,
totalCursorDistance,
totalPoints
],
0,
0,
behaviorChecksum
]
```
### Struttura dell'evento del mouse:
Ogni voce all'interno di mouseEvents segue questa struttura:
```
[
timestamp,
clickDuration,
clientX,
clientY,
[
elementLeft,
elementTop,
elementWidth,
elementHeight
],
elementTagType,
trackedElementIndex,
pressure,
pointerTravelDistance,
pointerArea
]
```
| Nome | Descrizione |
|---|---|
| `timestamp` | Timestamp dell'evento relativo all'inizio dell'evento |
| `clickDuration` | Durata tra `pointerdown` e `pointerup` |
| `clientX` | ... |
| `clientY` | ... |
| `elementBounds` | Rettangolo di delimitazione dell'elemento interagito |
| `elementTagType` | Identificatore codificato del tag DOM dell'elemento interagito |
| `trackedElementIndex` | Identificatore interno dell'elemento DOM interagito dalla mappa di interazione runtime |
| `pressure` | Valore di pressione del puntatore normalizzato moltiplicato per `100` |
| `pointerTravelDistance` | Distanza percorsa tra `pointerdown` e `pointerup` |
| `pointerArea` | Area di contatto calcolata come `width * height` |
### Tipo di elemento tag
Viene inizializzato durante l'esecuzione della VM di reCAPTCHA
| Tipo | ID |
|------|----|
| `BODY` | 1 |
| `INPUT` | 2 |
| `BUTTON` | 3 |
| `SELECT` | 4 |
| `TEXTAREA` | 5 |
| `FORM` | 6 |
| `A` | 7 |
| `AREA` | 8 |
| `AUDIO` | 9 |
| `VIDEO` | 10 |
| `IFRAME` | 11 |
| `DIV` | 12 |
| `SPAN` | 13 |
| `LABEL` | 14 |
### Esempio
```
[
18342,
91,
742,
381,
[700, 320, 120, 38],
3,
1,
50,
1.4,
16
]
```
Rappresenta:
- evento a `18.342s`
- durata clic di `91ms`
- clic a `(742, 381)`
- interazione con un `BUTTON`
- pressione del puntatore `0.5` (50)
- leggero movimento del cursore durante il clic
- area di contatto del puntatore di `16`
### Algoritmo Behavior CheckSum
Per ogni evento del mouse:
- La durata del clic viene amplificata
- Il risultato viene combinato con il timestamp dell'evento
- Le coordinate del cursore e le dimensioni dell'elemento vengono mescolate
- Viene calcolato un rapporto ponderato
- Il rapporto viene arrotondato e accumulato
Dopo che tutti gli eventi sono stati elaborati:
- Il punteggio accumulato viene combinato con la distanza totale del cursore
- Il risultato viene normalizzato usando il numero di punti raccolti
- Viene applicata una trasformazione logaritmica
- Vengono incorporate statistiche di movimento aggiuntive
- Il valore finale viene ridotto usando un'operazione modulo
- Il risultato viene arrotondato a un piccolo punteggio intero
---
```javascript
function computeMouseBehaviorChecksum(mouseDataArray) {
let totalSum = 0;
for (let i = 0; i < mouseDataArray[1].length; i++) {
const event = mouseDataArray[1][i];
const scaledClickDuration = event[1] * 4;
const xPlusScaledDuration = event[0] + scaledClickDuration;
const combinedElementDims = event[2] + event[4][2] + event[4][1]; // clientY + elementWidth + elementTop
const product = xPlusScaledDuration * combinedElementDims;
const divisor = event[3] + event[4][3] + event[4][0] + 1; // elementTagType + elementHeight + elementLeft + 1
const roundedValue = Math.round(product / divisor);
console.log(roundedValue);
totalSum += roundedValue;
}
const summaryArray = mouseDataArray[3]; // [totalPoints, clickSequenceScore, totalCursorDistance, totalPoints]
const sumPlusCursorDistance = totalSum + summaryArray[2];
const totalPointsPlusOne = summaryArray[0] + 1;
const ratio = sumPlusCursorDistance / totalPointsPlusOne;
const ratioPlusOne = ratio + 1;
const logRatio = Math.log(ratioPlusOne);
const scaledLog = logRatio * 4;
const ratioPlusTotalPoints = ratio + summaryArray[0];
const ratioPlusTotalPointsPlusScore = ratioPlusTotalPoints + summaryArray[1];
const modResult = ratioPlusTotalPointsPlusScore % 11;
const behaviorChecksum = Math.round(scaledLog + modResult);
return JSON.stringify(mouseDataArray);
}
```
### Esempio
```javascript
const checksum = computeMouseChecksum([1,[[2050,125,633,266,[609,266,105,44],3,1,50,1,1]],[3,3,318],[28,777,858,28],0,0,25]);
console.log(checksum); // → 25
```
- **Key 360** (`string`)
- Value: `""`
- Descrizione: Parsing del totale dei prezzi del sito web raccolti con un regex ``(?i)total[\S\s]{0,20}?(?:(?:(?:USD|\$)\s*)?[\d\.,]+\s*(?:USD|\$)|(?:USD|\$)\s*[\d\.,]+)``, [Esempio](https://github.com/elyelysiox/recaptcha/blob/main/websitePricesTotal.js)
- **Key 1278** (`integer`)
- Value: `229.6`
- Descrizione: Divisione per 10 del timing di runtime corrente `Math.trunc(performance.now()) / 10`
- **Key 1422** (`boolean`)
- Value: `false`
- Descrizione: Analizza se ci sono campi OTP/2FA sul sito web, [Esempio](https://github.com/elyelysiox/recaptcha/blob/main/parseOTPFields.js)
- **Key 614** (`array`)
- Value: `[1,0,0,Infinity]`
- Descrizione: Informazioni sulla batteria del dispositivo, nel formato `[level,isCharging,chargingTime,dischargingTime]`
- **Key 2033** (`array`)
- Value: `["0",-1,-1,999]`
- Descrizione: Alcuni valori costanti della VM e timing di runtime della VM
- **Key 1313** (`array`)
- Value: `["undefined",3]`
- Descrizione: Controlli Android, Chrome, `[typeof window.android, Object.keys(window.chrome).length]`
- **Key 1994** (`array`)
- Value: `[2,4,53324367238]`
- Descrizione: `[navigator.hardwareConcurrency, navigator.deviceMemory, navigator.storage.estimate().qouta]`
- **Key 1310** (`array`)
- Value: `["Google Inc. (Intel Inc.)","ANGLE (Intel Inc.,...`
- Descrizione: Renderer WebGL, Vendor e Estensioni Totali, [Esempio](https://github.com/elyelysiox/recaptcha/blob/main/webglSignals.js)
- **Key 291** (`array`)
- Value: `[1542343452,0,105002991,3556653,96784904,-731949068,-902263026,...`
- Descrizione: Chiave hash di specifici prototipi di oggetti del browser, come `SpeechSynthesisEvent`, `NetworkInformation`, `HTMLElement`, ecc., [Esempio](https://github.com/elyelysiox/recaptcha/blob/main/hashBrowserProtos.js)
## Payload della Richiesta di Ricarica
Questo dato è serializzato usando protobuf (Protocol Buffers), un metodo efficiente e neutro per serializzare dati strutturati, sviluppato da Google.```javascript
[
"rreq",
"U5VsmTDhJM1iOJUyw4DEUTYv",
"03AFcWeA5Els3SIQviW2OYCHYD4uDhKlFPG6A48z2nk74BC2vrXSRvtpP9uVkWW96kUKm7sHIr...",
null,
null,
"-383788762",
"q",
"05APQrAobTCFGtbKVY3NwExv-K_G7oqmzGyUcTXi532CBKvSJUiT49tkRSgGD__OdfVRZtrI3i...",
"submit",
null,
null,
null,
null,
null,
"6LcAbwIqAAAAAJvVAhSSJ8qzYsujc7kn1knmSgQX",
null,
"0XA4cHhALxgMF9_Kt6uze2ZTR08XAe2x8o3BrU1hbTouNf3o1cnRmYRxZW01IA0BCNC_qJykb...",
null,
null,
null,
"tbMywxNTQsODQ0XSxbMSwyOTksMTA4Nl1dLFtbMiw2MSwxMzIuNzM5OTk5OTk5ODQ2MzNdLF...",
"0aAPQrAobqMEazjp9PGLYWTgxWGGcq9k5MJNI6LFBWfTh0UkDaVobdH-InwAYsTXtxs3rH_fI",
"BDAAYAIAGEcAAUoYI4lDCKAsCJlcgB6AAJtgggoIEEOALSoQRZxSZyAJBHANCkAJQYhFJES...",
null,
null,
"W1tbNTAwNiw0M10sWzY0NjA3LDFdLFs0NTQ2NCwxXSxbMzU4MzcsMV1dXQ==",
null,
null,
]
| Valore | Descrizione |
|---|---|
q | Sfida reCAPTCHA V3 |
fi | Sfida reCAPTCHA V2/Invisibile |
a | Sfida audio |
Idx 20)Per decodificare:```javascript atob("W1tbMywwLDgyOV0sWzEs...") // → [[[3,0,829],[1,42,863]],[[2,727,1341.300000011921]...
Il payload contiene:
- Informazioni sui tempi delle risorse
- Tempistiche di performance dei long-task
- Delta di esecuzione della VM di reCAPTCHA
- URL degli script del sito web
- Statistiche di raccolta degli oggetti del browser
### Struttura di base```js
[
[recaptchaResources],
[tasksTiming],
[
null,
null,
null,
idleTimeoutDelta,
deltaTiming,
0,
0,
0,
],
websiteScriptsUrls,
[collectionElapsed, browserObjectsLength]
]
[ PerformanceLongTaskTiming.name == "self" ? 2 : 4, PerformanceLongTaskTiming.duration, PerformanceLongTaskTiming.startTime ]
### reCAPTCHA Resource Timing Format```js
[
resourceType,
duration,
startTime
]
| Resource |
|---|
Idx 25)Questo campo contiene contatori codificati in Base64 per gli eventi di interazione del browser raccolti durante l'esecuzione
Esempio decodificato:```js [ [ [5006, 43], [64607, 1], [45464, 1], [35837, 1] ] ]
### Struttura del Contatore di Eventi```js
[
[
[eventType, count]
]
]
[ "rresp", "", null, 120, [ "pmeta", [ "/m/013xlm", null, 3, 3, 3, null, "Tractor" ], null, [1] ], "", null, null, "", "", null, null, "", null, "", "", 0 ]
## Descrizioni dei campi
| Indice | Nome | Descrizione |
|---|---|---|
| `0` | `rresp` | Identificatore del tipo di risposta restituito dall'endpoint di ricarica |
| `1` | `responseToken` | Token di risposta reCAPTCHA |
| `3` | `tokenExpiration` | Durata del token in secondi prima della scadenza |
| `4` | `pmeta` | Blocco di metadati della sfida contenente informazioni sul tipo di CAPTCHA, categoria e disposizione della griglia |
| `5` | `challengeType` | Tipo di sfida CAPTCHA |
| `8` | `usagePatternToken` | Pattern di utilizzo, memorizzati in `window.sessionStorage` e riutilizzati in future richieste `/reload` |
| `9` | `challengeImageToken` | Token utilizzato per recuperare il payload dell'immagine CAPTCHA dall'endpoint `/payload` |
| `12` | `humanVerificationToken` | Token di identificazione umana associato allo stato di Google reCAPTCHA e ai cookie del browser |
| `14` | `captchaSessionToken` | Token di sessione interno |
| `15` | `bftToken` | ... |
---
### `pmeta` Struttura
Esempio:```js
[
"pmeta",
[
"/m/013xlm",
null,
3,
3,
3,
null,
"Tractor"
],
null,
[1]
]
pmeta[1]Il valore a Idx 9 (challengeImageToken) viene utilizzato per recuperare l'immagine CAPTCHA:```txt
https://www.google.com/recaptcha//payload
?p=
&k=
### Category Identifiers
| ID | Categoria |
|---|---|
| `/m/0pg52` | Taxi |
| `/m/01bjv` | Autobus |
| `/m/02yvhj` | Autobus scolastico |
| `/m/04_sv` | Motocicletta |
| `/m/013xlm` | Trattore |
| `/m/01jk_4` | Camino |
| `/m/014xcs` | Attraversamento pedonale |
| `/m/015qff` | Semaforo |
| `/m/0199g` | Bicicletta |
| `/m/015qbp` | Parcometro |
| `/m/0k4j` | Auto |
| `/m/015kr` | Ponte |
| `/m/019jd` | Barca |
| `/m/0cdl1` | Palma |
| `/m/09d_r` | Montagna / collina |
| `/m/01pns0` | Idrante antincendio |
| `/m/01lynh` | Scale |
## Payload della Richiesta UserVerify
Il payload `/userverify` viene inviato dopo che l'utente completa una sfida reCAPTCHA v2
# Struttura del Payload```
v: hsFBb1u5wWWWkWP4in1ua2cQ
c: 03AFcWeA5RIHz5mI2COQqTcLjdrC7FiPpdfkX-hB-B2iFenI...
response: eyJyZXNwb25zZSI6WzMsMSw0LDksMCwxMSwxMCwxMywxNF0....
t: 24521
ct: 24521
ch: -4007845
oc: 0ZpqzzPgYKEEaN0xpfo3v_voeVUySZK3Ktf_fLVRdhnu3yeTy4BhO...
pm: 51bGwsbnVsbCxbbnVsbCxudWxsLG51bGwsWzEwLDQuMjcwMDAwMD....
response PayloadRappresenta gli indici/posizioni dei quadrati selezionati dall'utente nella griglia
Il payload viene successivamente codificato come JWT prima dell'invio
```txt
0 1 2
3 4 5
6 7 8
Esempio di payload:```json
{
"response": [2, 3, 6]
}
```txt
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
Esempio di payload:```json
{
"response": [2, 3, 6, 14]
}
e FieldIl payload response può anche includere un campo e:```json
{
"response": [2, 3, 6, 14],
"e": "bxCoiXVt49I7CTS_tNlVbGg"
}
Questo campo contiene metadati di interazione crittografati relativi alle azioni dei pulsanti CAPTCHA come:
- `Verify`
- `Next`
- `Skip`
### Struttura interna di `e`
Dopo la decifratura, la struttura assomiglia a:```txt
[[["9ffd9672"]]]
Ogni valore rappresenta un identificatore hash per la classe/azione del pulsante rc-button-default
L'hash è:
Sequenze di interazione più lunghe potrebbero apparire come:```txt [ [ ["9ffd9672"], ["9ffd9672"], ["9ffd9672"], ["9ffd9672"] ] ]
### `oc` — Segnali VM crittografati
Utilizza lo stesso algoritmo di crittografia del campo `idx 16` del payload della richiesta `/reload`, con la chiave di crittografia caricata nell'ancora (indice 31) `1777752103288`
### `pm` — Payload di telemetria
Il campo `pm` contiene una struttura di telemetria codificata in Base64 simile al payload di telemetria utilizzato in `/reload`.
## Anti-debugging/Manomissione
- ***Tag di integrità basato su Symbol***
reCAPTCHA imposta una chiave Symbol `Symbol(jas)` su ogni array e oggetto con un valore numerico utilizzato come controllo di integrità. Poiché i Symbol non sono enumerabili e invisibili alle operazioni di clonazione standard (come JSON.stringify), qualsiasi tentativo di sostituire o clonare queste strutture perde il tag, che reCAPTCHA rileva come manomissione

- ***Cattura di variabili closure***
Alcuni valori sono intenzionalmente inseriti nell'ambito di una funzione esterna e consumati solo all'interno di callback o closures annidate, la variabile non esiste mai nello stesso ambito in cui viene utilizzata
- ***Controlli di temporizzazione***
reCAPTCHA incorpora meccanismi di rilevamento del debugging in fase di esecuzione. Se rileva che il codice viene analizzato da un debugger, riavvia la sessione di debugging, causando la perdita dello stato e del contesto di esecuzione
- ***Scheda di origine crash***
https://github.com/user-attachments/assets/4ae3bf68-5ae7-4adc-a0b9-36cc11b64998
Questo bug si verifica nei browser che utilizzano Chromium. Ci sono diversi bug che causano la chiusura imprevista del browser o degli strumenti di sviluppo, come quello mostrato qui:
https://blog.castle.io/detect-and-crash-chromium-bots-with-one-weird-trick-bots-hate-it/
https://issues.chromium.org/issues/340836884?ref=blog.castle.io
Pertanto, è molto probabile che uno di questi bug venga attivato quando si verifica il timeout, poiché probabilmente non è qualcosa che accadrebbe nel flusso di un utente reale
## reCAPTCHA Botguard
Sebbene BotGuard sia stato rimosso da Google, spiegherò un po' come funziona internamente per chi è interessato a come è, e quanto sia diverso da altri tipi di botguard
Innanzitutto, il processo di generazione dei token: la VM genera token per errori persistenti durante l'esecuzione. Questi errori possono essere dovuti a deviazioni dell'offset del bytecode, registri VM mancanti, stato VM errato e scarsa integrità del flusso di controllo. Questi errori vengono catturati dal dispatcher, che chiama una funzione che scrive byte per il token.
La VM utilizza ARX Cipher, un algoritmo creato dalla NSA nel 2013, simile a Speck per crittografare i dati. Viene utilizzato anche in tutti i Google BotGuard. L'algoritmo cambia con ogni versione, così come la costante (3990), l'ordine delle operazioni e dei round. Si presenta così:```javascript
/*
D -> cipher state array
P -> seed
E -> byte index
*/
Vl = function(D, P, E, F, v) {
F = D[3] | 0;
D = D[2] | 0;
for (v = 0; v < 14; v++) {
E = E >>> 8 | E << 24;
E += P | 0;
E ^= D + 3990;
P = P << 3 | P >>> 29;
P ^= E;
F = F >>> 8 | F << 24;
F += D | 0;
F ^= v + 3990;
D = D << 3 | D >>> 29;
D ^= F;
}
return [P >>> 24 & 255, P >>> 16 & 255, P >>> 8 & 255, P >>> 0 & 255, E >>> 24 & 255, E >>> 16 & 255, E >>> 8 & 255, E >>> 0 & 255];
}
La funzione di crittografia principale ha due modalità: crittografia e nessuna crittografia. La modalità di crittografia utilizza ARX Cipher, Bitwise + XOR per crittografare i dati e inserirli in un buffer. Ci sono 4 tipi di buffer:
180353304243 (non utilizzato in questo tipo di botguard).La modalità senza crittografia imposta semplicemente i byte già crittografati nel buffer.```javascript // (The sequence flatten messed up the statements a bit) /* Q -> cipher state array FQ(v, c) -> derive a seed c = (z << 3) - 4 -> index FQ(v, (c | 0) + 4) -> position */ t = function(D, P, E, F, v, Q) { if (E.O == E) { P = function(h, A, c, x, z) { A = v.length; // buffer length z = (A | 0) - 4 >> 3; if (v.Jw != z) { // vm.block_index != index v.Jw = z; // set new block index c = (z << 3) - 4; x = [0, 0, Q[1], Q[2]]; try { v.zB = Vl(x, FQ(v, c), FQ(v, (c | 0) + 4)); // call ARX Cipher to generate keyStream } catch (V) { throw V; } } v.push(v.zB[A & 7] ^ h); // sets A to bits 0-7, and obtains a byte from the keystream and applies xor with a byte of the data to be encrypted }; v = Z(P, E); // get buffer if (P == 180 || P == 243 || P == 353) { Q = Z(189, E); } else { // set encripted bytes to buffer P = function(h) { v.push(h); }; } F && P(F & 255); E = D.length; for (F = 0; F < E; F++) { P(D[F]); } } }
E questa è la funzione che gestisce gli errori e chiama il byte writer```javascript
// (The sequence flatten messed up the statements a bit)
p = function(D, P, E, F, v, Q, h, A) {
D = E[1];
A = E[2];
Q = Z(465, P) >> 3;
h.push(D, Q >> 8 & 255, Q & 255); // error code/header bytes
E.message && (D += E.message);
A = void 0;
E && E[0] === U && (E = void 0);
h = Z(244, P);
h.length == 0 && (A != void 0 && h.push(A & 255));
D = "";
E && (E.stack && (D += ":" + E.stack));
E = Z(0, P); // buffer size limit (2048)
if (!P.TB && E[0] > 3) {
D = D.slice(0, (E[0] | 0) - 3);
E[0] -= (D.length | 0) + 3; // reduce size limit
D = Pv(D);
E = P.O;
P.O = P;
try {
v = (v = Z(304, P)) && v[v.length - 1] || 95;
if (P.n3) {
// this path is never executed
(F = Z(123, P)) && F[F.length - 1] == v || t([v & 255], 123, P);
} else {
t([95], 304, P); // set byte to error buffer
}
t(O(2, D.length).concat(D), 180, P, 9); // set bytes to main buffer
} finally {
P.O = E;
}
}
}
Alla fine dell'esecuzione, la VM chiama la funzione principale che prepara il payload con questi buffer e genera il token, che è una firma. A differenza di altre VM BotGuard, questa VM non ha un sistema di fingerprinting, Google Botguard né esegue queste emissioni di errori + scrittura di byte, ed è molto più semplice e facile da reverse engineering.
Questo repository è esclusivamente per scopi educativi e di ricerca. Il codice, le tecniche e i concetti presentati qui sono intesi per lo studio accademico e la comprensione degli argomenti trattati.
yM5Us/j/fn6EDgtmPlP4Pxj605nMJN9dRYHyy5MnHashato: true
Descrizione: Impronta digitale Bloom filter in base64 a 40 caratteri di tutti i nodi <HEAD>. Scorre ogni elemento figlio raccogliendo nomi di tag, attributi e contenuto testuale, serializzati e sottoposti a hash djb2.
Ogni digest viene inserito in un BitHash(240 bit, 7 round, max 25 nodi) che imposta bit su una griglia 40×6, quindi codifica ogni segmento da 6 bit come carattere base64. I tag script di reCAPTCHA sono esclusi tramite un'espressione regolare dinamica su src.
Idx 17 (integer)
2falseIdx 18 (string)
a2hyNTFuNDI4NnA3falseIdx 27 (string)
location.originfalseIdx 28 (boolean)
falsefalsewindow.parent != window ? true : window.frameElement != null ? true : falseIdx 29 (string)
e2a3cd70truegrecaptcha.execute hashato con SHA-256, EsempioIdx 30 (integer)
0falsehttps://www.gstatic.com/recaptcha/releases/<version>/, EsempioIdx 31 (string)
AAgkAQI0SBtruedocument.cookie hashate, EsempioIdx 32 (string)
""falsedocument.referrer.Idx 33 (integer)
Valore: 2
Hashato: false
Descrizione: Elemento del box reCAPTCHA in cui avviene il rendering.
// come grecaptcha.execute('.grecaptcha') -> questo div
// Fondamentalmente, restituisce un numero o la profondità/livello di quel div nel documento.
// Esempio: html > body > main > form > fieldset > div.recaptcha.form-field
// 5 4 3 2 1 0
// out = 5
nM = document.getElementsByClassName('grecaptcha-badge')[0] // o document.getElementsByClassName('g-recaptcha')[0] v2
let count = 0;
for (; nM = nM.parentElement || null;) {
count++;
}
const result = count;
Idx 34 (string)
AAAAAAAAAAtrue<INPUT> hashati, EsempioIdx 35 (string)
0,DIV,f0c7414etruedocument.activeElement Analisi se è un elemento di acquisto usando un'espressione regolare /buy|pay|place|order|donate|purchase/i con textContent, classNames e id, EsempioIdx 36 (string)
h3, h2 o http/1.1falsenextHopProtocol della performance di navigazione performance.getEntriesByType("navigation")[0].nextHopProtocolIdx 37 (integer)
-1falseperformance.timing.unloadEventStartIdx 38 (integer)
96falseperformance.timing.domainLookupStart - performance.timing.domainLookupEndIdx 39 (integer)
0falseperformance.navigation.typeIdx 40 (integer)
0falsewindow.scrollY o document.defaultView.pageYOffsetIdx 41 (string)
DIV,a08cd360true:hover su cui si trovava il mouse in quel momento, ottiene l'ultimo elemento e ne calcola l'hash di tagName, classNames e id, EsempioIdx 42 (string)
9,e3b0c442trueIdx 44 (string)
2v591z63wqtrue:hover, document.activeElement, tutti gli elementi <INPUT> hashati, location.url, window.scrollY, Esempio:const element = document.querySelectorAll(":hover");
const current = element[element.length - 1];
const result = [
deriveSignalCode(hash(current)),
deriveSignalCode(hash(document.activeElement)),
deriveSignalCode(hash(document.querySelectorAll('input'))),
deriveSignalCode(location.url),
deriveSignalCode(String(window.scrollY))
].join('')
Idx 45 (integer)
4falsewindow.history.Idx 46 (string)
https://static.kogstatic.com/0000/34c...falselinea:colonna in cui è accaduto.Idx 47 (integer)
0falsewindow.getSelection().toString().length || 0Idx 49 (string)
h2-0falsenextHopProtocol e determina se la sua duration è zero. Restituisce il risultato nel formato protocol-isZero, EsempioIdx 50 (array)
Valore: [1,0,null,1,1,["805b1z63wq"],"MWc2MzZwMnR0ZHNkMw==",0,null,[[1]]]
Hashato: true
Descrizione: Contiene comportamenti utente, elementi :hover hashati e un timeout che si incrementa ogni volta che viene raccolto un altro elemento :hover. Analizza le attivazioni utente per accumulare il numero di volte in cui l'utente ha interagito o è ancora presente sulla pagina calcolando (10 * IsActive + IsBeenActive)
Formato base:
[
count,
timeout,
null,
timeoutMultiplier,
transitionCount,
[ elementsHoverHashed ],
sessionId,
userActivationScore,
null,
[ [ flags ] ]
]
Idx 51 (array)
[0]falsedocument.body.innerText corrispondenze con le parole "try again", "incorrect", "invalid" o "declined" e restituisce il numero totale di corrispondenze trovate. Altrimenti restituisce 0, EsempioIdx 52 (integer)
11false10 * navigator.userActivation.isActive + navigator.userActivation.hasBeenActiveIdx 53 (integer)
Valore: 4
Hashato: false
Descrizione: Prende l'URL corrente del sito web, lo converte in un array di caratteri, lo tronca a 100 caratteri e poi lo riconverte in una stringa, Esempio
Poi è 5 se la lunghezza di quella stringa troncata è pari, o 4 se è dispari.
Idx 54 (boolean)
falsefalsewindow.document.hiddenIdx 55 (array)
[[[1,"2v"],[1,"9z"],[1,"z8"],[1,"us"],[1,..falseIdx 56 (string)
-1,-1falsewindow.opener, restituisce "-1,-1" se nullo, EsempioIdx 57 (string)
Valore: www.gstatic.com,_,static.kogstatic.com,www.google.com,www.googletagmanager.,...
Hashato: false
Descrizione: Raccoglie gli host da src di tutti gli elementi <SCRIPT> presenti in document.scripts, Esempio
Per ogni <SCRIPT>
Se l'elemento ha l'attributo src (hasAttribute("src")), il valore di src viene preso e analizzato con un'espressione regolare di tipo URI (nd), estraendo solo il componente host (gruppo di cattura 3 dell'espressione regolare).
Se il <SCRIPT> non ha un attributo src (è uno script inline), viene utilizzato il segnaposto "_".
Idx 58 (string)
mapslitepromosdismissed1falsewindow.localStorage campionata.Idx 59 (string)
""falsewindow.nameIdx 60 (string)
https://www.kogama.com,https://www.google.com,https://js.stripe.comfalseIdx 61 (array)
[0,"AAAAAAAAAA","AAAAAAAAAA"]trueMutationObserver, EsempioIdx 62 (string)
document.titlefalseIdx 63 (array)
Valore: []
Hashato: false
Descrizione: Estrae timestamp (numeri di 12-13 cifre che iniziano con 1[2-9], tipici di epoch millisecondi ~2008-2099) dai valori dei cookie, Esempio
Accumula i seguenti valori su tutti gli ID trovati: count, min, max e media.
Il risultato del valore finale è un array [count, min, max, avg]
Idx 64 (integer)
55557falseIdx 65 (string)
sha384-3qctruehttps://www.google.com/recaptcha/api.js?render= (troncato a 10 caratteri)Idx 67 (array)
[screen.width, screen.height, screen.availHeight, window.innerWidth, window.innerHeight, window.outerHeight]falseIdx 68 (array)
[300,null,1777685870223]false[new Date().getTimezoneOffset(), null, Date.now()]Idx 69 (string)
09AKhCRwjrDFiHsrRA--o23-HB-eWqOtk_XQ-rLE1...falseIdx 70 (array)
Valore: [null,null,"","",null,"1l0fl"]
Hashato: false
Descrizione: Estrae importi monetari totali (come Total: $50.00 o Total 150.00 EUR), Esempio
da document.innerText cercando il simbolo o codice della valuta insieme all'importo numerico usando l'espressione regolare:
total[\S\s]{0,20}?(((R\$|\$|€|£|USD|EUR)\s*[\d\.,]+)|[\d\.,]+\s*(€|USD|EUR))`
total → Cerca la parola esatta "total"
[\S\s]{0,20}? → Cerca tra (0) e (20) caratteri intermedi (come spazi, due punti o interruzioni di riga) prima di trovare il numero
(((R\$|\$|€|£|USD|EUR)\s*[\d\.,]+)|[\d\.,]+\s*(€|USD|EUR)) → Questo è il blocco principale che cattura il denaro ed è diviso in due opzioni separate
Idx 71 (array)
[jsHeapSizeLimit,usedJSHeapSize,totalJSHeapSize]falseIdx 72 (array)
Valore: [[["Google Chrome","147"],["Not.A/Brand",...
Hashato: false
Descrizione: Array di dati userAgent navigator.userAgentData un flag che indica se è mobile e la piattaforma, Esempio:
[
navigator.userAgentData.brands.map(b => [b.brand, b.version]),
navigator.userAgentData.mobile ? 1 : 0,
navigator.userAgentData.platform
]
Idx 73 (array)
[[null,2,0,"Mozilla/5.0 (Windows NT 10.0;...falseIdx 77 (integer)
nullfalseIdx 78 (string)
""false| Indice | Valore | Descrizione |
|---|
0 | rreq | Identificatore del tipo di richiesta |
1 | U5VsmTDhJM1iO... | Versione reCAPTCHA |
2 | 03AFcWeA5Els3... | Token di validazione ottenuto dall'endpoint /anchor |
5 | -383788762 | Ha hashato l'intero payload dell'impronta digitale serializzata, Sample |
6 | q | Indica la sfida o la modalità di richiesta in esecuzione |
7 | 05APQrAobTCFG... | Pattern di utilizzo, contenenti la cronologia di utilizzo e i pattern di sfida precedentemente risolti. Possono aumentare significativamente il punteggio se validi |
8 | submit | Azione specifica del sito che l'utente sta eseguendo sulla pagina al momento della verifica (ad es. signin, register) |
14 | 6LcAbwIqAAAA... | Chiave del sito web |
16 | 0XA4cHhALxgM... | Ha crittografato l'intero payload dell'impronta digitale serializzata con la chiave di crittografia proveniente da anchor (indice 18) 1777669303203 |
20 | tbMywxNTQsOD... | Struttura di telemetria codificata in Base64 contenente delta temporali della VM, tempi delle risorse, statistiche degli oggetti del browser raccolte e URL degli script del sito web |
21 | 0aAPQrAobqME... | Token associato a un CAPTCHA precedentemente risolto. Utilizzato per la continuità della sessione e la correlazione della fiducia |
22 | BDAAYAIAGEcA... | Ha hashato tutte le chiavi degli oggetti del browser |
25 | W1tbNTAwNiw... | Contatori codificati in Base64 per eventi di interazione dell'utente come movimento del mouse, clic, tastiera e cambiamenti di focus |
qr | Risposta rapida (nuovo) |
| Type |
|---|
recaptcha/api.js | 3 |
recaptcha/releases/<version> | 1 |
https://www.google.com/recaptcha/api2/anchor | 2 |
https://www.google.com/recaptcha/api2/bframe | 4 |
| Hash | Tipo di Evento |
|---|
5006 | pointermove |
64607 | pointerdown |
45464 | pointerup |
31617 | keydown |
37178 | keyup |
35837 | focusin |
| Posizione | Valore | Descrizione |
|---|
0 | /m/013xlm | Identificatore di categoria interna per la classe dell'oggetto target |
2 | 3 | Numero di colonne della griglia |
3 | 3 | Numero di righe della griglia |
5 | null | Campo metadati riservato o opzionale |
6 | "Tractor" | Etichetta di testo |
| Tipo | Descrizione |
|---|
imageselect | Selezione immagine standard CAPTCHA |
tileselect | Challenge basata su tile dinamico dell'immagine |
dynamic | Challenge dinamica in cui i tile si ricaricano dopo la selezione |
multicaptcha | Challenge CAPTCHA a più passi |
audio | Challenge di accessibilità basata su audio |
nocaptcha | Flusso di verifica solo con checkbox |
doscaptcha | Nega CAPTCHA in caso di abuso |
| Campo | Nome | Descrizione |
|---|
v | recaptchaVersion | Versione di reCAPTCHA |
c | challengeToken | Token dello stato della challenge restituito da /replaceimage o da una richiesta precedente /userverify |
response | Payload codificato contenente gli indici delle tessere selezionate e metadati aggiuntivi dell'interazione | |
t | challengeElapsed | Tempo trascorso dal caricamento iniziale della challenge |
ct | completionTime | Tempo totale impiegato dall'utente per risolvere e inviare il CAPTCHA |
ch | ocHash | Hash dell'intero payload serializzato oc, Esempio |
oc | encryptedVmSignals | Segnali crittografati raccolti dalla VM di reCAPTCHA, vedi qui. |
pm | telemetryPayload | Struttura di telemetria codificata in Base64 contenente delta dei tempi della VM, tempi delle risorse, statistiche degli oggetti del browser raccolte e metadati dello script del sito web |