Skip to content

Instantly share code, notes, and snippets.

@dzogrim
Last active July 8, 2025 11:53
Show Gist options
  • Save dzogrim/bc9ef20d5004e9e6da677dd38b2ebb4f to your computer and use it in GitHub Desktop.
Save dzogrim/bc9ef20d5004e9e6da677dd38b2ebb4f to your computer and use it in GitHub Desktop.
Vérifie l'existence de workspaces en générant des sous-domaines potentiels (golang & bash)
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2025 Sébastien L.
// SPDX-FilePurpose: POC
// SPDX-FileComment: Programme à usage démonstratif
// Version: 1.0.0
// Date: 2025-06-14
//
// slack-look-up.go — Vérifie l'existence de workspaces Slack en générant
// et testant des sous-domaines potentiels (HTTP HEAD).
//
// Usage :
// go run slack-look-up.go -help
// go run slack-look-up.go -quiet
// go run slack-look-up.go -quiet -workers 2 -delay 1s
// Build :
// go build -o slack-look-up slack-look-up.go
package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"strings"
"sync"
"time"
)
// Config contient les paramètres de configuration pour l'exécution du script
// comme les combinaisons de noms, les délais, la sortie de log, etc.
type Config struct {
Prefixes []string
Fixes []string
Suffixes []string
LogFile string
Quiet bool
Delay time.Duration
Timeout time.Duration
Workers int
}
// cfg contient la configuration par défaut utilisée pour l'exécution...
var cfg = Config{
Prefixes: []string{"itmanager", "itmanagers", "it-manager", "it-managers"},
Fixes: []string{"stepup", "step-up", "scaleup", "startup", "team", "group", "lead", "leaders"},
Suffixes: []string{"fr"},
LogFile: "/tmp/slack_check.log",
Delay: 2 * time.Second,
Timeout: 10 * time.Second,
Workers: 4,
}
// init configure les flags en ligne de commande pour le script.
// --quiet : masque les sorties des tests en cours.
// --delay : définit le délai entre les requêtes (ex: 2s, 500ms…).
// --workers : nombre de goroutines concurrentes pour les vérifications.
// Les valeurs sont liées directement au champ correspondant de la struct Config.
func init() {
flag.BoolVar(&cfg.Quiet, "quiet", false, "Ne pas afficher les tests en cours")
flag.DurationVar(&cfg.Delay, "delay", cfg.Delay, "Temps entre chaque requête")
flag.IntVar(&cfg.Workers, "workers", cfg.Workers, "Nombre de workers parallèles")
flag.Parse()
}
// generateDomains crée toutes les combinaisons possibles de sous-domaines Slack
// en combinant préfixes, fixes et suffixes selon la logique souhaitée.
func generateDomains(c Config) []string {
domains := make([]string, 0)
for _, p := range c.Prefixes {
domains = append(domains, p)
for _, f := range c.Fixes {
domains = append(domains, p+f)
for _, s := range c.Suffixes {
domains = append(domains, p+f+s)
domains = append(domains, fmt.Sprintf("%s-%s-%s", p, f, s))
}
}
}
return domains
}
// checkURL effectue une requête HEAD HTTP sur l'URL donnée avec un timeout défini.
// Retourne le code HTTP reçu ou une erreur si la requête échoue.
func checkURL(url string, timeout time.Duration) (int, error) {
client := http.Client{Timeout: timeout}
resp, err := client.Head(url)
if err != nil {
return 0, err
}
defer resp.Body.Close()
return resp.StatusCode, nil
}
// writeLog ajoute une ligne de texte au fichier de log spécifié.
// - Crée le fichier s'il n'existe pas, ou l'ouvre en mode ajout.
// - Écrit la ligne suivie d’un saut de ligne.
// - Gère les erreurs d'ouverture avec un message sur stderr.
func writeLog(path, line string) {
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "Erreur d'écriture du log: %v\n", err)
return
}
defer f.Close()
f.WriteString(line + "\n")
}
// worker consomme des sous-domaines depuis un canal, les teste avec checkURL,
// affiche le résultat formaté avec couleurs, et écrit dans le fichier de log.
// Chaque worker attend une pause entre les requêtes pour éviter le flood.
func worker(domains <-chan string, wg *sync.WaitGroup, cfg Config, mu *sync.Mutex) {
defer wg.Done()
for sub := range domains {
url := fmt.Sprintf("https://%s.slack.com", sub)
if !cfg.Quiet {
fmt.Printf("Testing %s ...\n", url)
}
code, err := checkURL(url, cfg.Timeout)
var result string
if err != nil {
result = fmt.Sprintf("[NO RESPONSE] %s", url)
} else {
switch code {
case 200:
result = fmt.Sprintf("\033[1;32m[FOUND: HTTP 200]\033[0m %s", url)
case 301, 302, 303:
result = fmt.Sprintf("\033[1;33m[REDIRECT: %d]\033[0m %s", code, url)
case 403, 404:
result = fmt.Sprintf("\033[1;31m[NOT FOUND: %d]\033[0m %s", code, url)
default:
result = fmt.Sprintf("\033[1;90m[UNKNOWN STATUS: %d]\033[0m %s", code, url)
}
}
fmt.Println(result)
mu.Lock()
writeLog(cfg.LogFile, result)
mu.Unlock()
time.Sleep(cfg.Delay)
}
}
// runChecks orchestre l'exécution parallèle des vérifications HTTP.
// - Supprime le fichier de log s'il existe déjà.
// - Génère la liste complète des sous-domaines à tester.
// - Lance un pool de workers concurrents pour traiter les domaines via un canal.
// - Attend la fin de tous les workers avant de terminer.
func runChecks(cfg Config) {
os.Remove(cfg.LogFile)
domains := generateDomains(cfg)
jobs := make(chan string, len(domains))
var wg sync.WaitGroup
var mu sync.Mutex
for i := 0; i < cfg.Workers; i++ {
wg.Add(1)
go worker(jobs, &wg, cfg, &mu)
}
for _, d := range domains {
jobs <- d
}
close(jobs)
wg.Wait()
}
// printSummary affiche la liste des sous-domaines avec code 200 (trouvés),
// suivie d'un compteur total. Utilise des couleurs ANSI pour plus de lisibilité.
func printSummary(path string) {
fmt.Println("\n\033[1;32m=== SUMMARY: FOUND ===\033[0m")
file, err := os.Open(path)
if err != nil {
fmt.Fprintf(os.Stderr, "Erreur lecture log: %v\n", err)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
count := 0
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "[FOUND: HTTP 200]") {
fmt.Printf("\033[1;32m%s\033[0m\n", line)
count++
}
}
fmt.Printf("\033[1;32mTotal FOUND: %d\033[0m\n", count)
}
// Main
func main() {
runChecks(cfg)
printSummary(cfg.LogFile)
}

slack-look-up

POC démonstratif pour tester l'existence de workspaces Slack via des sous-domaines supposés.

Ce projet propose deux versions (Bash et Go) d’un outil qui génère des combinaisons de sous-domaines Slack (*.slack.com) et vérifie s’ils existent via une requête HTTP HEAD.


🔧 Fonctionnalités

  • Génération combinatoire (préfixes, fixes, suffixes)
  • Requêtes HTTP HEAD avec gestion du délai
  • Résultat coloré en ligne de commande
  • Log dans /tmp/slack_check.log
  • Résumé final avec compteur des domaines existants (HTTP 200)
  • Version Go : exécution concurrente (workers), CLI via flag

📁 Fichiers

  • slack-look-up.sh — Version Bash (portable, dépend de curl, awk, grep)
  • slack-look-up.go — Version Go (plus rapide, parallélisme, extensible)

▶️ Utilisation

🐚 Bash

chmod +x slack-look-up.sh
./slack-look-up.sh          # mode normal
./slack-look-up.sh -q       # mode silencieux

Bash ≥ 4.3 recommandé pour les systèmes comme macOS (utiliser brew install bash ou Mac Ports)

🧬 Go

Exécution directe :

go run slack-look-up.go

Compilation + exécution :

go build -o slack-look-up slack-look-up.go
./slack-look-up -q --workers 3 --delay 1500ms

📝 Exemples de sous-domaines générés

  • itmanagerstepupfr.slack.com
  • it-managers-group-fr.slack.com
  • itmanagersstartupfr.slack.com
  • etc.

📄 Licence

MIT — © 2025 Sébastien L.


❓ À propos

Ce script est conçu dans un but démonstratif et exploratoire.
Il ne scanne que des domaines Slack publics valides et ne contourne aucune authentification.

#!/usr/bin/env bash
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2025 Sébastien L.
# SPDX-FilePurpose: POC
# SPDX-FileComment: Script à usage démonstratif
#
# slack-look-up.sh — Vérifie l'existence de workspaces Slack en générant des sous-domaines potentiels.
#
# Génère des combinaisons de noms de workspace à partir de préfixes, fixes et suffixes
# et teste chaque sous-domaine Slack pour détecter s'il renvoie une page valide (code 200),
# une redirection, une erreur ou un code inconnu.
#
# Auteur : Sébastien L.
# Licence : MIT
# Version: 1.0.0
# Date: 2025-06-14
# === Couleurs ANSI pour affichage lisible ===
GREEN="\033[1;32m"
RED="\033[1;31m"
YELLOW="\033[1;33m"
GRAY="\033[1;90m"
RESET="\033[0m"
base="https://"
# 1. Préfixes (imposés)
# shellcheck disable=SC2034
prefixes=("itmanager" "itmanagers" "it-manager" "it-managers")
# 2. Fixes (internes)
# shellcheck disable=SC2034
fixes=("stepup" "step-up" "scaleup" "startup" "team" "group" "lead" "leaders")
# 3. Suffixes (géographiques ou temporels)
# shellcheck disable=SC2034
suffixes=("fr")
# === Fonction d'aide ===
usage() {
echo -e "${GREEN}Usage:${RESET} $(basename "$0") [--quiet|-q] [--help|-h]"
echo
echo " -q, --quiet, Ne pas afficher les tests en cours"
echo " -h, --help, Afficher cette aide"
echo
exit 0
}
if [[ "$(uname)" == "Darwin" ]]; then
if [[ -z "${BASH_VERSINFO[0]}" || "${BASH_VERSINFO[0]}" -lt 4 || ( "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -lt 3 ) ]]; then
echo "Bash ≥ 4.3 requis (fonction 'local -n' non supportée par cette version)." >&2
echo "Installe un Bash moderne (ex: 'brew install bash' sur macOS) ;" >&2
echo "Puis relance le script avec la version de bash à jour :" >&2
echo "par ex. : /opt/local/bin/bash $0 -h" >&2
exit 1
fi
fi
# Vérifie les dépendances
required_bins=("curl" "awk" "grep" "sleep")
for bin in "${required_bins[@]}"; do
if ! command -v "$bin" >/dev/null 2>&1; then
printf "${RED}❌ Erreur : '%s' ${RESET}requis mais non trouvé dans : %s.\n" "$bin" "$PATH" >&2
exit 1
fi
done
# === Fonction : génère les sous-domaines Slack à tester ===
generate_domains() {
local -n pre=$1
local -n fix=$2
local -n suf=$3
local domains=()
for p in "${pre[@]}"; do
domains+=("$p") # préfixe seul
for f in "${fix[@]}"; do
domains+=("${p}${f}")
for s in "${suf[@]}"; do
domains+=("${p}${f}${s}") # sans tiret
domains+=("${p}-${f}-${s}") # avec tirets
done
done
done
echo "${domains[@]}"
}
# Gestion des arguments
case "$1" in
-q|--quiet)
QUIET=true
;;
-h|--help)
usage
;;
"")
QUIET=false
;;
*)
echo -e "${RED}Argument invalide :$RESET $1"
usage
;;
esac
# Fichier de log
log="/tmp/slack_check.log"
# Vide proprement le log
true > "$log"
# Génère les domaines candidats
# shellcheck disable=SC2207
candidates=($(generate_domains prefixes fixes suffixes))
# === Boucle de test des URLs générées ===
for subdomain in "${candidates[@]}"; do
url="${base}${subdomain}.slack.com"
$QUIET || echo -e "Testing ${GRAY}$url${RESET} ..."
status=$(curl -s -I --max-time 10 -A "Mozilla/5.0" "$url" | grep -i "^HTTP" | tail -1)
code=$(echo "$status" | awk '{print $2}')
# Fallback si aucun code reçu
if [[ -z "$code" ]]; then
echo -e "${GRAY}[NO RESPONSE]${RESET} $url" | tee -a "$log"
sleep 2
continue
fi
case "$code" in
200)
echo -e "${GREEN}[FOUND: HTTP 200]${RESET} $url" | tee -a "$log"
;;
301|302|303)
echo -e "${YELLOW}[REDIRECT: $code]${RESET} $url" | tee -a "$log"
;;
403|404)
echo -e "${RED}[NOT FOUND: $code]${RESET} $url" | tee -a "$log"
;;
*)
echo -e "${GRAY}[UNKNOWN STATUS: $code]${RESET} $url" | tee -a "$log"
;;
esac
sleep 2
done
# === Résumé final ===
echo -e "\n${GREEN}=== SUMMARY: FOUND ===${RESET}"
awk '/\[FOUND: HTTP 200\]/ {print "\033[1;32m" $0 "\033[0m"}' "$log"
# === Compteur final ===
count=$(grep -c '\[FOUND: HTTP 200\]' "$log")
echo -e "${GREEN}Total FOUND: $count${RESET}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment