Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix loading dynamic auth templates on fuzzing #5646

Merged
merged 2 commits into from
Sep 20, 2024

Conversation

RamanaReddy0M
Copy link
Contributor

@RamanaReddy0M RamanaReddy0M commented Sep 19, 2024

closes:

Test:

setup mock server
      package main
      
      import (
          "encoding/json"
          "fmt"
          "log"
          "net/http"
          "strings"
      )
      
      // LoginRequest represents the structure of the login request body
      type LoginRequest struct {
          Username string `json:"username"`
          Password string `json:"password"`
      }
      
      // LoginResponse represents the structure of the login response
      type LoginResponse struct {
          Token   string `json:"auth_token"`
          Message string `json:"message"`
          Status  string `json:"status"`
      }
      
      // TokenCheckerResponse simulates a test response with potential SQL error for regex matchers
      type TokenCheckerResponse struct {
          Message string `json:"message"`
          Status  string `json:"status"`
      }
      
      const BearerToken = "E!d2Arrqac=JlEnGa966T8WuZS7Q0J9GRB-Mk6-8nC47VNCTnNrf!TrnIZc7VYC!DM=//yGwIIf!0z!H3j63MIPOKXOdKoCAflHFOGwojSl5Mw-i9thpIO0pwnucLbisauh0h?Bb6lG?9KZrw3IlkCHj1jR6fCfRWD0lH9nRop4yWvKyTb050?66BQpEChpo6lNI4!eCXjToCz5UVTh/8MrhBcLMRB0zcMR/ji6!Hrg?LEzpizs9RtzKfdn8KRzc"
      
      func main() {
          http.HandleFunc("/users/v1/login", loginHandler)
          http.HandleFunc("/api/test", tokenCheckHandler)
      
          fmt.Println("Server is running on http://127.0.0.1:5002")
          log.Fatal(http.ListenAndServe(":5002", nil))
      }
      
      // loginHandler handles the login request
      func loginHandler(w http.ResponseWriter, r *http.Request) {
          // Check if the method is POST
          if r.Method != http.MethodPost {
  	        http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
  	        return
          }
      
          // Parse request body to get username and password
          var loginReq LoginRequest
          if err := json.NewDecoder(r.Body).Decode(&loginReq); err != nil {
  	        http.Error(w, "Invalid request body", http.StatusBadRequest)
  	        return
          }
      
          // Simulate authentication logic
          if loginReq.Username == "name1" && loginReq.Password == "pass1" {
  	        // Simulate issuing an auth token
  	        token := LoginResponse{
  		        Token:   BearerToken,
  		        Message: "Successfully logged in.",
  		        Status:  "success",
  	        }
      
  	        // Set response header to application/json
  	        w.Header().Set("Content-Type", "application/json")
  	        w.WriteHeader(http.StatusOK)
  	        json.NewEncoder(w).Encode(token)
          } else {
  	        http.Error(w, "Invalid credentials", http.StatusUnauthorized)
          }
      }
      
      // tokenCheckHandler checks the Bearer token and returns a SQL error if the token is valid
      func tokenCheckHandler(w http.ResponseWriter, r *http.Request) {
          // Check if the method is GET
          if r.Method != http.MethodGet {
  	        http.Error(w, "Only GET method is allowed", http.StatusMethodNotAllowed)
  	        return
          }
      
          // Check Authorization header for Bearer token
          authHeader := r.Header.Get("Authorization")
          if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
  	        http.Error(w, "Missing or invalid Authorization header", http.StatusUnauthorized)
  	        return
          }
      
          // Extract the token from the Authorization header
          token := strings.TrimPrefix(authHeader, "Bearer ")
          if token != BearerToken {
  	        http.Error(w, "Invalid token", http.StatusUnauthorized)
  	        return
          }
      
          // Simulate returning a response that contains SQL-related error for regex matcher
          sqlErrorResponse := TokenCheckerResponse{
  	        Message: "SELECT * FROM users WHERE id = ?; SQL Error: Table not found",
  	        Status:  "error",
          }
      
          // Set response header to application/json
          w.Header().Set("Content-Type", "application/json")
          w.WriteHeader(http.StatusOK)
          json.NewEncoder(w).Encode(sqlErrorResponse)
      }
use login.yaml and sqli-test.yaml templates
  1. login.yaml:
id: login

info:
  name: Login
  author: test 
  severity: info
  tags: login

http:
  - raw:
      - |
        POST /users/v1/login HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        
        {"password": "{{password}}", "username": "{{username}}"}
    
    extractors:
      - type: regex
        name: auth_token 
        part: body 
        internal: true
        group: 1
        regex:
          - '"auth_token":\s*"([^"]+)"'

2.sqli-test.yaml:

id: sqli-test

info:
  name: SQLi
  author: test
  severity: critical

http:
  - pre-condition:
      - type: dsl
        dsl:
          - 'method == "GET"'

    fuzzing:
      - part: path 
        type: postfix
        mode: single
        fuzz:
          - "/v1/test"
          - "/test"
    matchers:
      # - type: status
      #   status:
      #     - 401
      - type: regex
        name: sql_error
        regex:
          - "SELECT"
          - "SQL"
        condition: or
            
    stop-at-first-match: true
secrets.yaml
dynamic:
  - template: login.yaml
    variables:
      - key: username 
        value: name1 
      - key: password
        value: pass1
    type: bearertoken
    domains:
      - 127.0.0.1:5002
    input: http://127.0.0.1:5002 
    token: "{{auth_token}}"
