GitHub Web Hook Modified


Description

Detects when a webhook is added, modified, or deleted

Query · python

from panther_github_helpers import github_alert_context


def rule(event):

    return event.get("action").startswith("hook.")


def title(event):
    repo = event.get("repo", "<UNKNOWN_REPO>")
    action = "modified"
    if event.get("action").endswith("destroy"):
        action = "deleted"
    elif event.get("action").endswith("create"):
        action = "created"

    title_str = (
        f"Github webhook [{event.deep_get('config','url',default='<UNKNOWN_URL>')}]"
        f" {action} by [{event.get('actor','<UNKNOWN_ACTOR>')}]"
    )
    if repo != "<UNKNOWN_REPO>":
        title_str += f" in repository [{repo}]"
    return title_str


def severity(event):
    if event.get("action").endswith("create"):
        return "MEDIUM"
    return "INFO"


def alert_context(event):
    ctx = github_alert_context(event)
    ctx["business"] = event.get("business", "")
    ctx["hook_id"] = event.get("hook_id", "")
    ctx["integration"] = event.get("integration", "")
    ctx["operation_type"] = event.get("operation_type", "")
    ctx["url"] = event.deep_get("config", "url", default="<UNKNOWN_URL>")
    return ctx
Raw source GitHub Web Hook Modified · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: github_webhook_modified.py
RuleID: "GitHub.Webhook.Modified"
DisplayName: "GitHub Web Hook Modified"
Enabled: true
LogTypes:
  - GitHub.Audit
Tags:
  - GitHub
  - Exfiltration:Automated Exfiltration
Reports:
  MITRE ATT&CK:
    - TA0010:T1020
Reference:
  https://docs.github.com/en/webhooks/about-webhooks
  # GH audit logs for hook events don't include the type: field
  # Only type:repo webhooks are obvious due to the repo field, Org and App look the same
  # GETs to /orgs/{org}/hooks or /repos/{owner}/{repo}/hooks will return type
  # App hooks don't return type and are defined by their API endpoint
Severity: Info
Description: Detects when a webhook is added, modified, or deleted
Tests:
  - Name: GitHub - Webhook Created
    ExpectedResult: true
    Log:
      {
        "actor": "cat",
        "action": "hook.create",
        "data":
          {
            "hook_id": 111222333444555,
            "events": ["fork", "public", "pull_request", "push", "repository"],
          },
        "config": { "url": "https://fake.url" },
        "org": "my-org",
        "p_log_type": "GitHub.Audit",
        "repo": "my-org/my-repo",
        "public_repo": false,
      }
  - Name: GitHub - Webhook Deleted
    ExpectedResult: true
    Log:
      {
        "actor": "cat",
        "action": "hook.destroy",
        "data":
          {
            "hook_id": 111222333444555,
            "events": ["fork", "public", "pull_request", "push", "repository"],
          },
        "org": "my-org",
        "p_log_type": "GitHub.Audit",
        "repo": "my-org/my-repo",
        "public_repo": false,
      }
  - Name: GitHub - Non Webhook Event
    ExpectedResult: false
    Log:
      {
        "actor": "cat",
        "action": "org.invite_member",
        "org": "my-org",
        "p_log_type": "GitHub.Audit",
        "repo": "my-org/my-repo",
      }
  - Name: Github - App Webhook Created #App and Org webhooks look the same in audit logs
    ExpectedResult: true
    Log:
      {
        "action": "hook.create",
        "actor": "dog",
        "actor_id": "11112222",
        "actor_location": { "country_code": "US" },
        "business": "my-biz",
        "business_id": "9999999",
        "config":
          {
            "content_type": "json",
            "insecure_ssl": "0",
            "url": "https://fake.url/",
          },
        "hook_id": "111222333444555",
        "integration": "My Cool Github Integration",
        "name": "webhook",
        "operation_type": "create",
        "org": "my-org",
        "org_id": 9999999,
        "p_log_type": "GitHub.Audit",
      }


# ------ paired body: github_webhook_modified.py ------

from panther_github_helpers import github_alert_context


def rule(event):

    return event.get("action").startswith("hook.")


def title(event):
    repo = event.get("repo", "<UNKNOWN_REPO>")
    action = "modified"
    if event.get("action").endswith("destroy"):
        action = "deleted"
    elif event.get("action").endswith("create"):
        action = "created"

    title_str = (
        f"Github webhook [{event.deep_get('config','url',default='<UNKNOWN_URL>')}]"
        f" {action} by [{event.get('actor','<UNKNOWN_ACTOR>')}]"
    )
    if repo != "<UNKNOWN_REPO>":
        title_str += f" in repository [{repo}]"
    return title_str


def severity(event):
    if event.get("action").endswith("create"):
        return "MEDIUM"
    return "INFO"


def alert_context(event):
    ctx = github_alert_context(event)
    ctx["business"] = event.get("business", "")
    ctx["hook_id"] = event.get("hook_id", "")
    ctx["integration"] = event.get("integration", "")
    ctx["operation_type"] = event.get("operation_type", "")
    ctx["url"] = event.deep_get("config", "url", default="<UNKNOWN_URL>")
    return ctx

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.