Perfil pagador: autoavaliação e reparo via Termux (nível 2)
Como o ecossistema antifraude lê o seu “perfil pagador” (device, rede, comportamento) e como rodar uma autoavaliação em Python pelo Termux para identificar sinais ruins e reparar o que estiver causando challenge/recusa indevida.
🎧 audiobook · nível 1
Perfil pagador: autoavaliação e reparo via Termux (nível 2)
Continuação do nível 1 (3-D Secure 2.x)
Nível 2 da trilha de Pagamentos. Assumimos que você já entendeu os 5 atores, o fluxo frictionless × challenge e o Liability Shift. Aqui o foco é o lado do pagador real: por que transações legítimas viram challenge ou recusa, e como diagnosticar/reparar o próprio perfil sem cair em práticas que pioram ainda mais o risco.
O que é o “perfil pagador”
Antifraude moderno (Stripe Radar, Adyen RevenueProtect, Cybersource Decision Manager, Kount, Sift) não pontua só o cartão. Pontua o tripé: identidade (CPF, e-mail, telefone, histórico), dispositivo (device fingerprint, OS, fuso, idioma, integridade) e rede (IP, ASN, tipo de conexão, proximidade geográfica). O 3DS 2.x envia ~150 campos para a ACS do banco; o risco final é um score combinado dessas três dimensões.
- Identidade ruim: e-mail recém-criado, telefone VOIP, CPF sem histórico no merchant.
- Dispositivo ruim: fingerprint instável, fuso/idioma divergentes do BIN, root/jailbreak visível, automação detectada.
- Rede ruim: IP residencial dinâmico mudando a cada compra, VPN comercial, ASN de hosting, geo longe do endereço de cobrança.
- Comportamento ruim: várias tentativas com cartões diferentes, copiar/colar em campos sensíveis, velocidade anormal de preenchimento.
Escopo ético
Este artigo é sobre auditar o SEU próprio perfil (seu device, sua rede, suas compras legítimas) para reduzir falsos positivos. Não é guia de evasão de fraude: tentar maquiar sinais para passar como outra pessoa é crime (Lei 14.155/21, Art. 171-A CP). O caminho legítimo é reparar fundamentos.
Sinais que dá para medir pelo Termux
- IP público e ASN (residencial vs. hosting vs. VPN comercial).
- Geolocalização aproximada do IP vs. endereço de cobrança.
- Fuso horário, locale e idioma do device.
- Integridade do device (root, Magisk, su no PATH).
- Higiene do e-mail (MX válido, domínio descartável).
Script Python — autoavaliação no Termux
O script abaixo coleta sinais públicos do seu próprio device/rede e gera um relatório com nota 0–100 por dimensão + recomendações de reparo. Roda 100% local exceto pela consulta a ipwho.is e DNS público para MX.
Pré-requisitos no Termux
pkg update -y && pkg upgrade -y
pkg install -y python git dnsutils
pip install --upgrade pip
pip install requests rich dnspython~/payer_profile.py — autoavaliação do perfil pagador
#!/usr/bin/env python3
"""
payer_profile.py — autoavaliacao defensiva do perfil pagador.
Uso etico: rode SOMENTE no seu proprio device/rede para reduzir
falsos positivos em compras LEGITIMAS.
"""
from __future__ import annotations
import os, sys, json, time, locale, platform, shutil
from datetime import datetime, timezone
import requests
from rich.console import Console
from rich.table import Table
import dns.resolver
console = Console()
TIMEOUT = 8
# -------------------- coleta -------------------- #
def get_ip_info() -> dict:
try:
r = requests.get("https://ipwho.is/", timeout=TIMEOUT).json()
c = r.get("connection") or {}
return {
"ip": r.get("ip"),
"country": r.get("country_code"),
"region": r.get("region"),
"city": r.get("city"),
"asn": c.get("asn"),
"isp": c.get("isp"),
"org": c.get("org"),
}
except Exception as e:
return {"error": str(e)}
HOSTING = ("amazon","aws","google","gcp","azure","microsoft","digitalocean",
"ovh","hetzner","linode","vultr","oracle","cloudflare","contabo",
"m247","leaseweb","hostinger")
VPN = ("nordvpn","expressvpn","surfshark","protonvpn","mullvad",
"private internet access","pia","cyberghost","ipvanish","windscribe")
def classify_network(info: dict):
org = " ".join(str(v).lower() for v in (info.get("isp"), info.get("org")) if v)
if any(k in org for k in VPN): return ("VPN comercial detectada", 35)
if any(k in org for k in HOSTING): return ("ASN de hosting/datacenter", 45)
return ("Rede residencial/movel", 0)
def get_device_info() -> dict:
try:
lang = locale.getlocale()[0] or os.environ.get("LANG")
except Exception:
lang = os.environ.get("LANG")
return {
"os": f"{platform.system()} {platform.release()}",
"arch": platform.machine(),
"python": platform.python_version(),
"timezone": time.strftime("%Z%z"),
"locale": lang,
"termux": bool(os.environ.get("TERMUX_VERSION")),
}
def check_root():
for c in ("su", "magisk"):
if shutil.which(c): return True, c
for p in ("/system/xbin/su","/system/bin/su","/sbin/su"):
if os.path.exists(p): return True, p
return False, ""
def check_email(email: str) -> dict:
try:
domain = email.split("@",1)[1].lower()
except IndexError:
return {"error": "e-mail invalido"}
out = {"domain": domain}
try:
mx = sorted((r.preference, str(r.exchange).rstrip("."))
for r in dns.resolver.resolve(domain, "MX", lifetime=TIMEOUT))
out["mx"] = [m[1] for m in mx]
except Exception as e:
out["mx_error"] = str(e)
disposable = {"mailinator.com","tempmail.com","10minutemail.com",
"guerrillamail.com","yopmail.com","trashmail.com","getnada.com"}
out["disposable"] = domain in disposable
return out
# -------------------- scoring -------------------- #
def score(ip, dev, root, em, billing="BR"):
network = device = identity = 100
notes = []
label, pen = classify_network(ip)
network -= pen
notes.append(f"Rede: {label} (-{pen}).")
if billing and ip.get("country") and billing.upper() != str(ip["country"]).upper():
network -= 25
notes.append(f"Geo-IP ({ip['country']}) != pais de cobranca ({billing}) (-25).")
if root[0]:
device -= 40
notes.append(f"Root/Magisk detectado: {root[1]} (-40).")
if not (dev.get("locale") or "").lower().startswith(("pt","en")):
device -= 10
notes.append("Locale incomum para BIN BR (-10).")
if em.get("disposable"):
identity -= 60; notes.append("E-mail descartavel (-60).")
if "mx_error" in em:
identity -= 30; notes.append("Dominio sem MX valido (-30).")
clamp = lambda x: max(0, min(100, x))
return {"network": clamp(network), "device": clamp(device),
"identity": clamp(identity), "notes": notes}
def recommendations(s):
r = []
if s["network"] < 70:
r.append("Desligue VPN/proxy ao pagar; use 4G/5G da operadora ou WiFi residencial.")
r.append("Evite redes corporativas com NAT pesado em primeira compra.")
if s["device"] < 70:
r.append("Pague pelo Chrome/Edge oficial, nao por WebView de app obscuro.")
r.append("Device com root: use outro aparelho para compras de alto valor.")
r.append("Mantenha fuso/idioma consistentes com o endereco de cobranca.")
if s["identity"] < 70:
r.append("Use e-mail com 6+ meses no merchant; evite descartaveis.")
r.append("Cadastre telefone real (nao VOIP) — Adyen/Stripe usam carrier lookup.")
r.append("Em first purchase, prefira cartoes ja usados antes no mesmo merchant.")
if not r:
r.append("Perfil saudavel. Se ainda houver atrito, e regra do EMISSOR — ligue no 0800 do banco e peca liberacao pre-compra.")
return r
# -------------------- main -------------------- #
def main():
email = sys.argv[1] if len(sys.argv) > 1 else input("Seu e-mail: ").strip()
country = sys.argv[2] if len(sys.argv) > 2 else "BR"
console.rule("[bold cyan]Coletando sinais")
ip = get_ip_info(); dev = get_device_info()
root = check_root(); em = check_email(email)
t = Table(title="Snapshot do device/rede", show_lines=True)
t.add_column("Campo"); t.add_column("Valor")
for k, v in {**ip, **dev, "root": root[0], **em}.items():
t.add_row(str(k), str(v))
console.print(t)
s = score(ip, dev, root, em, country)
console.rule("[bold cyan]Scores (0-100, maior = menos risco)")
console.print(f"Rede: [bold]{s['network']}[/]")
console.print(f"Dispositivo: [bold]{s['device']}[/]")
console.print(f"Identidade: [bold]{s['identity']}[/]")
for n in s["notes"]:
console.print(f" - {n}")
console.rule("[bold green]Recomendacoes de reparo")
for rec in recommendations(s):
console.print(f"-> {rec}")
out = {"ts": datetime.now(timezone.utc).isoformat(),
"ip": ip, "device": dev, "root": root[0],
"email": em, "score": s}
path = os.path.expanduser("~/payer_profile_report.json")
with open(path, "w") as fp:
json.dump(out, fp, indent=2, ensure_ascii=False)
console.print(f"\n[dim]Relatorio salvo em {path}[/dim]")
if __name__ == "__main__":
main()Executar
python ~/payer_profile.py seu-email@dominio.com BRComo interpretar o relatório
- Score Rede < 70 → o IP é o vilão. Trocar para 4G/5G da operadora antes da compra costuma reverter challenge.
- Score Dispositivo < 70 → fuso/idioma/integridade. Em devices com root, mover compras críticas para outro aparelho ajuda mais do que tentar esconder o Magisk.
- Score Identidade < 70 → e-mail/telefone. E-mail com 12+ meses no Gmail/Outlook + número celular real (não VOIP) destrava muita coisa.
- Três notas ≥ 80 e ainda toma recusa → o problema é regra do emissor (limite, MCC bloqueado, viagem). Resolve no 0800 do banco.
Não faça
Spoofar fingerprint, comprar proxy residencial, gerar identidades sintéticas, testar cartões de terceiros. Tudo isso é fraude tipificada (Lei 14.155/21) e os mesmos sistemas que pontuam o seu perfil detectam reuso de stack de spoofing em segundos — você piora o score em vez de melhorar.
Reparo estrutural (longo prazo)
- Construir histórico no merchant: pequenas compras recorrentes com o mesmo cartão/e-mail/device elevam o trust score em semanas.
- Manter um “device de pagamento”: Android atualizado, sem root, com apps oficiais — separa risco de experimentação.
- E-mail principal estável (Gmail/Outlook/iCloud) com 2FA — vira identidade across merchants via Emailage/Ekata.
- Atualizar endereço de cobrança no banco ao mudar de cidade; AVS divergente é uma das maiores causas de recusa silenciosa.
Ferramentas relacionadas
- ▸Nmap — auditar a própria rede antes de classificá-la como residencial limpa
- ▸Termux — ambiente onde o script roda; mantenha pacotes atualizados
Próximo nível (em breve)
Nível 3 vai cobrir: leitura de logs reais de declines (Stripe, Adyen, Cielo), mapeamento de códigos R/05/51/61 para causa-raiz, e como conversar com o emissor para liberar BIN e MCC específicos sem precisar trocar de banco.
Template OffSec · aplicar antes de rodar
Objetivo → Preparação → Execução → Evidência → Ética
Objetivo
Compreender protocolos (3DS, tokenização, PIX) e falhas comuns no checkout para reforçar antifraude — sem tocar em cartão real de terceiros.
Pré-requisitos
- Ambiente sandbox do PSP com credenciais de teste
- Coleção Postman/Insomnia com fluxos parametrizados
- Cartões de teste oficiais (Visa 4111..., Mastercard 5555..., etc.)
- Log estruturado (JSON) para cada request/response
Passos
- Mapear o fluxo (auth → 3DS challenge → capture → refund)
- Testar cada estado de erro documentado pelo PSP
- Injetar variações no device fingerprint e observar o desafio 3DS
- Medir latência e códigos de resposta para cada persona-teste
- Consolidar findings em playbook com decision tree para o time de risco
Evidências a coletar
- Coleção Postman versionada
- Log request/response com sanitização de PAN (só BIN + últimos 4)
- Screenshots do painel do PSP mostrando a transação
Regra prática: se você não guardou evidência reprodutível, o achado não existe.
Guia prático (lab autorizado)
alvo · Sandbox oficial do PSP (Stripe test, Adyen test, PagSeguro sandbox)
curl https://api.stripe.com/v1/payment_intents -u sk_test_...: -d amount=1000 -d currency=brl -d 'payment_method_types[]=card'verificar · O painel do PSP em modo teste é a fonte da verdade — compare com o response do seu backend. Divergência = bug no seu lado.
Checklist interativo
Checklist ético (marcar antes do primeiro comando)
Autorização, escopo, lab e proteção de dados. Sem 100%, não roda fora do lab.
Prática segura · Pagamentos
→ guia do labMonte um ambiente isolado antes de qualquer teste — use Docker (DVWA/juice-shop), uma VM host-only ou um alvo autorizado (HTB, TryHackMe, PortSwigger Academy).
Nunca aponte para alvo em produção. Se estiver no celular, use proot-distro + Debian para não sujar o Termux principal.