input: openapi.json
{
  "openapi": "3.0.0",
  "info": {
    "version": "1.0.0",
    "title": "Simple Auth API",
    "description": "A simple API for user login and token validation."
  },
  "servers": [
    {
      "url": "http://127.0.0.1:5002",
      "description": "Local development server"
    }
  ],
  "paths": {
    "/api": {
      "get": {
        "summary": "Token validation",
        "description": "Validates the bearer token from the Authorization header.",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": true,
            "schema": {
              "type": "string",
              "example": "Bearer E!d2Arrqac=JlEnGa966T8WuZS7Q0J9GRB-Mk6-8nC47VNCTnNrf!TrnIZc7VYC!DM=//yGwIIf!0z!H3j63MIPOKXOdKoCAflHFOGwojSl5Mw-i9thpIO0pwnucLbisauh0h?Bb6lG?9KZrw3IlkCHj1jR6fCfRWD0lH9nRop4yWvKyTb050?66BQpEChpo6lNI4!eCXjToCz5UVTh/8MrhBcLMRB0zcMR/ji6!Hrg?LEzpizs9RtzKfdn8KRzc"
            },
            "description": "Bearer token from the login response"
          }
        ],
        "responses": {
          "401": {
            "description": "Invalid token or missing Authorization header",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string",
                  "example": "Missing or invalid Authorization header"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "Only GET method is allowed"
                }
              }
            }
          }
        }
      }
    }
  }
}
✗ ./nuclei -im openapi -l openapi.json  -t sqli-test.yaml -proxy http://127.0.0.1:8080 -sf secrets.yaml -debug      

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.3.2

                projectdiscovery.io

[INF] Current nuclei version: v3.3.2 (latest)
[INF] Current nuclei-templates version: v10.0.0 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 14
[INF] Templates loaded for current scan: 1
[WRN] Loading 1 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] [login] Dumped HTTP request for http://127.0.0.1:5002/users/v1/login

POST /users/v1/login HTTP/1.1
Host: 127.0.0.1:5002
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15
Connection: close
Content-Length: 42
Content-Type: application/json
Accept-Encoding: gzip

{"password": "pass1", "username": "name1"}
[DBG] [login] Dumped HTTP response http://127.0.0.1:5002/users/v1/login

HTTP/1.1 200 OK
Content-Length: 329
Content-Type: application/json
Date: Thu, 19 Sep 2024 06:46:07 GMT

{"auth_token":"E!d2Arrqac=JlEnGa966T8WuZS7Q0J9GRB-Mk6-8nC47VNCTnNrf!TrnIZc7VYC!DM=//yGwIIf!0z!H3j63MIPOKXOdKoCAflHFOGwojSl5Mw-i9thpIO0pwnucLbisauh0h?Bb6lG?9KZrw3IlkCHj1jR6fCfRWD0lH9nRop4yWvKyTb050?66BQpEChpo6lNI4!eCXjToCz5UVTh/8MrhBcLMRB0zcMR/ji6!Hrg?LEzpizs9RtzKfdn8KRzc","message":"Successfully logged in.","status":"success"}
[INF] [sqli-test] Dumped HTTP request for http://127.0.0.1:5002/api/v1/test

GET /api/v1/test HTTP/1.1
Host: 127.0.0.1:5002
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
Authorization: Bearer E!d2Arrqac=JlEnGa966T8WuZS7Q0J9GRB-Mk6-8nC47VNCTnNrf!TrnIZc7VYC!DM=//yGwIIf!0z!H3j63MIPOKXOdKoCAflHFOGwojSl5Mw-i9thpIO0pwnucLbisauh0h?Bb6lG?9KZrw3IlkCHj1jR6fCfRWD0lH9nRop4yWvKyTb050?66BQpEChpo6lNI4!eCXjToCz5UVTh/8MrhBcLMRB0zcMR/ji6!Hrg?LEzpizs9RtzKfdn8KRzc

[DBG] [sqli-test] Dumped HTTP response http://127.0.0.1:5002/api/v1/test

HTTP/1.1 404 Not Found
Content-Length: 19
Content-Type: text/plain; charset=utf-8
Date: Thu, 19 Sep 2024 06:46:07 GMT
X-Content-Type-Options: nosniff

404 page not found
[INF] [sqli-test] Dumped HTTP request for http://127.0.0.1:5002/api/test

GET /api/test HTTP/1.1
Host: 127.0.0.1:5002
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
Authorization: Bearer E!d2Arrqac=JlEnGa966T8WuZS7Q0J9GRB-Mk6-8nC47VNCTnNrf!TrnIZc7VYC!DM=//yGwIIf!0z!H3j63MIPOKXOdKoCAflHFOGwojSl5Mw-i9thpIO0pwnucLbisauh0h?Bb6lG?9KZrw3IlkCHj1jR6fCfRWD0lH9nRop4yWvKyTb050?66BQpEChpo6lNI4!eCXjToCz5UVTh/8MrhBcLMRB0zcMR/ji6!Hrg?LEzpizs9RtzKfdn8KRzc

[DBG] [sqli-test] Dumped HTTP response http://127.0.0.1:5002/api/test

HTTP/1.1 200 OK
Content-Length: 92
Content-Type: application/json
Date: Thu, 19 Sep 2024 06:46:07 GMT

{"message":"SELECT * FROM users WHERE id = ?; SQL Error: Table not found","status":"error"}
[sqli-test:sql_error] [http] [critical] http://127.0.0.1:5002/api/test [path:/api] [GET]

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

pkg/catalog/loader/loader.go Show resolved Hide resolved
@ehsandeep ehsandeep merged commit 3eee967 into dev Sep 20, 2024
12 checks passed
@ehsandeep ehsandeep deleted the issue-5493-fix-dynamic-auth-with-fuzzing branch September 20, 2024 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants