Voltar para o blog

Endpoint Discovery: JS Tricks e Recon Ofensivo

19/06/2026 30 min de leitura
Endpoint Discovery: JS Tricks e Recon Ofensivo

Resumo:

  • O endpoint discovery combina técnicas passivas e ativas para mapear rotas esquecidas, APIs expostas e painéis administrativos desprotegidos.
  • O recon passivo utiliza Google Dorks, Wayback Machine, Certificate Transparency, Shodan e Censys para mapear a superfície de ataque sem enviar requisições diretas ao servidor.
  • O JavaScript de aplicações React, Vue, Angular e Next.js revela endpoints ocultos, chamadas de API e, quando source maps estão expostos, o código-fonte original da aplicação.
  • O fuzzing ativo com ffuf e feroxbuster é mais eficaz quando combinado com wordlists construídas a partir dos dados coletados sobre o próprio alvo.
  • Cada framework tem estruturas de URL previsíveis e pontos de exposição específicos que tornam o recon mais direcionado.
  • Todo o processo pode ser automatizado em um pipeline de shell script, acompanhado de um checklist para garantir cobertura sistemática em cada engajamento.

Antes de explorar qualquer vulnerabilidade, o pentester precisa mapear o que existe no ambiente-alvo, incluindo endpoints não documentados, rotas administrativas ocultas, arquivos de configuração e APIs internas expostas. Este guia aborda todas essas técnicas, apresentando ferramentas e exemplos prontos para uso.

Por que endpoint discovery é a etapa mais crítica do pentest

Aplicações modernas acumulam endpoints ao longo de anos de desenvolvimento: rotas criadas para debug e nunca removidas, APIs internas expostas por acidente, painéis administrativos protegidos apenas por URL obscura, versões antigas de endpoints ainda funcionais e esquecidas.

O processo de descoberta de endpoints, chamado de endpoint discovery ou recon de superfície de ataque, combina técnicas passivas (sem tocar o servidor) e ativas (enviando requisições) para mapear tudo o que pode ser acessado.

Fase 1: Reconhecimento passivo

O recon passivo coleta informações sem enviar requisições diretas ao alvo. É a fase mais segura juridicamente e, frequentemente, a mais produtiva porque explora dados já públicos.

Google Dorks: usando o próprio Google como scanner

O Google indexa arquivos e páginas que deveriam estar restritos. Com operadores de busca avançados, como o Google Dorks, é possível encontrar endpoints expostos, arquivos de configuração, painel de admin e documentação de API diretamente no índice do Google, sem tocar no servidor do alvo.

Encontrar arquivos de configuracao de API expostos
site:alvo.com filetype:json "api_key" OR "apikey" OR "secret"

site:alvo.com filetype:yaml OR filetype:yml "swagger" OR "openapi"

site:alvo.com filetype:json "endpoints" OR "routes" OR "paths"

# Encontrar painéis de administração e login

site:alvo.com inurl:admin OR inurl:administrator OR inurl:panel

site:alvo.com inurl:login OR inurl:signin OR inurl:dashboard

site:alvo.com inurl:manage OR inurl:management OR inurl:backend

site:alvo.com intitle:"admin" OR intitle:"dashboard" OR intitle:"control panel"

 

# Encontrar documentação de API e Swagger

site:alvo.com inurl:swagger OR inurl:api-docs OR inurl:redoc

site:alvo.com inurl:openapi.json OR inurl:swagger.json OR inurl:api/v1

site:alvo.com filetype:yaml "swagger: '2.0'" OR "openapi: '3.0'"

 

# Encontrar arquivos de ambiente e configuração

site:alvo.com filetype:env OR filetype:config OR filetype:cfg

site:alvo.com inurl:.git OR inurl:/.env OR inurl:config.php

 

# Encontrar subdomínios e subdiretórios

site:*.alvo.com -www                    # todos os subdomains

site:alvo.com inurl:/api/ OR inurl:/v1/ OR inurl:/v2/


# Encontrar backups e arquivos expostos

site:alvo.com filetype:bak OR filetype:old OR filetype:backup

site:alvo.com filetype:sql OR filetype:db OR filetype:sqlite

 

 

Wayback Machine: endpoints que existiram e ainda funcionam

O Internet Archive armazena snapshots históricos de aplicações web. Endpoints removidos da interface pública frequentemente continuam funcionando no servidor. A ferramenta waybackurls automatiza a extração de todas as URLs históricas de um domínio.

 

// Shell

# Instalar waybackurls

go install github.com/tomnomnom/waybackurls@latest

 

# Extrair todas as URLs historicas do dominio

waybackurls alvo.com | tee wayback_urls.txt

 

# Filtrar por extensao ou padrao

waybackurls alvo.com | grep -E "\.(php|asp|aspx|jsp|json|xml|env|bak|sql)" > endpoints_ext.txt

waybackurls alvo.com | grep -E "/api/|/v[0-9]+/|/admin|/internal" > endpoints_api.txt

 

# Remover duplicatas e ordenar

waybackurls alvo.com | sort -u > unique_urls.txt

 

# Ferramenta alternativa: gau (Get All URLs)

go install github.com/lc/gau/v2/cmd/gau@latest

gau alvo.com --subs | tee gau_urls.txt

 

# Combinar waybackurls + gau para cobertura máxima

cat <(waybackurls alvo.com) <(gau alvo.com) | sort -u > all_historical_urls.txt

 

# Testar quais ainda respondem (filtrar ativos)

cat all_historical_urls.txt | httpx -silent -status-code -content-length -o active_endpoints.txt

Certificate Transparency: mapeando subdomains

Todo certificado TLS emitido para um domínio é registrado publicamente nos logs de Certificate Transparency. Isso cria um banco de dados auditável de subdomínios que pode revelar ambientes de staging, APIs internas, painel de admin e outros ativos não publicados.

 

// Shell

# Consultar certificate transparency logs

# Via curl diretamente na API do crt.sh

curl -s "https://crt.sh/?q=%.alvo.com&output=json" | \

python3 -c "import json,sys; [print(e['name_value']) for e in json.load(sys.stdin)]" | \

sort -u | grep -v "^\*" > subdomains_cert.txt

 

# Ferramenta subfinder (recon de subdomains multi-fonte)

go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest

subfinder -d alvo.com -all -o subdomains.txt

 

# Ferramenta amass

go install github.com/owasp-amass/amass/v4/...@master

amass enum -passive -d alvo.com -o subdomains_amass.txt


# Verificar quais subdomains estão ativos

cat subdomains.txt | httpx -silent -ports 80,443,8080,8443,3000,5000 \

-status-code -title -o live_subdomains.txt

 

# Procurar por subdomains reveladores

grep -E "api|internal|admin|dev|staging|beta|test|qa|uat|old|legacy|backup" subdomains.txt

 

Shodan e Censys: o que está exposto na internet

 

// Shell / Shodan

# Shodan: buscar por organização, ASN ou hostname

shodan search "hostname:alvo.com" --fields ip_str,port,hostnames,org,http.title

shodan search "org:Empresa Alvo" --fields ip_str,port,http.title

shodan search "ssl.cert.subject.cn:*.alvo.com"


# Dorks Shodan para encontrar serviços específicos

# Painel de administração expostos

shodan search 'http.title:"admin" hostname:alvo.com'

# APIs com documentação Swagger

shodan search 'http.html:"swagger" hostname:alvo.com'

# Servidores de CI/CD expostos

shodan search 'product:"Jenkins" hostname:alvo.com'

# Bancos de dados sem autenticação

shodan search 'product:"Elasticsearch" hostname:alvo.com port:9200'

 

# Censys (alternativa ao Shodan com maior cobertura de TLS)

# Via API:

curl -u "API_ID:API_SECRET" \

"https://search.censys.io/api/v2/hosts/search?q=services.tls.certificates.leaf_data.names%3Aalvo.com" | \

python3 -m json.tool

 

Fase 2: Análise de JavaScript (a técnica mais produtiva)

Aplicações React, Vue, Angular e Next.js compilam todo o código do frontend em bundles JavaScript que ficam publicamente acessíveis. Esses bundles frequentemente contêm rotas completas da aplicação, endpoints de API hardcoded, chaves de API, tokens de acesso, URLs de ambientes internos e lógica de negócio.

Por que funciona tão bem

Bundlers como Webpack, Vite e esbuild unem e modificam o código, mas não o criptografam. Todo endpoint definido no frontend, toda string de URL, todo fetch() e axios.get() está disponível para quem souber onde procurar.

Localizando e baixando os bundles JS

 

// Shell

# Passo 1: Identificar os arquivos JS do bundle

# Abrir DevTools > Network > filtrar por JS > recarregar a página

# Os arquivos principais geralmente seguem o padrão:

#   main.[hash].js, chunk.[hash].js, app.[hash].js

 

# Passo 2: Baixar todos os JS do domínio automaticamente

# Ferramenta: getJS

go install github.com/003random/getJS@latest

getJS --url https://alvo.com --complete --output js_files.txt

 

# Baixar com wget recursivo (apenas JS)

wget -r -l 2 -A "*.js" --no-parent https://alvo.com -P ./js_dump/

 

# Via Burp Suite: navegar a aplicação, depois:

# Target > Site Map > filtrar por .js > botão direito > Save all responses

 

# Passo 3: Verificar todos os JS via curl

cat js_files.txt | xargs -I {} curl -s {} >> all_js_content.txt

 

 

LinkFinder: extraindo endpoints de JS automaticamente

 

 

// Shell / LinkFinder

# Instalar LinkFinder

git clone https://github.com/GerbenJavado/LinkFinder.git

cd LinkFinder && pip3 install -r requirements.txt

 

# Analisar arquivo JS local

python3 linkfinder.py -i main.abc123.js -o results.html

 

# Analisar URL diretamente

python3 linkfinder.py -i https://alvo.com/static/js/main.abc123.js -o cli

 

# Analisar o domínio inteiro (crawl + análise de JS)

python3 linkfinder.py -i https://alvo.com -d -o results.html

 

# Filtrar apenas endpoints de API

python3 linkfinder.py -i https://alvo.com -d -o cli | grep -E "/api/|/v[0-9]+/"

 

# Ferramenta alternativa: subjs

go install github.com/lc/subjs@latest

echo "https://alvo.com" | subjs | xargs -I {} python3 linkfinder.py -i {} -o cli

 

 

Source Maps: o código-fonte original exposto

Source maps (arquivos .js.map) são gerados durante o build para facilitar o debug em produção. Quando deixados publicamente acessíveis, eles expõem o código-fonte original, antes da minificação, com nomes de variáveis, funções, rotas e comentários do desenvolvedor.

 

 

// Shell / Go

# Verificar se source maps estão expostos

# Os source maps ficam no mesmo path do JS, com extensão .map

curl -I https://alvo.com/static/js/main.abc123.js.map

 

# Automatizar a verificação para todos os JS encontrados

cat js_files.txt | while read url; do

