Hetty HTTP Toolkit

repository·main·Indexed 11 days ago

https://github.com/dstotijn/hetty

An open-source HTTP toolkit for security research featuring a MITM proxy, HTTP client, request interception, and a web-based admin interface. It provides tools for managing certificates, modifying live HTTP traffic, and organizing security projects via a GraphQL API.

Tokens
6.4K
Snippets
29
Records
32
Agent score
94%

What's inside Hetty

  1. Run Hetty

    main

    Once installed, you can start the Hetty HTTP server (which includes the MITM proxy, GraphQL service, and web-based admin interface) by running the hetty command.

    To see all available configuration options and subcommands, run hetty --help.

    hetty
  2. Install Hetty

    main

    Hetty can be installed via several package managers depending on your operating system, or via Docker.

    macOS

    Use Homebrew:

    brew install hettysoft/tap/hetty

    Linux

    Use Snap:

    sudo snap install hetty

    Windows

    Use Scoop:

    scoop bucket add hettysoft https://github.com/hettysoft/scoop-bucket.git
    scoop install hettysoft/hetty

    Docker

    To run Hetty with a volume for database and certificate storage, and port 8080 forwarded, use the following command:

    docker run -v $HOME/.hetty:/root/.hetty -p 8080:8080 \
      ghcr.io/dstotijn/hetty:latest

    Manual Installation

    Download the latest release for your OS and architecture from GitHub Releases and move the binary to a directory in your $PATH.

    brew install hettysoft/tap/hetty
  3. Run the Hetty CLI

    main
    The hetty command runs an HTTP server that acts as a (MITM) proxy, provides a GraphQL service, and hosts a web-based admin interface. By default, it listens on :8080 and manages its own CA certificates and database files in the ~/.hetty/ directory.
    hetty
  4. Configure Hetty CLI options

    main

    When running the hetty command, you can use the following flags to configure the server behavior:

    FlagDescription
    --certPath to root CA certificate. Creates file if it doesn't exist. (Default: ~/.hetty/hetty_cert.pem)
    --keyPath to root CA private key. Creates file if it doesn't exist. (Default: ~/.hetty/hetty_key.pem)
    --dbDatabase file path. Creates file if it doesn't exist. (Default: ~/.hetty/hetty.db)
    --addrTCP address for HTTP server to listen on, in the form "host:port". (Default: :8080)
    --chromeLaunch Chrome with proxy settings applied and certificate errors ignored. (Default: false)
    --verboseEnable verbose logging.
    --jsonEncode logs as JSON, instead of pretty/human readable output.
    --version, -vOutput version.
    --help, -hOutput this usage text.
    $ hetty --help
    
    Usage:
        hetty [flags] [subcommand] [flags]
    
    Runs an HTTP server with (MITM) proxy, GraphQL service, and a web based admin interface.
    
    Options:
        --cert         Path to root CA certificate. Creates file if it doesn't exist. (Default: "~/.hetty/hetty_cert.pem")
        --key          Path to root CA private key. Creates file if it doesn't exist. (Default: "~/.hetty/hetty_key.pem")
        --db           Database file path. Creates file if it doesn't exist. (Default: "~/.hetty/hetty.db")
        --addr         TCP address for HTTP server to listen on, in the form "host:port". (Default: ":8080")
        --chrome       Launch Chrome with proxy settings applied and certificate errors ignored. (Default: false)
        --verbose      Enable verbose logging.
        --json         Encode logs as JSON, instead of pretty/human readable output.
        --version, -v  Output version.
        --help, -h     Output this usage text.
  5. Use the KeyValuePairTable component

    main

    The KeyValuePairTable component is a UI utility for displaying and managing a list of key-value pairs in a table format. It supports two modes of operation:

    1. Read-only/Display mode: If onChange is not provided, the table displays static text. Clicking on a cell (key or value) automatically copies the content to the clipboard and shows a
  6. Launch Chrome with Hetty Proxy settings

    main

    You can use the --chrome flag to automatically launch a Chrome instance configured to use the Hetty proxy. This setup also instructs Chrome to ignore certificate errors, which is necessary for the MITM proxy to function without manual certificate installation in the browser.

    hetty --chrome
  7. Manage Scope Settings

    main

    Control the scope of intercepted requests using these hooks:

    • useScopeQuery: Fetches the current scope (URLs included in the scope).
    • useSetScopeMutation: Updates the scope with a list of ScopeRuleInput objects.
    • useScopeLazyQuery: Lazy version of the scope query.
    // Query current scope
    const { data, loading, error } = useScopeQuery();
    
    // Set new scope
    const [setScopeMutation] = useSetScopeMutation({
      variables: {
        scope: // Array of ScopeRuleInput
      }
    });
  8. Query HTTP logs and intercepted requests

    main

    Retrieve data about network activity:

    • projects: Returns a list of all available Project objects.
    • httpRequestLogs: Returns a list of HttpRequestLog entries.
    • interceptedRequests: Returns a list of currently intercepted HttpRequest objects.
    • getInterceptedRequest(id: ID!): Retrieves full details (headers, body, response) for a specific intercepted request.
    • senderRequests: Returns a list of saved SenderRequest objects.
    // Get all projects
    const { data } = useProjectsQuery();
    
    // Get details of a specific intercepted request
    const { data } = useGetInterceptedRequestQuery({ 
      variables: { id: 'req-id' } 
    });
  9. Manage HTTP Request Log Filters

    main

    Manage how request logs are filtered using the following hooks:

    • useHttpRequestLogFilterQuery: Fetches the current filter settings (onlyInScope, searchExpression).
    • useSetHttpRequestLogFilterMutation: Updates the current filter settings.
    • useHttpRequestLogFilterLazyQuery: Lazy version of the filter query.
    • useHttpRequestLogLazyQuery: Lazy version of the filter query.
    // Query current filter
    const { data, loading, error } = useHttpRequestLogFilterQuery();
    
    // Set a new filter
    const [setFilterMutation] = useSetHttpRequestLogFilterMutation({
      variables: {
        filter: { /* HttpRequestLogFilterInput */ }
      }
    });
  10. Configure intercept settings and scope

    main

    Control which requests are intercepted and how they are filtered:

    • updateInterceptSettings(input: UpdateInterceptSettingsInput!): Enables or disables request/response interception and sets regex filters for requestFilter and responseFilter.
    • setScope(scope: [ScopeRuleInput!]!): Defines the scope of interception using ScopeRule objects (matching via url, header, or body regex).
    • setHttpRequestLogFilter(filter: HttpRequestLogFilterInput): Filters the visible HTTP request logs.
    • setSenderRequestFilter(filter: SenderRequestFilterInput): Filters the sender requests list.
    // Enable interception with a URL filter
    const [updateInterceptSettings] = useUpdateInterceptSettingsMutation();
    await updateInterceptSettings({
      variables: {
        input: {
          requestsEnabled: true,
          responsesEnabled: true,
          requestFilter: '^https://api\\..*'
        }
      }
    });
    
    // Set interception scope
    const [setScope] = useSetScopeMutation();
    await setScope({
      variables: {
        scope: [{ url: '^https://example\.com/.*' }]
      }
    });
  11. Manage active project state with ActiveProjectProvider and useActiveProject

    main

    In the hetty-admin package, you can manage and access the currently active project state using the ActiveProjectProvider component and the useActiveProject hook.

    1. Wrap your application (or a specific component tree) with <ActiveProjectProvider>. This component internally executes a useActiveProjectQuery GraphQL query to fetch the current project data.
    2. Use the useActiveProject() hook in any child component to access the Project object. If no project is active or the query returns no data, the hook returns null.
    import { ActiveProjectProvider, useActiveProject } from './lib/ActiveProjectContext';
    
    function App() {
      return (
        <ActiveProjectProvider>
          <MyComponent />
        </ActiveProjectProvider>
      );
    }
    
    function MyComponent() {
      const project = useActiveProject();
    
      if (!project) {
        return <div>No active project selected.</div>;
      }
    
      return <div>Active Project: {project.name}</div>;
    }