wappalyzergo Documentation

repository·main·Indexed 22 days ago

https://github.com/projectdiscovery/wappalyzergo

A high-performance Go implementation of the Wappalyzer technology detection library. It identifies web technologies used by websites through HTML and HTTP header analysis using normalized regexes. The library includes a client for fingerprinting, support for loading custom fingerprint JSON files, and an `update-fingerprints` CLI tool to synchronize fingerprint data from the official Wappalyzer and webappanalyzer repositories.

Tokens
4.4K
Snippets
16
Records
20
Agent score
77%

What's inside wappalyzergo

  1. Overview of Wappalyzergo

    main
    Wappalyzergo is a high-performance Go port of the Wappalyzer Technology Detection Library. It is optimized for speed by manually parsing HTML and uses normalized regexes. It leverages fingerprint data from webappanalyzer and the official wappalyzer repository.
  2. Install the fingerprint update tool

    main

    To ensure you have the latest Wappalyzer fingerprints, use the update-fingerprints command via go install. This tool manages the auto-updating database of fingerprints used by the library.

    go install -v github.com/projectdiscovery/wappalyzergo/cmd/update-fingerprints@latest
  3. Understand the Fingerprint data structures

    main

    The library uses two primary structures to represent technology detection rules:

    1. Fingerprints: A raw representation of technology fingerprints, typically used for unmarshaling JSON data. It contains maps for Cookies, Dom, JS, Headers, HTML, Script, ScriptSrc, and Meta tags.
    2. CompiledFingerprints: An optimized, internal representation where raw patterns are compiled into ParsedPattern objects for efficient matching. This is what the engine uses during runtime to perform detection.

    When a match is found, the engine also considers implies (technologies that are implicitly present if the primary technology is detected) and returns a matchPartResult containing the application name, version, and confidence level.

  4. Initialize a Wappalyze client

    main

    You can initialize a new Wappalyze client using New() to use the embedded fingerprints, or NewFromFile() to load fingerprints from a specific JSON file. Using NewFromFile allows you to use updated fingerprint definitions without recompiling your application.

    When using NewFromFile, you can control how embedded fingerprints interact with the file-based ones using the loadEmbedded and supersede parameters:

    • loadEmbedded: If true, the client first loads the built-in fingerprints.
    • supersede: If true (and loadEmbedded is also true), fingerprints in the provided file will overwrite embedded fingerprints if they share the same application name.
    // Using embedded fingerprints
    client, err := wappalyzer.New()
    
    // Using fingerprints from a specific file
    // loadEmbedded: true, supersede: true
    client, err := wappalyzer.NewFromFile("path/to/fingerprints.json", true, true)
  5. Use Wappalyzergo to detect technologies

    main

    To use the library, initialize a new client using wappalyzer.New() and then call the Fingerprint method. The Fingerprint method requires the HTTP response headers and the response body (as a byte slice) to identify technologies via normalized regexes.

    package main
    
    import (
    	"fmt"
    	"io"
    	"log"
    	"net/http"
    
    	wappalyzer "github.com/projectdiscovery/wappalyzergo"
    )
    
    func main() {
    	resp, err := http.DefaultClient.Get("https://www.hackerone.com")
    	if err != nil {
    		log.Fatal(err)
    	}
    	data, _ := io.ReadAll(resp.Body) // Ignoring error for example
    
    	wappalyzerClient, err := wappalyzer.New()
    	fingerprints := wappalyzerClient.Fingerprint(resp.Header, data)
    	fmt.Printf("%v\n", fingerprints)
    
    	// Output: map[Acquia Cloud Platform:{} Amazon EC2:{} Apache:{} Cloudflare:{} Drupal:{} PHP:{} Percona:{} React:{} Varnish:{}]
    }
  6. Retrieve raw fingerprint data with GetRawFingerprints

    main

    Use GetRawFingerprints() to access the raw JSON string containing all technology fingerprints embedded within the package. This is useful if you need to perform custom parsing or inspect the underlying fingerprint definitions directly.

    package main
    
    import (
    	"fmt"
    	"github.com/projectdiscovery/wappalyzergo"
    )
    
    func main() {
    	rawFingerprints := wappalyzer.GetRawFingerprints()
    	fmt.Println(rawFingerprints)
    }
  7. Access compiled JS and DOM rules

    main

    If you are working with a CompiledFingerprint object, you can access the compiled rules for JavaScript and DOM detection using the following methods:

    • GetJSRules(): Returns a map[string]*ParsedPattern containing the compiled JS rules.
    • GetDOMRules(): Returns a map[string]map[string]*ParsedPattern containing the compiled DOM rules.
    jsRules := compiledFingerprint.GetJSRules()
    domRules := compiledFingerprint.GetDOMRules()
  8. Format application and version strings

    main

    Use FormatAppVersion to create a standardized string representation of a detected technology. If a version is provided, it returns app:version; otherwise, it returns just the app name.

    // Returns "nginx:1.18.0"
    str := wappalyzer.FormatAppVersion("nginx", "1.18.0")
    
    // Returns "nginx"
    str := wappalyzer.FormatAppVersion("nginx", "")
  9. Parse a technology detection pattern with ParsePattern

    main

    Use ParsePattern to convert a raw pattern string into a ParsedPattern object. The function supports complex patterns that include a regular expression followed by metadata separated by \;.

    Supported metadata keys:

    • confidence:<int>: Sets the detection confidence level (defaults to 100).
    • version:<string>: Defines how the version should be extracted or formatted. The version string can use placeholders like \1, \2, etc., to refer to regex capture groups, or ternary expressions (e.g., \1?exists:not_exists) to handle conditional versioning.

    If the pattern starts with an empty string before the first \;, SkipRegex is set to true, meaning the pattern is treated as a simple existence check without regex evaluation.

    pattern := "some-regex-pattern\;confidence:80\;version=\\1"
    parsed, err := wappalyzer.ParsePattern(pattern)
    if err != nil {
        // handle error
    }
  10. Retrieve category mappings with GetCategoriesMapping

    main

    Use GetCategoriesMapping() to get a map of technology categories. The map keys are integers (parsed from the original JSON category IDs) and the values are categoryItem structs containing the category's Name and Priority.

    package main
    
    import (
    	"fmt"
    	"github.com/projectdiscovery/wappalyzergo"
    )
    
    func main() {
    	mapping := wappalyzer.GetCategoriesMapping()
    	for id, item := range mapping {
    		fmt.Printf("ID: %d, Name: %s, Priority: %d\n", id, item.Name, item.Priority)
    	}
    }
  11. Access raw fingerprint data from Wappalyze

    main

    The Wappalyze client allows you to inspect the underlying fingerprint data used for detection via two methods:

    • GetFingerprints(): Returns the original *Fingerprints structure (the raw data).
    • GetCompiledFingerprints(): Returns the *CompiledFingerprints structure (the optimized version used for matching).
  12. Perform technology fingerprinting with Wappalyze

    main

    The Wappalyze client provides several methods to identify technologies based on HTTP response headers and the response body.

    Important: Do not mutate the body byte slice while calling these functions, as it may lead to unexpected behavior.

    Basic Fingerprinting

    Use Fingerprint(headers, body) to get a map of detected technologies. The keys in the returned map are formatted as application:version (if a version was detected).

    Fingerprinting with Metadata

    If you need more than just the names, use these specialized methods:

    • FingerprintWithTitle(headers, body): Returns the detected technologies and the HTML <title> of the page.
    • FingerprintWithInfo(headers, body): Returns a map of AppInfo containing descriptions, website URLs, icons, CPEs, and categories.
    • FingerprintWithCats(headers, body): Returns a map of CatsInfo containing the raw category identifiers for the detected technologies.
    // Basic fingerprinting
    results, err := wappalyzer.New()
    techs := results.Fingerprint(headers, body)
    
    // Fingerprinting with page title
    techs, title := results.FingerprintWithTitle(headers, body)
    
    // Fingerprinting with detailed AppInfo
    infoMap := results.FingerprintWithInfo(headers, body)
    // infoMap[techName] returns AppInfo { Description, Website, Icon, CPE, Categories }