Skip to content

Commit

Permalink
Merge pull request #8 from 0x303/feature_1-brute_custom_wordlists
Browse files Browse the repository at this point in the history
Feature: brute custom wordlists
  • Loading branch information
twest-bf authored Jul 16, 2024
2 parents eef1407 + 03ac3f1 commit 17743c8
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 124 deletions.
202 changes: 79 additions & 123 deletions cmd/brute.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"bufio"
"encoding/json"
"fmt"
"net/http"
Expand All @@ -16,75 +17,83 @@ import (
log "github.com/sirupsen/logrus"
)

var (
prefixDirs = []string{
"/docs",
"",
"/swagger",
"/swagger/docs",
"/swagger/v1",
"/swagger/v2",
"/swagger/v3",
"/swagger/static",
"/swagger/ui",
"/swagger-ui",
"/api-docs",
"/api-docs/v1",
"/api-docs/v2",
"/apidocs",
"/api",
"/api/v1",
"/api/v2",
"/api/v3",
"/v1",
"/v2",
"/v3",
"/doc",
"/docs/swagger",
"/docs/swagger/v1",
"/docs/swagger/v2",
"/docs/swagger-ui",
"/docs/swagger-ui/v1",
"/docs/swagger-ui/v2",
"/docs/v1",
"/docs/v2",
"/docs/v3",
"/public",
"/redoc",
}
jsonEndpoints = []string{
"",
"/index",
"/swagger",
"/swagger-ui",
"/swagger-resources",
"/swagger-config",
"/openapi",
"/api",
"/api-docs",
"/apidocs",
"/v1",
"/v2",
"/v3",
"/doc",
"/docs",
"/apispec",
"/apispec_1",
"/api-merged",
}
javascriptEndpoints = []string{
"/swagger-ui-init",
"/swagger-ui-bundle",
"/swagger-ui-standalone-preset",
"/swagger-ui",
"/swagger-ui.min",
"/swagger-ui-es-bundle-core",
"/swagger-ui-es-bundle",
"/swagger-ui-standalone-preset",
"/swagger-ui-layout",
"/swagger-ui-plugins",
}
)
var endpointWordlist string

var prefixDirs []string = []string{"", "/swagger", "/swagger/docs", "/swagger/latest", "/swagger/v1", "/swagger/v2", "/swagger/v3", "/swagger/static", "/swagger/ui", "/swagger-ui", "/api-docs", "/api-docs/v1", "/api-docs/v2", "/apidocs", "/api", "/api/v1", "/api/v2", "/api/v3", "/v1", "/v2", "/v3", "/doc", "/docs", "/docs/swagger", "/docs/swagger/v1", "/docs/swagger/v2", "/docs/swagger-ui", "/docs/swagger-ui/v1", "/docs/swagger-ui/v2", "/docs/v1", "/docs/v2", "/docs/v3", "/public", "/redoc"}
var jsonEndpoints []string = []string{"", "/index", "/swagger", "/swagger-ui", "/swagger-resources", "/swagger-config", "/openapi", "/api", "/api-docs", "/apidocs", "/v1", "/v2", "/v3", "/doc", "/docs", "/apispec", "/apispec_1", "/api-merged"}
var javascriptEndpoints []string = []string{"/swagger-ui-init", "/swagger-ui-bundle", "/swagger-ui-standalone-preset", "/swagger-ui", "/swagger-ui.min", "/swagger-ui-es-bundle-core", "/swagger-ui-es-bundle", "/swagger-ui-standalone-preset", "/swagger-ui-layout", "/swagger-ui-plugins"}

