chore: auto-commit 2026-04-24 19:17

This commit is contained in:
administrator 2026-04-24 19:17:01 +00:00
parent db41397368
commit 1f56d2a3c5
14 changed files with 174 additions and 739 deletions

View file

@ -1,5 +1,7 @@
# Compiled binary (generated by build)
bin/aasd
aasd
dist/
# Log files
*.log

Binary file not shown.

View file

@ -1,563 +0,0 @@
# Subdomain Finder
[![CI](https://github.com/valllabh/domain-scan/actions/workflows/ci.yml/badge.svg)](https://github.com/valllabh/domain-scan/actions/workflows/ci.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/valllabh/domain-scan)](https://goreportcard.com/report/github.com/valllabh/domain-scan)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/valllabh/domain-scan)](https://github.com/valllabh/domain-scan/releases)
A comprehensive Go-based tool for discovering and verifying active subdomains through multiple techniques including passive enumeration, TLS certificate analysis, and HTTP service verification.
## Built on Amazing Tools
This project stands on the shoulders of giants and integrates the excellent work from [ProjectDiscovery](https://projectdiscovery.io):
- **[subfinder](https://github.com/projectdiscovery/subfinder)** - Fast passive subdomain enumeration tool
- **[httpx](https://github.com/projectdiscovery/httpx)** - Fast and multi-purpose HTTP toolkit
### Why This Project Exists
While `subfinder` and `httpx` are incredibly powerful tools on their own, this project provides:
- **Unified Workflow**: Combines subdomain discovery, certificate analysis, and HTTP verification in one command
- **Keyword-Based Filtering**: Automatically extracts organization keywords from domains to filter SSL certificate SANs
- **Structured Output**: Provides consistent JSON/YAML output with detailed statistics and metadata
- **Library Integration**: Offers a Go library for programmatic use in other security tools
- **Queue-Based Processing**: Uses message queues for efficient concurrent domain processing
**TL;DR**: This is a wrapper that orchestrates `subfinder` and `httpx` with additional logic for enterprise security workflows.
## Quick Start
```bash
# Download and install
curl -sSL https://github.com/valllabh/domain-scan/releases/latest/download/domain-scan_$(uname -s)_$(uname -m).tar.gz | tar -xz
sudo mv domain-scan /usr/local/bin/
# Run a basic scan
domain-scan discover example.com
# Or with Homebrew
brew install valllabh/tap/domain-scan
domain-scan discover example.com
# For development (from source)
git clone https://github.com/valllabh/domain-scan.git
cd domain-scan
make init && make run-discover
```
## Overview
This tool integrates [ProjectDiscovery's](https://projectdiscovery.io) security tools to perform comprehensive subdomain discovery and verification:
1. **Passive Discovery**: Uses [subfinder](https://github.com/projectdiscovery/subfinder) to enumerate subdomains from passive sources
2. **TLS Certificate Analysis**: Probes domains using [httpx](https://github.com/projectdiscovery/httpx) with TLS certificate inspection
3. **HTTP Service Verification**: Scans discovered subdomains for active HTTP/HTTPS services
4. **Keyword Extraction**: Automatically extracts keywords from domain names
5. **Keyword Filtering**: Filters domains from SSL certificates based on organizational relevance
6. **Deduplication**: Outputs unique active HTTP services
## How It Works
The tool combines three powerful techniques for comprehensive subdomain discovery and verification:
### 1. Subfinder Integration
- Uses [ProjectDiscovery's subfinder](https://github.com/projectdiscovery/subfinder) to query passive DNS sources
- Discovers subdomains from certificate transparency logs, DNS records, and other sources
- Provides comprehensive initial subdomain enumeration without any active scanning
### 2. TLS Certificate Analysis
- Inspects Subject Alternative Names (SANs) in SSL/TLS certificates
- Finds additional subdomains not discovered by passive sources
- Filters domains based on organizational relevance using keywords
- Leverages certificate transparency for passive reconnaissance
#### SSL Certificate Keyword Filtering
When analyzing SSL certificates, domains often contain Subject Alternative Names (SANs) from multiple organizations due to shared hosting or third-party services. For example, if `apple.com` has a subdomain `status.apple.com` pointing to a third-party SaaS provider, that provider's certificate might also contain domains like `status.microsoft.com` or other unrelated organizations.
The keyword filtering system:
1. **Extracts keywords** from target domains (e.g., `apple.com``apple`, `iphone.com``iphone`)
2. **Filters certificate domains** to only include those matching organizational keywords
3. **Prevents noise** from unrelated domains in shared certificates
4. **Examples**:
- Target: `apple.com` → Keywords: `apple`
- Certificate contains: `status.apple.com`, `store.apple.com`, `status.microsoft.com`
- Filtered result: `status.apple.com`, `store.apple.com` (excludes `status.microsoft.com`)
### 3. HTTP Service Verification
- Scans all discovered subdomains for active HTTP/HTTPS services
- Tests multiple ports (configurable) for web services
- Verifies actual accessibility and responsiveness
- Returns only active, reachable services
### Key Features
- **Integrated Subfinder**: Built-in subfinder execution for comprehensive discovery
- **TLS Certificate Analysis**: Inspects Subject Alternative Names in SSL certificates with keyword filtering
- **HTTP Service Scanning**: Verifies active HTTP/HTTPS services on discovered subdomains
- **Configurable Port Scanning**: Customizable port list for HTTP service detection
- **Automatic Keyword Extraction**: Extracts keywords from domain names automatically
- **SSL Certificate Filtering**: Filters domains from SSL certificates based on organizational relevance
- **Concurrent Processing**: Uses httpx with configurable threads for fast scanning
- **Timeout Protection**: Configurable timeouts for reliable operation
- **Progress Indicators**: Real-time feedback on scanning progress
- **Deduplication**: Automatically removes duplicate subdomains
## Usage
```bash
domain-scan discover [domains...] [flags]
```
### Basic Commands
```bash
# Get help
domain-scan --help
domain-scan discover --help
# Configuration management
domain-scan config show
domain-scan config init
domain-scan config set discovery.timeout 15
```
### Available Options
**Target and Keywords:**
- `domains`: Target domains for subdomain discovery
- `--keywords/-k`: Additional keywords for filtering SSL certificate domains (auto-extracted from domains and combined with provided keywords)
**Discovery Settings:**
- `--timeout`: Timeout in seconds (default: from config)
- `--threads`: Number of concurrent threads (default: from config)
**Output Options:**
- `--output/-o`: Output file path (default: stdout)
- `--format/-f`: Output format (text, json)
- `--result-dir`: Directory to save results (default: ./result)
- `--quiet/-q`: Suppress progress output
**Logging:**
- `--loglevel`: Log level (trace, debug, info, warn, error, silent)
- `--debug`: Enable debug logging (deprecated, use --loglevel debug)
**Configuration:**
- `--config`: Config file (default: $HOME/.domain-scan/config.yaml)
### Examples
```bash
# Basic discovery (keywords automatically extracted from domain names)
domain-scan discover example.com
# Scan multiple domains
domain-scan discover example.com domain2.com
# Additional keywords (combined with auto-extracted ones)
domain-scan discover example.com --keywords staging,prod
# Custom discovery settings
domain-scan discover example.com --timeout 15 --threads 25
# Save results to JSON file
domain-scan discover example.com --output results.json --format json
# Custom result directory
domain-scan discover example.com --result-dir ./my-results
# Quiet mode with debug logging
domain-scan discover example.com --quiet --loglevel debug
# Multiple domains with custom settings
domain-scan discover example.com domain2.com --keywords api,admin --timeout 15
```
## Configuration Management
The tool supports configuration files for persistent settings:
```bash
# Initialize default configuration
domain-scan config init
# View current configuration
domain-scan config show
# Set configuration values
domain-scan config set discovery.timeout 15
domain-scan config set keywords [mycompany,staging]
```
**Default Ports:** 80, 443, 8080, 8443, 3000, 8000, 8888
**Configuration File:** `$HOME/.domain-scan/config.yaml`
## Integration with Main Project
This tool can be used standalone or integrated with the main reconnaissance script. The tool is self-contained and includes:
1. **Subfinder Integration**: Direct subfinder execution for comprehensive discovery
2. **Automatic Keyword Extraction**: No need for separate keyword extraction utilities
3. **TLS Certificate Analysis**: Additional discovery through certificate inspection with organizational filtering
4. **HTTP Service Verification**: Ensures only active services are reported
5. **Unified Output**: All active HTTP services in a single, deduplicated list
## Built-in Security Tools
This tool integrates the amazing security tools from [ProjectDiscovery](https://projectdiscovery.io):
- **[subfinder](https://github.com/projectdiscovery/subfinder)** - Fast passive subdomain enumeration tool
- **[httpx](https://github.com/projectdiscovery/httpx)** - Fast and multi-purpose HTTP toolkit for probing and TLS inspection
These tools are now integrated directly into domain-scan, so no separate installation is required.
## Configuration
The tool uses these default settings:
- **Timeout**: 10 seconds per domain
- **Threads**: 10 concurrent connections (TLS), 50 (HTTP scanning)
- **TLS Probe**: Enabled for certificate inspection
- **Subfinder**: Silent mode with all sources enabled
- **HTTP Scanning**: Tests both HTTP and HTTPS protocols
- **Default Ports**: 80,443,8080,8443,3000,8000,8888
## Security Considerations
This tool is designed for defensive security purposes:
- Performs passive reconnaissance and active HTTP probing
- No exploitation or intrusive testing beyond HTTP requests
- Helps organizations understand their external attack surface
- Complies with responsible disclosure practices
- Only tests for HTTP service availability
## Output Format
The tool outputs active HTTP services to stdout, one per line, making it easy to pipe to other tools or save to files. Progress information and statistics are sent to stderr.
**Example Output:**
```
https://store.example.com
http://staging.example.com:8080
https://staging.example.com:8443
```
## Progress Indicators
The tool provides real-time feedback through stderr:
- 🔍 Subdomain discovery progress
- 📋 Discovery statistics
- 🔐 TLS certificate analysis progress
- 🌐 HTTP service scanning progress
- ✅ Active service discoveries
- 📊 Final statistics
## Workflow
1. **Parse Arguments**: Extract target domains, keywords, and ports
2. **Keyword Extraction**: Auto-extract keywords from domain names and combine with any manually provided keywords
3. **Subfinder Discovery**: Run subfinder to get initial subdomain list
4. **TLS Certificate Analysis**: Probe domains for additional subdomains via certificate SANs, filtering by organizational relevance
5. **HTTP Service Scanning**: Test all discovered subdomains for active HTTP services
6. **SSL Certificate Filtering**: Filter certificate domains based on keyword relevance to target organization
7. **Deduplication**: Remove duplicate entries
8. **Output**: Print active HTTP services to stdout
## Limitations
- TLS certificate analysis limited to domains with valid SSL/TLS certificates
- SSL certificate keyword filtering may exclude domains from shared certificates that don't match organizational keywords
- HTTP scanning limited to specified ports
- Performance depends on target domain response times and network connectivity
- Large subdomain lists may take considerable time to scan
## Installation
### Binary Downloads
Download the latest release for your platform from the [releases page](https://github.com/valllabh/domain-scan/releases).
### Package Managers
#### Homebrew (macOS/Linux)
```bash
brew install valllabh/tap/domain-scan
```
#### APT (Debian/Ubuntu)
```bash
wget https://github.com/valllabh/domain-scan/releases/latest/download/domain-scan_amd64.deb
sudo dpkg -i domain-scan_amd64.deb
```
#### RPM (RHEL/CentOS/Fedora)
```bash
wget https://github.com/valllabh/domain-scan/releases/latest/download/domain-scan_amd64.rpm
sudo rpm -i domain-scan_amd64.rpm
```
#### Alpine Linux
```bash
wget https://github.com/valllabh/domain-scan/releases/latest/download/domain-scan_amd64.apk
sudo apk add --allow-untrusted domain-scan_amd64.apk
```
### From Source
```bash
go install github.com/valllabh/domain-scan@latest
```
## Testing
The tool includes comprehensive test coverage:
```bash
# Run all tests
go test -v ./...
# Run with coverage
make test-coverage
# Run specific test packages
go test -v ./pkg/utils
go test -v ./pkg/discovery
go test -v ./pkg/domainscan
```
## Development
This section covers everything needed for developing and contributing to domain-scan.
**Quick Navigation:**
- [Building](#building)
- [Running During Development](#running-during-development)
- [Code Quality](#code-quality)
- [Make Commands Reference](#make-commands-reference)
### Building
```bash
# Build for current platform
make build
# Build for all platforms
make build-all
# Development build with race detection
make dev
```
### Running During Development
```bash
# Run with custom arguments
make run ARGS="discover example.com --keywords staging,prod"
# Quick shortcuts for testing
make run-help # Show help
make run-discover # Test discovery with example.com
make run-config # Show current configuration
# Examples
make run ARGS="discover example.com --keywords staging,prod --ports 80,443"
make run ARGS="discover test.com --format json --output results.json"
```
### Code Quality
```bash
# Format code
make fmt
# Lint code
make lint
# Security scan
make security
# Vulnerability check
make vuln
```
### Make Commands Reference
The project includes a comprehensive Makefile with targets for all development tasks. Run `make help` to see all available targets.
**Quick Start**: `make init && make test && make run-discover`
#### Build Targets
```bash
make build # Build for current platform
make build-all # Build for multiple platforms (Linux, macOS)
make dev # Development build with race detection
make clean # Clean build artifacts
```
#### Development & Testing
```bash
make run ARGS="..." # Build and run with custom arguments
make run-help # Show application help
make run-discover # Quick test discovery with example.com
make run-config # Show current configuration
make test # Run all tests
make test-coverage # Run tests with HTML coverage report
make bench # Run benchmark tests
```
#### Code Quality & Security
```bash
make fmt # Format code with gofmt
make lint # Run golangci-lint (installs if needed)
make security # Run gosec security scanner
make vuln # Check for vulnerabilities with govulncheck
```
#### Dependencies & Environment
```bash
make deps # Install and verify Go dependencies
make init # Initialize development environment
make update # Update all dependencies
```
#### Release & Distribution
```bash
make release # Create release using GoReleaser
make snapshot # Create snapshot release for testing
```
#### Installation
```bash
make install # Install binary to $GOPATH/bin
make uninstall # Remove binary from $GOPATH/bin
```
#### Documentation & Help
```bash
make docs # Generate command documentation
make help # Show all available targets
```
#### Example Development Workflow
```bash
# Initialize environment
make init
# Run tests
make test
# Test the application
make run-discover
# Test with custom arguments
make run ARGS="discover example.com --keywords api,admin --ports 80,443,8080"
# Format and lint code
make fmt lint
# Create a snapshot build
make snapshot
```
## Release Process
This project uses automated releases via GitHub Actions and [GoReleaser](https://goreleaser.com/).
### Creating a Release
1. **Ensure all changes are on the main branch**
2. **Create and push a new tag**:
```bash
git tag v1.0.0
git push origin v1.0.0
```
3. **GitHub Actions will automatically**:
- Run all tests and quality checks
- Build binaries for multiple platforms (Linux, macOS)
- Create packages (DEB, RPM, APK)
- Generate release notes and publish to GitHub
- Update Homebrew formula
### Release Artifacts
Each release automatically produces:
- **Cross-platform binaries** for Linux and macOS (Intel/ARM)
- **Linux packages** (DEB, RPM, APK) for easy installation
- **Homebrew formula** for macOS and Linux users
- **Checksums** for artifact verification
### Versioning
The project follows [Semantic Versioning](https://semver.org/):
- `v1.0.0` - Major release with breaking changes
- `v1.1.0` - Minor release with new features
- `v1.1.1` - Patch release with bug fixes
### Development Releases
For testing unreleased changes:
```bash
# Create a snapshot build locally
make snapshot
# Or use the manual test workflow in GitHub Actions
```
## Troubleshooting
**Common Issues:**
- Check network connectivity for target domains
- Verify domain names are correct and accessible
- For large subdomain lists, consider using smaller port ranges
- Monitor system resources during intensive scans
**Installation Issues:**
- For package installations, ensure you have appropriate permissions
- For Homebrew, run `brew update` if the formula isn't found
## Security
This tool is designed for defensive security and authorized reconnaissance only. Please review our [Security Policy](SECURITY.md) for:
- **Responsible usage guidelines**
- **Vulnerability reporting process**
- **Security best practices**
- **Dependency security information**
⚠️ **Important**: Only use this tool on systems you own or have explicit permission to test.
## Contributing
Contributions are welcome! Please:
1. Read our [Security Policy](SECURITY.md) first
2. Fork the repository
3. Create a feature branch
4. Make your changes with tests
5. Run `make test` and `make lint`
6. Submit a pull request
## Acknowledgments
This project is built on the excellent work from the security community:
### Core Dependencies
- **[ProjectDiscovery](https://projectdiscovery.io)** - For creating amazing open source security tools
- **[subfinder](https://github.com/projectdiscovery/subfinder)** - Fast passive subdomain enumeration tool
- **[httpx](https://github.com/projectdiscovery/httpx)** - Fast and multi-purpose HTTP toolkit
- **[Cobra](https://github.com/spf13/cobra)** - CLI framework for Go
- **[Viper](https://github.com/spf13/viper)** - Configuration management for Go
### Special Thanks
- The [ProjectDiscovery](https://github.com/projectdiscovery) team for building the security tools that power this project
- The Go security community for creating robust security tooling
- All contributors who help improve this tool
💖 **If you find this tool useful, please star the repositories of the amazing tools it depends on!**
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

View file

@ -1,13 +0,0 @@
# Domain-scan default configuration
discovery:
timeout: 10
threads: 50
ports:
default: [80, 443, 8080, 8443, 3000, 8000, 8888]
web: [80, 443, 8080, 8443]
dev: [3000, 8000, 8888, 9000]
enterprise: [80, 443, 8080, 8443, 8000, 9000, 8443]
keywords: []

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -46,8 +46,12 @@ func main() {
// e.g. AASD_BASE_URL=https://coding.sechpoint.app
baseURL := os.Getenv("AASD_BASE_URL")
// Initialize services
deepSeekClient := ai.NewClient("sk-2b898e303be94266a060c8f3a0ca205c")
// Initialize AI client (reads api_key from config.yaml in working directory)
deepSeekClient, err := ai.NewClient()
if err != nil {
fmt.Printf("Warning: AI client init failed: %v (reports will use fallback)\n", err)
deepSeekClient = nil
}
mailerService := mailer.New(mailer.ConfigFromEnv())
orch := scanner.NewOrchestrator(projectDir, baseURL, deepSeekClient, mailerService)
@ -56,11 +60,11 @@ func main() {
defer cancel()
router := gin.Default()
router.LoadHTMLGlob("src/templates/*")
router.LoadHTMLGlob("templates/*")
// Serve static files
router.Static("/static", "./src/static")
router.StaticFile("/", "./src/static/index.html")
router.Static("/static", "./static")
router.StaticFile("/", "./static/index.html")
router.Static("/reports", "./reports")
// QR code generator endpoint
@ -216,7 +220,7 @@ func main() {
})
// ----- SIMULATION: Serve new simulation page with token support -----
router.StaticFile("/simulation", "./src/static/simulation.html")
router.StaticFile("/simulation", "./static/simulation.html")
// ----- DOWNLOAD: Serve the raw scan results for debugging -----
router.GET("/report-data/:token", func(c *gin.Context) {

View file

@ -8,34 +8,79 @@ import (
"fmt"
"io"
"net/http"
"os"
"regexp"
"strings"
"time"
"github.com/goccy/go-yaml"
)
const (
defaultBaseURL = "https://api.deepseek.com"
defaultModel = "deepseek-chat"
requestTimeout = 60 * time.Second
)
const requestTimeout = 60 * time.Second
// Config holds application configuration loaded from config.yaml.
type Config struct {
AI AIConfig `yaml:"ai"`
}
// AIConfig holds AI provider settings.
type AIConfig struct {
ProviderURL string `yaml:"provider_url"`
APIKey string `yaml:"api_key"`
Model string `yaml:"model"`
}
// Client communicates with the DeepSeek API.
type Client struct {
apiKey string
baseURL string
model string
http *http.Client
config AIConfig
systemPrompt string
http *http.Client
}
// NewClient creates a new DeepSeek API client.
func NewClient(apiKey string) *Client {
// NewClient reads config from config.yaml and prompt from prompt.txt,
// returning a configured DeepSeek API client.
func NewClient() (*Client, error) {
cfg, err := loadConfig("config.yaml")
if err != nil {
return nil, fmt.Errorf("ai: failed to load config: %w", err)
}
prompt, err := loadPrompt("prompt.txt")
if err != nil {
return nil, fmt.Errorf("ai: failed to load prompt: %w", err)
}
return &Client{
apiKey: apiKey,
baseURL: defaultBaseURL,
model: defaultModel,
config: cfg.AI,
systemPrompt: prompt,
http: &http.Client{
Timeout: requestTimeout,
},
}, nil
}
// loadConfig reads and parses config.yaml.
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading config file %s: %w", path, err)
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing config file %s: %w", path, err)
}
return &cfg, nil
}
// loadPrompt reads the system prompt from a text file.
func loadPrompt(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("reading prompt file %s: %w", path, err)
}
return string(data), nil
}
// chatMessage represents a message in the chat completion request.
@ -63,59 +108,44 @@ type chatResponse struct {
Choices []chatChoice `json:"choices"`
}
// GenerateResilienceReport sends scan results to DeepSeek and returns
// a clean HTML snippet with the resilience narrative.
//
// The prompt instructs DeepSeek to return well-formed HTML that can be
// embedded directly into the report template, focusing on Wallarm WAF
// protection metrics and JetPatch remediation recommendations.
func (c *Client) GenerateResilienceReport(subdomains []string, criticalDomain string, scanOutput string) (string, error) {
systemPrompt := `You are a senior cybersecurity analyst specializing in API security assessment.
Your role is to produce a "Resilience Narrative" a concise HTML report that:
1. Summarizes the attack surface discovered (subdomains)
2. Highlights the most critical domain found
3. Evaluates Wallarm WAF protection effectiveness based on GoTestWAF scan data
4. Provides JetPatch remediation recommendations
// GenerateResilienceReport sends the GoTestWAF consultant report HTML
// to DeepSeek and returns a user-facing HTML summary for booth visitors.
func (c *Client) GenerateResilienceReport(consultantReportHTML string) (string, error) {
html, err := c.sendChatRequest(consultantReportHTML)
if err != nil {
return "", err
}
IMPORTANT RULES:
- Return ONLY a complete, well-formed HTML snippet (no markdown, no code fences).
- Use <div class="resilience-report"> as the root element.
- Use inline styles or Tailwind CSS classes (CDN is loaded on the page).
- Structure: Summary Attack Surface WAF Analysis Remediation Resilience Score.
- Keep it professional, scannable, and demo-ready.
- Use high contrast colors (#0f172a backgrounds, #f1f5f9 text, #3b82f6 blue accents).`
if html == "" {
domain := extractDomain(consultantReportHTML)
html = generateFallbackReport(domain)
}
userContent := fmt.Sprintf(`Analyze the following security scan results and generate a Resilience Narrative.
Target Domain (Email-derived): %s
Critical Subdomain: %s
All Discovered Subdomains: %s
GoTestWAF Scan Output:
%s
Generate a complete Resilience Narrative HTML snippet.`, subdomains[0], criticalDomain, strings.Join(subdomains, ", "), scanOutput)
return html, nil
}
// sendChatRequest sends a chat completion request and returns the response content.
func (c *Client) sendChatRequest(userContent string) (string, error) {
req := chatRequest{
Model: c.model,
Model: c.config.Model,
Messages: []chatMessage{
{Role: "system", Content: systemPrompt},
{Role: "system", Content: c.systemPrompt},
{Role: "user", Content: userContent},
},
Stream: false,
}
body, err := json.Marshal(req)
if err != nil {
return "", fmt.Errorf("deepseek: failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", c.baseURL+"/chat/completions", bytes.NewReader(body))
httpReq, err := http.NewRequest("POST",
c.config.ProviderURL+"/chat/completions",
bytes.NewReader(body))
if err != nil {
return "", fmt.Errorf("deepseek: failed to create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+c.apiKey)
httpReq.Header.Set("Authorization", "Bearer "+c.config.APIKey)
resp, err := c.http.Do(httpReq)
if err != nil {
@ -127,56 +157,61 @@ Generate a complete Resilience Narrative HTML snippet.`, subdomains[0], critical
if err != nil {
return "", fmt.Errorf("deepseek: failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("deepseek: API error (HTTP %d): %s", resp.StatusCode, string(respBody))
return "", fmt.Errorf("deepseek: API error (HTTP %d): %s",
resp.StatusCode, string(respBody))
}
var chatResp chatResponse
if err := json.Unmarshal(respBody, &chatResp); err != nil {
return "", fmt.Errorf("deepseek: failed to decode response: %w", err)
}
if len(chatResp.Choices) == 0 {
return "", fmt.Errorf("deepseek: no choices in response")
}
html := strings.TrimSpace(chatResp.Choices[0].Message.Content)
if html == "" {
// Fallback report if AI returns empty
html = generateFallbackReport(subdomains, criticalDomain)
}
return html, nil
return strings.TrimSpace(chatResp.Choices[0].Message.Content), nil
}
// generateFallbackReport creates a basic resilience report when the AI call fails
// or returns empty content, ensuring the booth demo always works.
func generateFallbackReport(subdomains []string, criticalDomain string) string {
domain := subdomains[0]
list := ""
for _, s := range subdomains {
list += fmt.Sprintf("<li class=\"text-gray-300\">%s</li>", s)
// domainPattern matches a hostname from an HTML href or text context.
var domainPattern = regexp.MustCompile(`https?://([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}`)
// extractDomain attempts to extract a domain name from the consultant report HTML.
// Used to provide context for the fallback report when AI returns empty content.
func extractDomain(html string) string {
match := domainPattern.FindString(html)
if match == "" {
return ""
}
// Strip the protocol prefix
match = strings.TrimPrefix(match, "https://")
match = strings.TrimPrefix(match, "http://")
return match
}
// generateFallbackReport creates a basic resilience report when the AI call
// succeeds but returns empty content, ensuring the booth demo always works.
func generateFallbackReport(domain string) string {
if domain == "" {
domain = "the scanned endpoint"
}
return fmt.Sprintf(`<div class="resilience-report bg-gray-900 text-gray-100 p-6 rounded-xl">
<h2 class="text-2xl font-bold text-blue-400 mb-4">Resilience Narrative</h2>
<div class="mb-6">
<h3 class="text-lg font-semibold text-gray-200 mb-2">Summary</h3>
<h3 class="text-lg font-semibold text-gray-200 mb-2">Scan Overview</h3>
<p class="text-gray-300">Security assessment completed for <strong class="text-white">%s</strong>.
Attack surface analysis identified %d subdomains with <strong class="text-yellow-400">%s</strong> as the most critical endpoint.</p>
The GoTestWAF analysis evaluated attack vectors across OWASP categories against the Wallarm-protected endpoint.</p>
</div>
<div class="mb-6">
<h3 class="text-lg font-semibold text-gray-200 mb-2">Attack Surface</h3>
<ul class="space-y-1">%s</ul>
<h3 class="text-lg font-semibold text-gray-200 mb-2">Category Breakdown</h3>
<p class="text-gray-300">Multiple attack categories were tested including OWASP API, OWASP Core, and Community payloads.
Wallarm WAF filtering node evaluated all vectors in monitoring mode.</p>
</div>
<div class="mb-6">
<h3 class="text-lg font-semibold text-gray-200 mb-2">WAF Analysis</h3>
<p class="text-gray-300">GoTestWAF scan executed against Wallarm-protected endpoint.
WAF filtering node operating in monitoring mode all attack vectors were evaluated without blocking.</p>
<h3 class="text-lg font-semibold text-gray-200 mb-2">Critical Findings</h3>
<p class="text-gray-300">Review the full consultant report for detailed per-vector results and bypass analysis.</p>
<div class="mt-3 grid grid-cols-2 gap-3">
<div class="bg-gray-800 p-3 rounded-lg">
<div class="text-2xl font-bold text-green-400">Scanned</div>
@ -188,16 +223,16 @@ func generateFallbackReport(subdomains []string, criticalDomain string) string {
</div>
</div>
</div>
<div class="mb-6">
<h3 class="text-lg font-semibold text-gray-200 mb-2">Remediation</h3>
<p class="text-gray-300">JetPatch remediation advisory: Review WAF monitoring logs and tune blocking rules for critical endpoints.
Recommended actions: enable blocking mode for OWASP Top 10 vectors, configure rate limiting, and set up real-time alerts.</p>
<h3 class="text-lg font-semibold text-gray-200 mb-2">Recommendations</h3>
<p class="text-gray-300">Enable blocking mode for OWASP Top 10 vectors, configure rate limiting on API endpoints,
set up real-time WAF alerts, and schedule weekly attack surface reviews via JetPatch remediation platform.</p>
</div>
<div class="text-center mt-8">
<div class="text-4xl font-bold text-green-400">B+</div>
<p class="text-sm text-gray-400 mt-1">Resilience Score</p>
</div>
</div>`, domain, len(subdomains), criticalDomain, list)
</div>`, domain)
}

View file

@ -24,11 +24,11 @@ type domainScanResult struct {
// DiscoverSubdomains runs the domain-scan tool against the given domain
// and returns a list of discovered active subdomains.
//
// domain-scan binary must be at projectRoot/bin/tools/domain-scan.
// domain-scan binary must be at projectRoot/domain-scan.
// Uses passive enumeration + TLS certificate analysis + HTTP verification.
// Falls back to the original domain if the scan takes too long or fails.
func DiscoverSubdomains(ctx context.Context, projectRoot, domain string) ([]string, error) {
binaryPath := filepath.Join(projectRoot, "bin", "tools", "domain-scan")
binaryPath := filepath.Join(projectRoot, "domain-scan")
outputFile := filepath.Join(projectRoot, "reports", fmt.Sprintf("discovery_%s.json", strings.ReplaceAll(domain, ".", "_")))
// Create a context with timeout so discovery doesn't block the pipeline

View file

@ -19,7 +19,7 @@ const (
// The report is saved to reports/ directory with the given reportName.
// Returns the raw output for AI analysis.
func RunGoTestWAF(ctx context.Context, projectRoot string, reportName string) (string, error) {
binaryPath := filepath.Join(projectRoot, "bin", "gotestwaf")
binaryPath := filepath.Join(projectRoot, "gotestwaf")
// Verify binary exists
if _, err := os.Stat(binaryPath); os.IsNotExist(err) {
@ -37,8 +37,8 @@ func RunGoTestWAF(ctx context.Context, projectRoot string, reportName string) (s
cmd := exec.CommandContext(scanCtx, binaryPath,
"--url", targetURL,
"--configPath", "src/gotestwaf/config.yaml",
"--testCasesPath", "src/gotestwaf/testcases",
"--configPath", "gotestwaf-config.yaml",
"--testCasesPath", "testcases",
"--maxIdleConns", "2",
"--maxRedirects", "10",
"--reportPath", reportsDir,

View file

@ -114,11 +114,22 @@ func (o *Orchestrator) executePipeline(ctx context.Context, result *ScanResult)
result.Error = fmt.Sprintf("scan error: %v", err)
scanOutput = fmt.Sprintf("Scan encountered an error: %v\nProceeding with partial results.", err)
}
_ = scanOutput // captured for error context; new AI signature accepts consultant report HTML
// Read GoTestWAF consultant report HTML for AI analysis
gtwReportPath := filepath.Join(o.projectRoot, "reports", fmt.Sprintf("report_%s.html", result.ReportToken))
consultantHTML, readErr := os.ReadFile(gtwReportPath)
if readErr != nil {
fmt.Printf("scanner: failed to read consultant report %s: %v\n", gtwReportPath, readErr)
}
// Phase 4: AI Narrative Generation
o.updateStatus(result.ReportToken, StatusGenerating)
aiHTML, err := o.aiClient.GenerateResilienceReport(subdomains, criticalDomain, scanOutput)
if err != nil {
var aiHTML string
if o.aiClient != nil && readErr == nil {
aiHTML, err = o.aiClient.GenerateResilienceReport(string(consultantHTML))
}
if o.aiClient == nil || readErr != nil || err != nil {
aiHTML = report.GenerateFallbackHTML(subdomains, criticalDomain)
}
@ -135,7 +146,7 @@ func (o *Orchestrator) executePipeline(ctx context.Context, result *ScanResult)
result.ReportFile = "/reports/" + result.ReportToken + ".html"
// Inject QR code into GoTestWAF native report (for consultants)
gtwReportPath := filepath.Join(o.projectRoot, "reports", fmt.Sprintf("report_%s.html", result.ReportToken))
// gtwReportPath already defined above; reuse it
if data, err := os.ReadFile(gtwReportPath); err == nil {
qrURL := fmt.Sprintf("%s/reports/report_%s.html", o.baseURL, result.ReportToken)
qrBlock := fmt.Sprintf(`

View file

@ -1,29 +0,0 @@
#!/bin/bash
# Start the AASD (API Attack Surface Discovery) server
# Version: 2026-04.1
set -e
cd "$(dirname "$0")"
echo "================================================"
echo " AASD — API Attack Surface Discovery"
echo " Version: 2026-04.1"
echo " GITEX 2026 — sechpoint.app"
echo "================================================"
echo ""
# Ensure required directories exist
mkdir -p reports
mkdir -p logs
mkdir -p bin/tools
# Verify domain-scan tool exists
if [ ! -f "bin/tools/domain-scan" ]; then
echo "[!] domain-scan not found in bin/tools/"
echo " Run: curl -sL https://github.com/valllabh/domain-scan/releases/download/v2.1.0/domain-scan_Linux_x86_64.tar.gz | tar -xz -C bin/tools/"
echo " Or download manually from: https://github.com/valllabh/domain-scan"
fi
# Run the server
./bin/aasd 2>&1 | tee logs/server-$(date +%Y%m%d-%H%M%S).log

View file

@ -7,18 +7,28 @@ An interactive booth experience that captures corporate emails, runs background
```
gitex2026/
├── AttackSurface/ # Main application folder
│ ├── bin/ # Executables (GoTestWAF binary, compiled app)
│ ├── dist/ # Deployment directory (self-contained)
│ │ ├── aasd # Compiled application binary
│ │ ├── static/ # HTML/JS/CSS frontend files
│ │ ├── templates/ # Go HTML templates
│ │ ├── gotestwaf # GoTestWAF binary
│ │ ├── domain-scan # Domain discovery tool
│ │ ├── testcases/ # GoTestWAF test cases
│ │ ├── config.yaml # AI provider configuration
│ │ ├── prompt.txt # AI system prompt
│ │ ├── reports/ # Generated scan reports
│ │ ├── logs/ # Server logs
│ │ └── start.sh # Startup script
│ ├── src/ # Source code (Go server, frontend)
│ │ ├── cmd/ # Go command entry points
│ │ ├── static/ # HTML/JS/CSS frontend files
│ │ ├── templates/ # Go HTML templates
│ │ ├── gotestwaf/ # GoTestWAF configuration
│ │ ├── gotestwaf/ # Vendored GoTestWAF source
│ │ ├── internal/ # Internal Go packages
│ │ └── pkg/ # Public Go packages
│ ├── reports/ # GoTestWAF output reports (generated)
│ ├── logs/ # Server logs
│ ├── docs/ # Documentation (CHANGELOG.md, DEVELOPMENT_STATUS.md)
│ └── start.sh # Server startup script
│ ├── VERSION # Current version
│ └── .gitignore
└── README.md # This file
```
@ -43,54 +53,32 @@ gitex2026/
## Quick Start
```bash
# Option 1: Use startup script (recommended)
cd gitex2026/AttackSurface
# Option 1: Run from dist/ (recommended - no build needed)
cd AttackSurface/dist
./start.sh
# Option 2: Manual build and run
# Option 2: Build and run from source
cd AttackSurface/src
go build -o ../bin/resilience-challenge ./cmd/resilience-challenge
cd ..
./bin/resilience-challenge
go build -o ../dist/aasd ./cmd/aasd/
cd ../dist
./start.sh
# Access the application
# Frontend: http://localhost:8080 (or booth Wi-Fi IP)
# Admin dashboard: http://localhost:8080/admin-dashboard
# Reports: http://localhost:8080/reports/report_*.html
```
> **Note**: Before running, set your DeepSeek API key in `dist/config.yaml` if AI-generated reports are desired. Without it, the app uses built-in fallback reports.
## Development
### Current Status
**Version 0.3.0** - Production ready for Phase 5 testing. All critical bugs fixed.
**Version 2026-04.1**
### Documentation
- [CHANGELOG.md](AttackSurface/docs/CHANGELOG.md) - Version history and detailed changes
- [DEVELOPMENT_STATUS.md](AttackSurface/docs/DEVELOPMENT_STATUS.md) - Current status and testing results
### Key Improvements in 0.3.0
- Fixed GoTestWAF integration bugs causing scan failures
- Enhanced security with comprehensive input validation
- Added graceful shutdown with OS signal handling
- Improved code quality and concurrency safety
## Testing
### Target Server
The application is configured to test `https://git.sechpoint.app` (your Wallarm-protected server in monitoring mode).
### Test Flow
1. User submits email at booth → Domain extracted → GoTestWAF scan initiated
2. Real-time status updates via frontend polling (`/scan-status/:domain`)
3. HTML report generated upon completion (120-second timeout)
4. Consultant monitors all scans via admin dashboard
### Verification
- Server binds to `0.0.0.0:8080` for booth Wi-Fi accessibility
- All endpoints respond correctly (frontend, API, reports)
- Graceful shutdown handles SIGINT/SIGTERM signals
- GoTestWAF integration uses valid flags for current version
## License
Proprietary - For internal event use only.