Voltar para o blog

Endpoint Discovery: JS Tricks e Recon Ofensivo

19/06/2026 29 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 históricas do domínio
waybackurls alvo.com | tee wayback_urls.txt
  • Filtrar por extensão ou padrão
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

  • Painéis 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

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