map_url="${url}.map"

status=$(curl -s -o /dev/null -w "%{http_code}" "$map_url")

if [ "$status" = "200" ]; then

echo "[!] Source map exposto: $map_url"

fi

done


# Baixar e reconstruir o código original

# Ferramenta: sourcemapper

go install github.com/denandz/sourcemapper@latest

sourcemapper -url https://alvo.com/static/js/main.abc123.js.map -output ./src_reconstructed/


# Ferramenta alternativa: source-map-explorer

npm install -g source-map-explorer

source-map-explorer main.abc123.js main.abc123.js.map

 

# Ferramenta: unwebpack (reconstrução de bundles Webpack)

npm install -g unwebpack-sourcemap

unwebpack-sourcemap main.abc123.js.map ./output/

 

 

Regex para minerar endpoints de JS minificado

Quando source maps não estão disponíveis, é possível minerar o JS minificado diretamente com regex. O objetivo é extrair strings que parecem paths de API:

 

 

// Shell / Python

# Regex para extrair paths de API do JS minificado

# Executar no conteúdo de todos os JS baixados

 

# Padrão 1: strings que parecem paths de API

grep -oE '"/[a-zA-Z0-9_/-]{2,50}"' all_js_content.txt | sort -u

 

# Padrão 2: URLs completas de API

grep -oE 'https?://[a-zA-Z0-9./_-]+/api/[a-zA-Z0-9._/-]+' all_js_content.txt | sort -u

 

# Padrão 3: paths começando com /api/, /v1/, /v2/ etc.

grep -oE '"(/api/|/v[0-9]+/|/graphql|/rest/|/rpc/)[^"]*"' all_js_content.txt | sort -u


# Padrão 4: fetch() e axios calls

grep -oE "fetch(['"][^'"]+['"]" all_js_content.txt | grep -oE "['"][^'"]+['"]"

grep -oE "axios.(get|post|put|delete|patch)(['"][^'"]+['"]" all_js_content.txt

 

# Padrão 5: constantes de URL (comuns em React/Vue)

grep -oE "API_URLs*=s*['"][^'"]+['"]" all_js_content.txt

grep -oE "BASE_URLs*=s*['"][^'"]+['"]" all_js_content.txt

grep -oE "ENDPOINTs*=s*['"][^'"]+['"]" all_js_content.txt

 

# Script Python completo para minerar endpoints

python3 - <<'EOF'

import re, sys, glob


patterns = [

r'["'](/api/[^"'\s]{1,100})["']',

r'["'](/vd+/[^"'\s]{1,100})["']',

r'fetch(["'](https?://[^"']+)["']',

r'axios.w+(["'](https?://[^"']+)["']',

r'["'](https://[a-z0-9-]+.alvo.com/[^"'\s]{1,200})["']'

]


found = set()

for f in glob.glob('./js_dump/**/*.js', recursive=True):

content = open(f, errors='ignore').read()

for pat in patterns:

for m in re.findall(pat, content):

found.add(m)

 

for url in sorted(found):

print(url)

EOF

 

 

Variáveis de ambiente e segredos no JavaScript

Frameworks modernos (React, Vue, Next.js) injetam variáveis de ambiente no bundle JavaScript no momento do build. Qualquer variável prefixada com REACT_APP_NEXT_PUBLIC_VITE_ ou similar fica disponível publicamente no bundle. Isso frequentemente expõe chaves de API, URLs de serviços internos e tokens:

 

 

// Shell

# Buscar variáveis de ambiente expostas no JS

grep -oE "REACT_APP_[A-Z_]+=\s*['"][^'"]+['"]" all_js_content.txt

grep -oE "NEXT_PUBLIC_[A-Z_]+=\s*['"][^'"]+['"]" all_js_content.txt

grep -oE "VITE_[A-Z_]+\s*:\s*['"][^'"]+['"]" all_js_content.txt

 

# Buscar chaves e tokens diretamente

grep -oE "(api_key|apikey|api-key|secret|token|password|auth)["'\s]*[:=]["'\s]*[a-zA-Z0-9_\-]{10,}" all_js_content.txt -i

 

# Buscar URLs de serviços internos

grep -oE "https?://[a-z0-9.-]+\.(internal|local|corp|intranet|private)[^"'\s]*" all_js_content.txt

grep -oE "https?://(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)[^"'\s]+" all_js_content.txt

 

# Ferramenta: SecretFinder (especializada em segredos em JS)

git clone https://github.com/m4ll0k/SecretFinder.git

python3 SecretFinder.py -i https://alvo.com -e -o results.html

python3 SecretFinder.py -i main.abc123.js -o cli

 

 

Fase 3: Fuzzing ativo de diretórios e endpoints

Com as informações do recon passivo e da análise de JS, parte-se para a enumeração ativa: enviar requisições ao servidor tentando descobrir paths que existem, mas não foram encontradas ainda. As ferramentas principais são ffuf, feroxbuster e dirsearch.

ffuf: o padrão da indústria

 

// Shell / ffuf

# Instalação

go install github.com/ffuf/ffuf/v2@latest

 

# Fuzzing básico de diretórios

ffuf -u https://alvo.com/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \

-mc 200,201,301,302,401,403 -o ffuf_results.json -of json


# Fuzzing de endpoints de API com extensões

ffuf -u https://alvo.com/api/FUZZ -w wordlist.txt \

-e .json,.php,.asp,.aspx,.xml -mc all -fc 404 -o api_results.json

 

# Fuzzing com headers de autenticação

ffuf -u https://alvo.com/FUZZ -w wordlist.txt \

-H "Authorization: Bearer eyJhbGc..." -H "Cookie: session=abc123" \

-mc all -fc 404

 

# Fuzzing recursivo (entra em subdiretórios encontrados)

ffuf -u https://alvo.com/FUZZ -w wordlist.txt -recursion -recursion-depth 3 \

-mc 200,301,302,401,403 -o recursive_results.json -of json

 

# Fuzzing de parâmetros em endpoints conhecidos

ffuf -u https://alvo.com/api/users?FUZZ=1 -w params_wordlist.txt \

-mc all -fc 400,404 -fs 0

 

# Filtros úteis para reduzir falsos positivos

# -fc: filtrar por status code

# -fs: filtrar por tamanho de resposta (em bytes)

# -fw: filtrar por número de palavras

# -fl: filtrar por número de linhas

# -fr: filtrar por regex no corpo da resposta

 

# Rate limiting para evitar detecção

ffuf -u https://alvo.com/FUZZ -w wordlist.txt -p 0.1 -t 5  # 0.1s de delay, 5 threads

 

 

Wordlists: o que usar para cada contexto

 

Contexto Wordlist recomendada Onde Obter
Diretórios gerais directory-list-2.3-medium.txt SecLists / dirbuster
Endpoints de API REST api/api-endpoints.txt SecLists/Discovery/Web-Content
Arquivos comuns raft-medium-files.txt SecLists/Discovery/Web-Content
Parâmetros de query burp-parameter-names.txt SecLists/Discovery/Web-Content
Subdomains subdomains-top1million-5000.txt SecLists/Discovery/DNS
Paths de admin AdminPanels.fuzz.txt SecLists/Discovery/Web-Content
Nomes de backup backup-filenames.txt SecLists/Discovery/Web-Content
Rotas Next.js/Nuxt next-js-routes.txt kaeferjaeger.gay wordlists
APIs comuns (custom) Construir com waybackurls + JS mining Processo descrito neste artigo

 

Construindo wordlists customizadas a partir do alvo

A wordlist mais eficaz é a construída especificamente para o alvo, combinando dados do waybackurls, da análise de JS e de dicionários genéricos:

 

// Shell / Bash

#!/usr/bin/env bash

# Gerar wordlist customizada para o alvo

 

TARGET="alvo.com"

 

echo "[*] Coletando URLs históricas..."

waybackurls $TARGET | grep -oE "(/[a-zA-Z0-9_/-]+)" | sort -u > wordlist_wayback.txt

 

echo "[*] Extraindo paths do JavaScript..."

getJS --url https://$TARGET --complete | xargs -I {} \

python3 linkfinder.py -i {} -o cli 2>/dev/null | \

grep -oE "(/[a-zA-Z0-9_/-]{2,50})" | sort -u > wordlist_js.txt

 

echo "[*] Combinando com wordlists genéricas..."

cat wordlist_wayback.txt wordlist_js.txt \

/usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \

/usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt | \

sort -u | \

grep -v "#" | \

awk 'length > 2 && length < 60' > wordlist_custom.txt

 

echo "[*] Total de entries: $(wc -l < wordlist_custom.txt)"

echo "[*] Iniciando fuzzing com wordlist customizada..."

ffuf -u https://$TARGET/FUZZ -w wordlist_custom.txt -mc all -fc 404 -o results.json -of json


feroxbuster: fuzzing recursivo e rápido

 

 

// Shell / feroxbuster

# Instalação

cargo install feroxbuster

# ou: apt install feroxbuster

 

# Fuzzing recursivo com detecção automática de subdiretórios

feroxbuster --url https://alvo.com --wordlist wordlist.txt \

--depth 3 --threads 50 --output results.txt

 

 

# Com headers de autenticação

feroxbuster --url https://alvo.com \

--wordlist wordlist.txt \

--headers "Authorization: Bearer TOKEN" \

--headers "Cookie: session=abc" \

--status-codes 200,201,301,302,401,403

 

# Fuzzing de extensões específicas

feroxbuster --url https://alvo.com \

--wordlist wordlist.txt \

--extensions php,asp,aspx,json,xml,bak,env \

--filter-status 404,429

 

# Modo silencioso com output formatado

feroxbuster --url https://alvo.com \

--wordlist wordlist.txt \

--quiet \

--output ferox_results.txt

 

 

// Shell / feroxbuster

# Instalação

cargo install feroxbuster

# ou: apt install feroxbuster

 

# Fuzzing recursivo com detecção automática de subdiretórios

feroxbuster --url https://alvo.com --wordlist wordlist.txt \

--depth 3 --threads 50 --output results.txt


# Com headers de autenticação

feroxbuster --url https://alvo.com \

--wordlist wordlist.txt \

--headers "Authorization: Bearer TOKEN" \

--headers "Cookie: session=abc" \

--status-codes 200,201,301,302,401,403

 

# Fuzzing de extensões específicas

feroxbuster --url https://alvo.com \

--wordlist wordlist.txt \

--extensions php,asp,aspx,json,xml,bak,env \

--filter-status 404,429

 

# Modo silencioso com output formatado

feroxbuster --url https://alvo.com \

--wordlist wordlist.txt \

--quiet \

--output ferox_results.txt

 

 

Fase 4: Tricks específicos por framework

Cada framework tem estruturas de URL previsíveis, arquivos de configuração próprios e pontos de exposição específicos. Conhecer essas características multiplica a eficácia do recon.

Next.js

Next.js é o framework React mais popular para produção. Ele gera rotas de API em /api/ e expõe estruturas previsíveis que podem ser exploradas:

 

 

// Shell / Next.js

# Estrutura de rotas Next.js:

# /api/*              -> API Routes (server-side, podem ter qualquer lógica)

# /_next/static/      -> assets estáticos (JS chunks, CSS)

# /_next/data/        -> dados pré-renderizados (JSON com dados da página)

# /api/auth/*         -> autenticação (NextAuth.js)

 

# Encontrar dados pré-renderizados (/_next/data/)

# Esses endpoints retornam o JSON usado pelo getServerSideProps/getStaticProps

# Formato: /_next/data/[build_id]/[pagina].json

 

# Passo 1: descobrir o build ID (presente em qualquer JS do bundle)

curl -s https://alvo.com | grep -oE '"buildId":"[^"]+"'

# Resultado: "buildId":"abc123xyz"

 

# Passo 2: acessar dados pré-renderizados de páginas conhecidas

curl https://alvo.com/_next/data/abc123xyz/index.json

curl https://alvo.com/_next/data/abc123xyz/dashboard.json

curl https://alvo.com/_next/data/abc123xyz/admin.json

curl https://alvo.com/_next/data/abc123xyz/profile.json

curl https://alvo.com/_next/data/abc123xyz/users.json

 

# Fuzzing de /_next/data/ com páginas comuns

ffuf -u "https://alvo.com/_next/data/abc123xyz/FUZZ.json" \

-w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt \

-mc 200

 

# Encontrar todas as API Routes via análise do bundle JS

grep -oE '"/api/[a-zA-Z0-9/_-]+"' *.js | sort -u

 

# Verificar NextAuth endpoints (autenticação)

curl https://alvo.com/api/auth/providers

curl https://alvo.com/api/auth/session

curl https://alvo.com/api/auth/csrf


# Encontrar rotas dinâmicas expostas

# [id].js -> /api/users/1, /api/users/2...

# [...slug].js -> captura qualquer path

 

# Wordlist específica para Next.js API Routes

ffuf -u https://alvo.com/api/FUZZ \

-w next-js-api-routes.txt -mc all -fc 404

 

 

React (SPA) e Vue

 

 

// Shell / JS

# React/Vue SPA: toda a lógica de roteamento está no JS

# O servidor serve index.html para qualquer rota (client-side routing)

 

# Passo 1: extrair rotas definidas no React Router / Vue Router

grep -oE 'path:s*["'][^"']+["']' *.js | sort -u

grep -oE '<Routes+path=["'][^"']+["']' *.js | sort -u

 

# Padrão de rotas no React Router v6

grep -oE '"s*/[a-zA-Z0-9/:_-]+"' main.*.js | grep -E "^"/" | sort -u

 

# Passo 2: mapear chamadas de API no código

grep -oE 'axios.(get|post|put|delete)(["'][^"']+["']' *.js | sort -u

grep -oE 'fetch(["'][^"']+["']' *.js | sort -u

grep -oE 'api.[a-zA-Z]+(["'][^"']+["']' *.js | sort -u

 

# Passo 3: encontrar a URL base da API (environment variable)

grep -oE "process.env.[A-Z_]+" *.js | sort -u

grep -oE "import.meta.env.[A-Z_]+" *.js | sort -u

 

# Vue Router: extrair rotas do bundle

grep -oE 'path:s*"[^"]+"' *.js | grep -oE '"[^"]+"' | sort -u

 

# Vuex/Pinia store actions: revelar nomes de endpoints

grep -oE "actionss*:s*{[^}]+}" *.js

Angular

 

// Shell / Angular

# Angular: rotas definidas nos módulos de roteamento

# Buscar no bundle por RouterModule e definições de rotas

 

grep -oE 'path:s*["'][^"']*["']' main.*.js | sort -u

grep -oE '{path:["'][^"']*["']' main.*.js | sort -u

 

# Services Angular: onde as chamadas HTTP estão definidas

# Buscar por HttpClient calls

grep -oE 'this.http.(get|post|put|delete)(["'][^"']+["']' *.js | sort -u

grep -oE '"[^"]*"[,s]*{[^}]*responseType' *.js | sort -u

 

# Angular environment files (prodution vs development)

# environment.ts / environment.prod.ts sao compilados no bundle

grep -oE 'apiUrls*:s*["'][^"']+["']' *.js | sort -u

grep -oE 'baseUrls*:s*["'][^"']+["']' *.js | sort -u

 

# Lazy-loaded modules: o Angular carrega chunks separados

# Verificar o manifesto de chunks para descobrir módulos ocultos

curl https://alvo.com/main.*.js | grep -oE 'chunk-[a-zA-Z0-9]+.js'

 

 

Laravel, Django, Rails: endpoints do backend

 

// Shell / Frameworks

# Laravel: estrutura previsível

# /api/ -> rotas de API definidas em routes/api.php

# /_debugbar -> laravel debugbar (em modo dev)

# /telescope -> laravel telescope (monitoramento)

# /horizon -> laravel horizon (queue monitoring)

# /nova -> laravel nova (admin panel)

# /sanctum/csrf-cookie -> autenticação Sanctum

 

# Verificar exposição de ferramentas Laravel

curl -s https://alvo.com/_debugbar/open | head -c 200

curl -s https://alvo.com/telescope/api/requests

curl -s https://alvo.com/horizon/api/stats

curl -s https://alvo.com/nova

 

# Django: estrutura previsível

# /admin/ -> Django Admin (interface de admin padrão)

# /api/ -> Django REST Framework

# /api/v1/, /api/v2/ -> endpoints versionados

# /django-admin/ -> admin em path alternativo

# /static/ -> arquivos estáticos

# /__debug__/ -> django-debug-toolbar


# Verificar Django Admin e debug

curl -s https://alvo.com/admin/

curl -s https://alvo.com/__debug__/

curl -s https://alvo.com/api/schema/ # DRF schema autogenerado

curl -s https://alvo.com/api/docs/   # DRF browsable API

 

# Ruby on Rails: estrutura previsível

# /rails/info -> informações do framework (em dev)

# /rails/mailers -> previa de emails

# /admin -> activeadmin

# GET /api/v1/users.json -> padrão Rails de formato JSON

 

# Verificar exposição Rails

curl -s https://alvo.com/rails/info/properties

curl -s https://alvo.com/rails/info/routes

 

 

GraphQL, Swagger e documentação de API exposta

 

// Shell / Bash

# GraphQL: endpoints comuns

endpoints_graphql=(

"/graphql" "/graphiql" "/playground"

"/api/graphql" "/v1/graphql" "/v2/graphql"

"/graphql/console" "/graphql/playground"

)

for ep in "${endpoints_graphql[@]}"; do

status=$(curl -s -o /dev/null -w "%{http_code}" "https://alvo.com$ep")

echo "$status -> https://alvo.com$ep"

done

 

# Swagger / OpenAPI: documentação completa da API exposta

endpoints_swagger=(

"/swagger" "/swagger-ui" "/swagger-ui.html"

"/api-docs" "/api/docs" "/docs"

"/openapi.json" "/swagger.json"

"/v1/swagger.json" "/v2/swagger.json"

"/api/openapi" "/redoc" "/rapidoc"

"/swagger/index.html" "/api/swagger"

)

for ep in "${endpoints_swagger[@]}"; do

status=$(curl -s -o /dev/null -w "%{http_code}" "https://alvo.com$ep")

[ "$status" != "404" ] && echo "[!] $status -> https://alvo.com$ep"

done

 

# Extrair todos os endpoints do Swagger encontrado

# Ferramenta: swagger-parser

curl -s https://alvo.com/openapi.json | python3 - <<'EOF'

import json, sys

data = json.load(sys.stdin)

base = data.get("servers", [{}])[0].get("url", "")

for path, methods in data.get("paths", {}).items():

for method in methods:

print(f"{method.upper()} {base}{path}")

EOF


 

Fase 5: Infraestrutura, subdomains e ambientes esquecidos

Descoberta e enumeração de subdomínios

 

 

// Shell

# Pipeline completo de subdomain discovery

 

# 1. Passive (sem tocar o alvo)

subfinder -d alvo.com -all -silent > passive_subs.txt

amass enum -passive -d alvo.com >> passive_subs.txt

curl -s "https://crt.sh/?q=%.alvo.com&output=json" | \

python3 -c "import json,sys; [print(e['name_value']) for e in json.load(sys.stdin)]" >> passive_subs.txt

 

# 2. Brute force DNS (ativo)

ffuf -u "https://FUZZ.alvo.com" \

-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \

-mc 200,301,302,401,403 -H "Host: FUZZ.alvo.com"

 

# ferramenta alternativa com DNS brute force

dnsx -d alvo.com -w subdomains-wordlist.txt -silent -a -cname >> passive_subs.txt

 

# 3. Limpar e deduplicar

sort -u passive_subs.txt | grep -v "^*" > all_subs.txt

 

# 4. Verificar quais estão ativos

cat all_subs.txt | httpx -silent -status-code -title -tech-detect \

-ports 80,443,8080,8443,3000,4000,5000,8000,8888 \

-o live_subs.txt

 

# 5. Identificar subdomains interessantes

grep -E "api|admin|internal|dev|staging|beta|test|qa|uat|old|legacy|backup|auth|login|dashboard|manage" live_subs.txt

 

 

Encontrar ambientes de staging e desenvolvimento

Ambientes de staging e desenvolvimento frequentemente têm autenticação mais fraca, dados reais e funcionalidades não disponíveis em produção. Eles são encontrados por convenção de nomes:

 

 

// Shell / Bash

# Convenções de nome comuns para ambientes não-produção

prefixos=(dev staging stage test qa uat beta alpha sandbox demo

preview release canary pilot internal corp intranet)

sufixos=(dev staging test qa uat)

 

# Testar combinações

for prefix in "${prefixos[@]}"; do

for domain in alvo.com api.alvo.com app.alvo.com; do

url="https://${prefix}.${domain}"

status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url")

[ "$status" != "000" ] && echo "$status -> $url"

done

done

 

# Procurar no Wayback Machine por subdomínios históricos

waybackurls alvo.com | grep -oE "https?://[a-zA-Z0-9.-]+.alvo.com" | sort -u

 

# Verificar registros DNS históricos via SecurityTrails

curl -s "https://api.securitytrails.com/v1/domain/alvo.com/subdomains" \

-H "APIKEY: seu_token" | python3 -m json.tool

 

# Verificar CORS mal configurado (revela domínios internos confiados)

curl -H "Origin: https://evil.com" -I https://alvo.com/api/users | grep -i "access-control"

# Se retornar: Access-Control-Allow-Origin: * -> qualquer origem aceita

 

Arquivos de configuração e backups expostos

 

// Shell / Bash

# Arquivos que não deveriam estar públicos mas frequentemente estão

arquivos=(

".env" ".env.local" ".env.production" ".env.backup"

".git/config" ".git/HEAD" ".git/COMMIT_EDITMSG"

"config.js" "config.json" "config.php" "config.yaml"

"database.yml" "database.json" "db.json"

"wp-config.php" "configuration.php" "settings.py"

"docker-compose.yml" "docker-compose.yaml"

"Dockerfile" ".dockerenv"

"package.json" "composer.json" "Gemfile"

"robots.txt" "sitemap.xml" "crossdomain.xml"

"phpinfo.php" "info.php" "test.php" "debug.php"

"backup.zip" "backup.tar.gz" "site.zip" "www.zip"

".DS_Store" "Thumbs.db" "desktop.ini"

"readme.txt" "README.md" "CHANGELOG.md"

"server-status" "server-info"

)

 

for f in "${arquivos[@]}"; do

status=$(curl -s -o /dev/null -w "%{http_code}" "https://alvo.com/$f")

if [[ "$status" =~ ^(200|206)$ ]]; then

echo "[!] EXPOSTO $status -> https://alvo.com/$f"

fi

done

 

# Verificar exposição de repositório .git

curl -s https://alvo.com/.git/config | head -20

# Se retornar configuração: repositório exposto

 

# Ferramenta: GitDumper (extrair repositório exposto)

git clone https://github.com/internetwache/GitTools.git

./GitTools/Dumper/gitdumper.sh https://alvo.com/.git/ ./git_dump/

./GitTools/Extractor/extractor.sh ./git_dump/ ./extracted_src/

 

 

Fase 6: Automatizando o pipeline completo de recon

Em engajamentos reais, o recon precisa ser sistemático e documentado. O pipeline abaixo combina todas as técnicas anteriores em um fluxo automatizado:

 

// Bash / Pipeline

#!/usr/bin/env bash

# endpoint_discovery.sh - Pipeline completo de recon

# Uso: ./endpoint_discovery.sh alvo.com

 

TARGET="${1:?Usage: $0 <domain>}"

OUTPUT_DIR="./recon_${TARGET//[^a-zA-Z0-9]/_}"

mkdir -p $OUTPUT_DIR/{subdomains,js_files,endpoints,wordlists,active}

 

echo "[1/8] Subdomain discovery..."

subfinder -d $TARGET -all -silent 2>/dev/null > $OUTPUT_DIR/subdomains/passive.txt

curl -s "https://crt.sh/?q=%.$TARGET&output=json" 2>/dev/null | \

python3 -c "import json,sys; [print(e['name_value']) for e in json.load(sys.stdin)]" \

>> $OUTPUT_DIR/subdomains/passive.txt

sort -u $OUTPUT_DIR/subdomains/passive.txt > $OUTPUT_DIR/subdomains/all.txt

echo "    Found $(wc -l < $OUTPUT_DIR/subdomains/all.txt) unique subdomains"

 

echo "[2/8] Probing live hosts..."

cat $OUTPUT_DIR/subdomains/all.txt | httpx -silent -status-code -ports 80,443,8080,8443 \

-o $OUTPUT_DIR/subdomains/live.txt

echo "    Found $(wc -l < $OUTPUT_DIR/subdomains/live.txt) live hosts"

 

echo "[3/8] Historical URLs..."

waybackurls $TARGET > $OUTPUT_DIR/endpoints/wayback.txt

gau $TARGET --subs >> $OUTPUT_DIR/endpoints/wayback.txt

sort -u $OUTPUT_DIR/endpoints/wayback.txt -o $OUTPUT_DIR/endpoints/wayback.txt

echo "    Found $(wc -l < $OUTPUT_DIR/endpoints/wayback.txt) historical URLs"

 

echo "[4/8] Collecting JavaScript files..."

getJS --url https://$TARGET --complete 2>/dev/null > $OUTPUT_DIR/js_files/urls.txt

echo "    Found $(wc -l < $OUTPUT_DIR/js_files/urls.txt) JS files"

 

echo "[5/8] Analyzing JavaScript for endpoints..."

cat $OUTPUT_DIR/js_files/urls.txt | while read url; do

python3 ~/tools/LinkFinder/linkfinder.py -i "$url" -o cli 2>/dev/null

done | sort -u > $OUTPUT_DIR/endpoints/from_js.txt

echo "    Extracted $(wc -l < $OUTPUT_DIR/endpoints/from_js.txt) endpoints from JS"

 

echo "[6/8] Checking for source maps..."

cat $OUTPUT_DIR/js_files/urls.txt | while read url; do

status=$(curl -s -o /dev/null -w "%{http_code}" "${url}.map")

[ "$status" = "200" ] && echo "[!] Source map exposed: ${url}.map"

done > $OUTPUT_DIR/js_files/sourcemaps.txt


echo "[7/8] Building custom wordlist..."

cat $OUTPUT_DIR/endpoints/wayback.txt $OUTPUT_DIR/endpoints/from_js.txt | \

grep -oE "(/[a-zA-Z0-9_/-]+)" | sort -u > $OUTPUT_DIR/wordlists/custom.txt

wc -l $OUTPUT_DIR/wordlists/custom.txt

 

echo "[8/8] Active fuzzing..."

ffuf -u "https://$TARGET/FUZZ" \

-w $OUTPUT_DIR/wordlists/custom.txt \

-mc all -fc 404 -t 40 -p 0.05 \

-o $OUTPUT_DIR/active/ffuf_results.json -of json -silent

 

echo "[DONE] Results in $OUTPUT_DIR"

echo "Summary:"

echo "  Subdomains: $(wc -l < $OUTPUT_DIR/subdomains/all.txt)"

echo "  Live hosts: $(wc -l < $OUTPUT_DIR/subdomains/live.txt)"

echo "  Historical URLs: $(wc -l < $OUTPUT_DIR/endpoints/wayback.txt)"

echo "  JS endpoints: $(wc -l < $OUTPUT_DIR/endpoints/from_js.txt)"

 

 

Arsenal de ferramentas: instalação e uso rápido

 

Ferramentas Instalação Uso principal Melhor para
ffuf go install github.com/ffuf/ffuf/v2@latest Fuzzing de diretórios e endpoints Todos os contextos de fuzzing ativo
feroxbuster cargo install feroxbuster Fuzzing recursivo automatico Sites com estrutura de subdiretórios
waybackurls go install github.com/tomnomnom/waybackurls@latest URLs históricas do Wayback Machine Encontrar endpoints legados
gau go install github.com/lc/gau/v2/cmd/gau@latest URLs de múltiplas fontes históricas Complementar ao waybackurls
subfinder go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest Subdomains passivos multi-fonte Mapeamento de superfície de ataque
httpx go install github.com/projectdiscovery/httpx/cmd/httpx@latest Probe de URLs e detecção de tecnologia Verificar quais hosts estão ativos
LinkFinder git clone + pip3 install -r requirements.txt Extrair URLs de arquivos JS Análise de bundles de SPA
getJS go install github.com/003random/getJS@latest Coletar todos os JS de um domínio Primeira etapa de análise de JS
sourcemapper go install github.com/denandz/sourcemapper@latest Reconstruir código de source maps Quando source maps estão expostos
SecretFinder git clone + pip3 install -r requirements.txt Encontrar segredos em JS Chaves, tokens, variáveis sensíveis
amass go install github.com/owasp-amass/amass/v4/…@master Enumeração avançada de subdomains Mapeamento profundo de infraestrutura
dnsx go install github.com/projectdiscovery/dnsx/cmd/dnsx@latest Resolução e brute force DNS Validar subdomínios e encontrar novos

 

 

Checklist de endpoint discovery por engajamento

Recon passivo

  • Google Dorks executados: arquivos, painel admin, documentação de API, env files.
  • waybackurls + gau executados e URLs históricas filtradas por extensão e path.
  • Certificate Transparency consultado (crt.sh + subfinder).
  • Shodan/Censys consultados para o ASN/org do alvo.
  • txt e sitemap.xml verificados.

Análise de JavaScript

  • Todos os arquivos JS identificados e baixados via getJS.
  • LinkFinder executado em cada JS para extrair endpoints.
  • Source maps verificados para cada JS: se expostos, código original reconstruído.
  • Regex executada no JS minificado para extrair paths e URLs.
  • Variáveis de ambiente e segredos buscados no bundle.
  • Rotas do framework identificadas (React Router, Vue Router, Next.js API Routes).
  • Chamadas de API extraídas (fetch, axios, HttpClient).

Enumeração ativa

  • ffuf/feroxbuster executados com wordlist genérica.
  • Wordlist customizada construída combinando wayback + JS mining + genérica.
  • Fuzzing recursivo realizado para subdiretórios encontrados.
  • Extensões relevantes para o stack testadas (.php, .asp, .json, .bak, .env).
  • Endpoints de API fuzzados (ffuf -u /api/FUZZ com wordlist de API).

Infraestrutura e subdomains

  • Subdomínios passivos coletados (subfinder + amass + crt.sh).
  • Força bruta DNS realizada com wordlist de subdomínios.
  • Subdomínios ativos identificados via httpx com detecção de tecnologia.
  • Subdomínios de staging/dev procurados por convenção de nomes.
  • Arquivos de configuração e backup comuns verificados em todos os hosts.
  • Repositório .git verificado: se exposto, conteúdo extraído.

Específicos de framework

  • js: buildId extraído, /_next/data/ fuzzado, /api/* mapeado.
  • GraphQL: endpoints comuns testados, introspecção verificada.
  • Swagger/OpenAPI: documentação exposta procurada e endpoints extraídos.
  • Django/Laravel: /admin/, /telescope/, /horizon/ verificados.
  • CORS: política verificada para origens aceitas.

 

O Endpoint Discovery é a combinação de recon passivo (Wayback, Google Dorks, CT logs), análise profunda de JavaScript (bundles, source maps, extração de rotas) e fuzzing ativo estruturado com wordlists customizadas para o alvo.

Em aplicações modernas baseadas em React, Vue, Angular ou Next.js, o JavaScript do frontend é frequentemente a fonte mais rica de informação sobre a arquitetura do sistema. Source maps expostos entregam código-fonte completo. Variáveis de ambiente no bundle entregam chaves e URLs internas. Rotas definidas no client-side router entregam o mapa completo da aplicação.

Na Vantico, a fase de recon é tratada como parte crítica de cada engajamento. A qualidade do recon determina a qualidade das descobertas: endpoints encontrados apenas via análise de JavaScript ou source maps expostos frequentemente levam aos achados de maior severidade, justamente porque nunca foram submetidos a revisão de segurança.

A plataforma da Vantico permite registrar e organizar cada endpoint descoberto com o método de discovery, evidência e status de teste, mantendo rastreabilidade completa entre o recon e os achados finais.

Conheça outros artigos técnicos da Vantico clicando aqui.

Siga a Vantico nas redes sociais e fique informado sobre tecnologia e insights da área.


Júlia Valim Júlia Valim

Agende uma demonstração com a Vantico

Agendar demonstração