var bruteCmd = &cobra.Command{
Use: "brute",
Short: "Sends a series of automated requests to discover hidden API operation definitions.",
Long: `The brute command sends requests to the target to find operation definitions based on commonly used file locations.`,
Run: func(cmd *cobra.Command, args []string) {

client := CheckAndConfigureProxy()

var allURLs []string
u, err := url.Parse(swaggerURL)
if err != nil {
log.Warnf("Error parsing URL:%s\n", err)
}
target := u.Scheme + "://" + u.Host
if endpointWordlist == "" {
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, "")...)
allURLs = append(allURLs, makeURLs(target, javascriptEndpoints, ".js")...)
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, ".json")...)
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, "/")...)
} else {
endpointList, err := os.Open(endpointWordlist)
if err != nil {
log.Fatalf("failed to open file: %s", err)
}
defer endpointList.Close()

scanner := bufio.NewScanner(endpointList)
for scanner.Scan() {
endpoint := scanner.Text()
fullURL := target + endpoint
allURLs = append(allURLs, fullURL)
}

if err := scanner.Err(); err != nil {
log.Fatalf("failed to read words from file: %s", err)
}
}
log.Infof("Sending %d requests. This could take a while...\n", len(allURLs))

specFound, definitionFile := findDefinitionFile(allURLs, client)
if specFound {
definedOperations, err := json.Marshal(definitionFile)
if err != nil {
log.Errorf("Error parsing definition file:%s\n", err)
}

if outfile != "" {

file, err := os.OpenFile(outfile, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Errorf("Error opening file: %s\n", err)
}

defer file.Close()

_, err = file.Write(definedOperations)
if err != nil {
log.Errorf("Error writing file: %s\n", err)
} else {
f, _ := filepath.Abs(outfile)
log.Infof("Wrote file to %s\n", f)
}
} else {
fmt.Println(string(definedOperations))
}
// TODO: Check if (future implementation) automate flag is true and if so than call the 'sj automate' command with the discovered definition file.
} else {
log.Errorf("No definition file found for:\t%s\n", swaggerURL)
}
},
}

func makeURLs(target string, endpoints []string, fileExtension string) []string {
urls := []string{}
Expand Down Expand Up @@ -139,60 +148,7 @@ func findDefinitionFile(urls []string, client http.Client) (bool, *openapi3.T) {
return false, nil
}

var bruteCmd = &cobra.Command{
Use: "brute",
Short: "Sends a series of automated requests to discover hidden API operation definitions.",
Long: `The brute command sends requests to the target to find operation definitions based on commonly used file locations.`,
Run: func(cmd *cobra.Command, args []string) {

client := CheckAndConfigureProxy()

var allURLs []string
u, err := url.Parse(swaggerURL)
if err != nil {
log.Warnf("Error parsing URL:%s\n", err)
}
target := u.Scheme + "://" + u.Host

allURLs = append(allURLs, makeURLs(target, jsonEndpoints, "")...)
allURLs = append(allURLs, makeURLs(target, javascriptEndpoints, ".js")...)
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, ".json")...)
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, "/")...)
log.Infof("Sending %d requests. This could take a while...\n", len(allURLs))

specFound, definitionFile := findDefinitionFile(allURLs, client)
if specFound {
definedOperations, err := json.Marshal(definitionFile)
if err != nil {
log.Errorf("Error parsing definition file:%s\n", err)
}

if outfile != "" {

file, err := os.OpenFile(outfile, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Errorf("Error opening file: %s\n", err)
}

defer file.Close()

_, err = file.Write(definedOperations)
if err != nil {
log.Errorf("Error writing file: %s\n", err)
} else {
f, _ := filepath.Abs(outfile)
log.Infof("Wrote file to %s\n", f)
}
} else {
fmt.Println(string(definedOperations))
}
// TODO: Check if (future implementation) automate flag is true and if so than call the 'sj automate' command with the discovered definition file.
} else {
log.Errorf("No definition file found for:\t%s\n", swaggerURL)
}
},
}

func init() {
// TODO: Add a flag here (boolean) that defaults to false that will cause the program to execute 'sj automate' on the discovered definition file automatically.
bruteCmd.PersistentFlags().StringVarP(&endpointWordlist, "wordlist", "w", "", "The file containing a list of paths to brute force for discovery.")
}
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ $ sj brute -u https://petstore.swagger.io`,
log.Error("Command not specified. See the --help flag for usage.")
}
},
Version: "1.4.6",
Version: "1.5.0",
}

func Execute() {
Expand Down

0 comments on commit 17743c8

Please sign in to comment.