Files
sif/docs/modules.md
2026-01-03 05:57:10 -08:00

6.1 KiB

writing sif modules

sif modules are yaml files that define security checks. they're similar to nuclei templates but designed specifically for sif.

module locations

  • built-in: modules/ directory in the sif installation
  • user-defined: ~/.config/sif/modules/ (linux/macos) or %LOCALAPPDATA%\sif\modules\ (windows)

user modules can override built-in modules with the same id.

basic structure

id: unique-module-id
info:
  name: human readable name
  author: your-name
  severity: low|medium|high|critical|info
  description: what this module checks for
  tags: [tag1, tag2, tag3]

type: http

http:
  method: GET
  paths:
    - "{{BaseURL}}/path"

  matchers:
    - type: status
      status:
        - 200

fields

id (required)

unique identifier for the module. use lowercase with hyphens.

id: sqli-error-based

info (required)

metadata about the module.

info:
  name: SQL Injection Detection
  author: sif
  severity: high
  description: detects sql injection via error messages
  tags: [sqli, injection, owasp-top10]

severity levels:

  • info - informational finding
  • low - minor issue
  • medium - moderate security concern
  • high - serious vulnerability
  • critical - critical security flaw

type (required)

module type. currently only http is supported.

type: http

http

http request configuration.

method

http method to use.

http:
  method: GET

supported: GET, POST, PUT, DELETE, HEAD, OPTIONS

paths

urls to check. use {{BaseURL}} as placeholder for the target.

http:
  paths:
    - "{{BaseURL}}/.git/HEAD"
    - "{{BaseURL}}/.git/config"
    - "{{BaseURL}}/admin"

payloads

values to inject into paths. use {{payload}} as placeholder.

http:
  paths:
    - "{{BaseURL}}/?id={{payload}}"

  payloads:
    - "'"
    - "1' OR '1'='1"
    - "1; DROP TABLE--"

each payload creates a separate request for each path.

headers

custom headers to send.

http:
  headers:
    User-Agent: "Mozilla/5.0"
    X-Custom-Header: "value"

body

request body for POST/PUT requests.

http:
  method: POST
  body: '{"username": "admin", "password": "{{payload}}"}'

threads

concurrent requests (default: 10).

http:
  threads: 5

matchers

matchers determine if a response indicates a finding.

status matcher

match http status codes.

matchers:
  - type: status
    status:
      - 200
      - 301
      - 302

word matcher

match words in response.

matchers:
  - type: word
    part: body
    words:
      - "admin"
      - "login"
    condition: or

parts:

  • body - response body
  • header - response headers

conditions:

  • or - match any word (default)
  • and - match all words

regex matcher

match regex patterns.

matchers:
  - type: regex
    part: body
    regex:
      - "SQL syntax.*MySQL"
      - "ORA-[0-9]+"
      - "PostgreSQL.*ERROR"
    condition: or

combining matchers

multiple matchers are combined with AND logic by default.

matchers:
  - type: status
    status:
      - 200

  - type: word
    part: body
    words:
      - "ref: refs/"
    condition: or

this matches responses with status 200 AND containing "ref: refs/".

extractors

extractors pull data from responses.

regex extractor

extractors:
  - type: regex
    name: version
    part: body
    regex:
      - "version[\"']?\\s*[:=]\\s*[\"']?([0-9.]+)"
    group: 1

group: capture group to extract (0 = full match, 1+ = groups)

kv extractor

extract key-value pairs.

extractors:
  - type: kv
    name: headers
    part: header

examples

exposed git repository

id: git-exposed
info:
  name: exposed git repository
  author: sif
  severity: high
  description: detects exposed .git directories
  tags: [git, exposure, source-code]

type: http

http:
  method: GET
  paths:
    - "{{BaseURL}}/.git/HEAD"
    - "{{BaseURL}}/.git/config"

  matchers:
    - type: word
      part: body
      words:
        - "ref: refs/"
        - "[core]"
      condition: or

    - type: status
      status:
        - 200

  extractors:
    - type: regex
      name: branch
      part: body
      regex:
        - "ref: refs/heads/(.+)"
      group: 1

sql injection detection

id: sqli-error-based
info:
  name: sql injection (error-based)
  author: sif
  severity: high
  description: detects sql injection via database errors
  tags: [sqli, injection, database]

type: http

http:
  method: GET
  paths:
    - "{{BaseURL}}/?id={{payload}}"
    - "{{BaseURL}}/search?q={{payload}}"

  payloads:
    - "'"
    - "1' OR '1'='1"
    - "1; SELECT * FROM--"

  threads: 10

  matchers:
    - type: regex
      part: body
      regex:
        - "SQL syntax.*MySQL"
        - "ORA-[0-9]+"
        - "PostgreSQL.*ERROR"
        - "Microsoft SQL Server"
      condition: or

security headers check

id: security-headers
info:
  name: security headers analysis
  author: sif
  severity: info
  description: checks for missing security headers
  tags: [headers, security, info]

type: http

http:
  method: GET
  paths:
    - "{{BaseURL}}/"

  matchers:
    - type: status
      status:
        - 200

  extractors:
    - type: kv
      name: headers
      part: header

tips

  1. use specific paths - don't just check /, be specific about what you're looking for

  2. combine matchers - use status + content matchers together to reduce false positives

  3. limit payloads - too many payloads slow down scans, pick the most effective ones

  4. tag properly - use consistent tags so modules can be filtered with -mt

  5. test locally - run your module against a test target before sharing

running modules

# list all modules
./sif -lm

# run specific module
./sif -u https://example.com -m git-exposed

# run multiple modules
./sif -u https://example.com -m git-exposed,sqli-error-based

# run by tag
./sif -u https://example.com -mt owasp-top10

# run all modules
./sif -u https://example.com -am