mirror of
https://github.com/BishopFox/sj.git
synced 2026-11-10 09:51:26 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75da0224d3 | ||
|
|
540d6064dc | ||
|
|
686022c827 | ||
|
|
df162f7c35 | ||
|
|
4d7814c74e | ||
|
|
4bde10ad1b | ||
|
|
4d05f51fbe |
No files matched your search
@@ -1,3 +1,5 @@
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
@@ -29,3 +31,12 @@ changelog:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
groups:
|
||||
- title: "New Features"
|
||||
regexp: '^(Add|add)(s|ed|ing)?'
|
||||
order: 0
|
||||
- title: "Bug Fixes"
|
||||
regexp: '^(Fix|fix)(es|ed|ing)?'
|
||||
order: 1
|
||||
- title: "Others"
|
||||
order: 999
|
||||
@@ -32,7 +32,7 @@ $ go install github.com/BishopFox/sj@latest
|
||||
|
||||

|
||||
|
||||
> Use the `prepare` command to prepare a list of curl commands for manual testing. You will likely have to modify these slightly.
|
||||
> Use the `prepare` command to prepare a list of commands for manual testing. Currently supports both `curl` and `sqlmap`. You will likely have to modify these slightly.
|
||||
|
||||

|
||||
|
||||
|
||||
+60
-51
@@ -21,61 +21,70 @@ var (
|
||||
|
||||
func CheckSecDefs(doc3 openapi3.T) (apiInQuery bool, apiKey string, apiKeyName string) {
|
||||
|
||||
if len(doc3.Components.SecuritySchemes) > 0 {
|
||||
log.Info("Available authentication mechanisms: ")
|
||||
}
|
||||
|
||||
for mechanism := range doc3.Components.SecuritySchemes {
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value == nil {
|
||||
log.Error("Authorization schema structure unsupported. Manual testing is required.")
|
||||
return false, "", ""
|
||||
if outputFormat == "json" {
|
||||
if len(doc3.Components.SecuritySchemes) != 0 {
|
||||
log.Warnf("The following authentication mechanisms are supported. If necessary, supply these manually when using the JSON output format:\n")
|
||||
}
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value.Scheme != "" {
|
||||
fmt.Printf(" - %s (%s)\n", mechanism, doc3.Components.SecuritySchemes[mechanism].Value.Scheme)
|
||||
} else {
|
||||
fmt.Printf(" - %s\n", mechanism)
|
||||
for mechanism := range doc3.Components.SecuritySchemes {
|
||||
log.Infof(`Type: %s, Scheme: %s`, doc3.Components.SecuritySchemes[mechanism].Value.Type, doc3.Components.SecuritySchemes[mechanism].Value.Scheme)
|
||||
}
|
||||
} else {
|
||||
if len(doc3.Components.SecuritySchemes) > 0 {
|
||||
log.Info("Available authentication mechanisms: ")
|
||||
}
|
||||
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value.Type == "http" && !quiet {
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value.Scheme == "basic" {
|
||||
log.Infof("Basic Authentication is accepted. Supply a username and password? (y/N)")
|
||||
fmt.Scanln(&autoApplyBasicAuth)
|
||||
autoApplyBasicAuth = strings.ToLower(autoApplyBasicAuth)
|
||||
if autoApplyBasicAuth == "y" {
|
||||
fmt.Printf("Enter a username.")
|
||||
fmt.Scanln(&basicAuthUser)
|
||||
fmt.Printf("Enter a password.")
|
||||
fmt.Scanln(&basicAuthPass)
|
||||
basicAuth = []byte(basicAuthUser + ":" + basicAuthPass)
|
||||
basicAuthString = base64.StdEncoding.EncodeToString(basicAuth)
|
||||
log.Infof("Using %s as the Basic Auth value.", basicAuthString)
|
||||
Headers = append(Headers, "Authorization: Basic "+basicAuthString)
|
||||
} else {
|
||||
log.Warn("A basic authentication header is accepted. Review the spec and craft a header manually using the -H flag.")
|
||||
for mechanism := range doc3.Components.SecuritySchemes {
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value == nil {
|
||||
log.Error("Authorization schema structure unsupported. Manual testing is required.")
|
||||
return false, "", ""
|
||||
}
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value.Scheme != "" {
|
||||
fmt.Printf(" - %s (%s)\n", mechanism, doc3.Components.SecuritySchemes[mechanism].Value.Scheme)
|
||||
} else if outputFormat != "json" {
|
||||
fmt.Printf(" - %s\n", mechanism)
|
||||
}
|
||||
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value.Type == "http" && !quiet {
|
||||
if doc3.Components.SecuritySchemes[mechanism].Value.Scheme == "basic" {
|
||||
log.Infof("Basic Authentication is accepted. Supply a username and password? (y/N)")
|
||||
fmt.Scanln(&autoApplyBasicAuth)
|
||||
autoApplyBasicAuth = strings.ToLower(autoApplyBasicAuth)
|
||||
if autoApplyBasicAuth == "y" {
|
||||
fmt.Printf("Enter a username.")
|
||||
fmt.Scanln(&basicAuthUser)
|
||||
fmt.Printf("Enter a password.")
|
||||
fmt.Scanln(&basicAuthPass)
|
||||
basicAuth = []byte(basicAuthUser + ":" + basicAuthPass)
|
||||
basicAuthString = base64.StdEncoding.EncodeToString(basicAuth)
|
||||
log.Infof("Using %s as the Basic Auth value.", basicAuthString)
|
||||
Headers = append(Headers, "Authorization: Basic "+basicAuthString)
|
||||
} else {
|
||||
log.Warn("A basic authentication header is accepted. Review the spec and craft a header manually using the -H flag.")
|
||||
}
|
||||
} else if strings.ToLower(doc3.Components.SecuritySchemes[mechanism].Value.Scheme) == "bearer" {
|
||||
log.Warn("A bearer token is accepted. Review the spec and craft a token manually using the -H flag.")
|
||||
}
|
||||
} else if doc3.Components.SecuritySchemes[mechanism].Value.Type == "apiKey" && doc3.Components.SecuritySchemes[mechanism].Value.In == "query" && !quiet {
|
||||
apiInQuery = true
|
||||
log.Infof("An API key can be provided via a parameter string. Would you like to apply one? (y/N)")
|
||||
fmt.Scanln(&autoApplyAPIKey)
|
||||
autoApplyAPIKey = strings.ToLower(autoApplyAPIKey)
|
||||
if autoApplyAPIKey == "y" {
|
||||
apiKeyName = doc3.Components.SecuritySchemes[mechanism].Value.Name
|
||||
fmt.Printf("What value would you like to use for the API key (%s)?", apiKeyName)
|
||||
fmt.Scanln(&apiKey)
|
||||
log.Infof("Using %s=%s as the API key in all requests.", apiKeyName, apiKey)
|
||||
}
|
||||
} else if doc3.Components.SecuritySchemes[mechanism].Value.Type == "apiKey" && doc3.Components.SecuritySchemes[mechanism].Value.In == "header" && !quiet {
|
||||
log.Infof("An API key can be provided via the header %s. Would you like to apply one? (y/N)", doc3.Components.SecuritySchemes[mechanism].Value.Name)
|
||||
fmt.Scanln(&autoApplyAPIKey)
|
||||
autoApplyAPIKey = strings.ToLower(autoApplyAPIKey)
|
||||
if autoApplyAPIKey == "y" {
|
||||
apiKeyName = doc3.Components.SecuritySchemes[mechanism].Value.Name
|
||||
fmt.Printf("What value would you like to use for the API key (%s)?", apiKeyName)
|
||||
fmt.Scanln(&apiKey)
|
||||
Headers = append(Headers, doc3.Components.SecuritySchemes[mechanism].Value.Name+": "+apiKey)
|
||||
}
|
||||
} else if strings.ToLower(doc3.Components.SecuritySchemes[mechanism].Value.Scheme) == "bearer" {
|
||||
log.Warn("A bearer token is accepted. Review the spec and craft a token manually using the -H flag.")
|
||||
}
|
||||
} else if doc3.Components.SecuritySchemes[mechanism].Value.Type == "apiKey" && doc3.Components.SecuritySchemes[mechanism].Value.In == "query" && !quiet {
|
||||
apiInQuery = true
|
||||
log.Infof("An API key can be provided via a parameter string. Would you like to apply one? (y/N)")
|
||||
fmt.Scanln(&autoApplyAPIKey)
|
||||
autoApplyAPIKey = strings.ToLower(autoApplyAPIKey)
|
||||
if autoApplyAPIKey == "y" {
|
||||
apiKeyName = doc3.Components.SecuritySchemes[mechanism].Value.Name
|
||||
fmt.Printf("What value would you like to use for the API key (%s)?", apiKeyName)
|
||||
fmt.Scanln(&apiKey)
|
||||
log.Infof("Using %s=%s as the API key in all requests.", apiKeyName, apiKey)
|
||||
}
|
||||
} else if doc3.Components.SecuritySchemes[mechanism].Value.Type == "apiKey" && doc3.Components.SecuritySchemes[mechanism].Value.In == "header" && !quiet {
|
||||
log.Infof("An API key can be provided via the header %s. Would you like to apply one? (y/N)", doc3.Components.SecuritySchemes[mechanism].Value.Name)
|
||||
fmt.Scanln(&autoApplyAPIKey)
|
||||
autoApplyAPIKey = strings.ToLower(autoApplyAPIKey)
|
||||
if autoApplyAPIKey == "y" {
|
||||
apiKeyName = doc3.Components.SecuritySchemes[mechanism].Value.Name
|
||||
fmt.Printf("What value would you like to use for the API key (%s)?", apiKeyName)
|
||||
fmt.Scanln(&apiKey)
|
||||
Headers = append(Headers, doc3.Components.SecuritySchemes[mechanism].Value.Name+": "+apiKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ responds in an abnormal way, manual testing should be conducted (prepare manual
|
||||
}
|
||||
|
||||
if swaggerURL != "" {
|
||||
bodyBytes, _, _ = MakeRequest(client, "GET", swaggerURL, timeout, nil, "automate")
|
||||
bodyBytes, _, _ = MakeRequest(client, "GET", swaggerURL, timeout, nil)
|
||||
} else {
|
||||
specFile, err := os.Open(localFile)
|
||||
if err != nil {
|
||||
@@ -46,7 +46,7 @@ responds in an abnormal way, manual testing should be conducted (prepare manual
|
||||
|
||||
bodyBytes, _ = io.ReadAll(specFile)
|
||||
}
|
||||
GenerateRequests(bodyBytes, client, "automate")
|
||||
GenerateRequests(bodyBytes, client)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -104,7 +104,7 @@ func findDefinitionFile(urls []string, client http.Client) (bool, *openapi3.T) {
|
||||
for i, url := range urls {
|
||||
ct := CheckContentType(client, url)
|
||||
if strings.Contains(ct, "application/json") {
|
||||
bodyBytes, _, _ := MakeRequest(client, "GET", url, timeout, nil, "brute")
|
||||
bodyBytes, _, _ := MakeRequest(client, "GET", url, timeout, nil)
|
||||
if bodyBytes != nil {
|
||||
checkSpec := UnmarshalSpec(bodyBytes)
|
||||
if (strings.HasPrefix(checkSpec.OpenAPI, "2") || strings.HasPrefix(checkSpec.OpenAPI, "3")) && checkSpec.Paths != nil {
|
||||
@@ -113,7 +113,7 @@ func findDefinitionFile(urls []string, client http.Client) (bool, *openapi3.T) {
|
||||
}
|
||||
}
|
||||
} else if strings.Contains(ct, "application/javascript") {
|
||||
bodyBytes, bodyString, _ := MakeRequest(client, "GET", url, timeout, nil, "brute")
|
||||
bodyBytes, bodyString, _ := MakeRequest(client, "GET", url, timeout, nil)
|
||||
if bodyBytes != nil {
|
||||
regexPattern := regexp.MustCompile(`(?s)let\s+(\w+)\s*=\s*({.*?});`)
|
||||
matches := regexPattern.FindAllStringSubmatch(bodyString, -1)
|
||||
|
||||
+3
-3
@@ -25,15 +25,15 @@ This list contains the raw endpoints (parameter values will not be appended or m
|
||||
log.Infof("Gathering endpoints.\n\n")
|
||||
|
||||
if swaggerURL != "" {
|
||||
bodyBytes, _, _ := MakeRequest(client, "GET", swaggerURL, timeout, nil, "endpoints")
|
||||
paths = GenerateRequests(bodyBytes, client, "endpoints")
|
||||
bodyBytes, _, _ := MakeRequest(client, "GET", swaggerURL, timeout, nil)
|
||||
paths = GenerateRequests(bodyBytes, client)
|
||||
} else {
|
||||
specFile, err := os.Open(localFile)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening file:", err)
|
||||
}
|
||||
bodyBytes, _ = io.ReadAll(specFile)
|
||||
paths = GenerateRequests(bodyBytes, client, "endpoints")
|
||||
paths = GenerateRequests(bodyBytes, client)
|
||||
}
|
||||
unique.Sort(unique.StringSlice{&paths})
|
||||
for _, v := range paths {
|
||||
|
||||
+10
@@ -14,6 +14,8 @@ func writeLog(sc int, target, method string, errorMsg string) {
|
||||
logSkipped(sc, target, method)
|
||||
} else if sc == 404 {
|
||||
logNotFound(sc, target, method, errorMsg)
|
||||
} else if sc == 1 {
|
||||
logDangerous(target, method)
|
||||
} else {
|
||||
logManual(sc, target, method, errorMsg)
|
||||
}
|
||||
@@ -30,6 +32,14 @@ func logAccessible(status int, target, method string) {
|
||||
}).Print("Endpoint accessible!")
|
||||
}
|
||||
|
||||
func logDangerous(target, method string) {
|
||||
log.WithFields(log.Fields{
|
||||
"Status": "skipped",
|
||||
"Target": target,
|
||||
"Method": method,
|
||||
}).Warn("Endpoint skipped due to dangerous keyword.")
|
||||
}
|
||||
|
||||
func logManual(status int, target, method, errorMsg string) {
|
||||
if errorMsg == "" {
|
||||
errorMsg = "Manual testing may be required."
|
||||
|
||||
+9
-4
@@ -12,7 +12,7 @@ import (
|
||||
var prepareCmd = &cobra.Command{
|
||||
Use: "prepare",
|
||||
Short: "Prepares a set of commands for manual testing of each endpoint.",
|
||||
Long: `The prepare command prepares a set of curl commands for manual testing of each endpoint.
|
||||
Long: `The prepare command prepares a set of commands for manual testing of each endpoint.
|
||||
This enables you to test specific API functions for common vulnerabilities or misconfigurations.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := CheckAndConfigureProxy()
|
||||
@@ -20,8 +20,8 @@ This enables you to test specific API functions for common vulnerabilities or mi
|
||||
fmt.Printf("\n")
|
||||
log.Infof("Gathering API details.\n\n")
|
||||
if swaggerURL != "" {
|
||||
bodyBytes, _, _ := MakeRequest(client, "GET", swaggerURL, timeout, nil, "prepare")
|
||||
GenerateRequests(bodyBytes, client, "prepare")
|
||||
bodyBytes, _, _ := MakeRequest(client, "GET", swaggerURL, timeout, nil)
|
||||
GenerateRequests(bodyBytes, client)
|
||||
} else {
|
||||
specFile, err := os.Open(localFile)
|
||||
if err != nil {
|
||||
@@ -29,7 +29,12 @@ This enables you to test specific API functions for common vulnerabilities or mi
|
||||
}
|
||||
|
||||
specBytes, _ := io.ReadAll(specFile)
|
||||
GenerateRequests(specBytes, client, "prepare")
|
||||
GenerateRequests(specBytes, client)
|
||||
}
|
||||
},
|
||||
}
|
||||
var prepareFor string
|
||||
|
||||
func init() {
|
||||
prepareCmd.PersistentFlags().StringVarP(&prepareFor, "external-tool", "e", "curl", "The external tool to prepare commands for. Generates syntax for 'curl' by default.")
|
||||
}
|
||||
+11
-5
@@ -7,6 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -51,25 +52,26 @@ var (
|
||||
userChoice string
|
||||
)
|
||||
|
||||
func MakeRequest(client http.Client, method, target string, timeout int64, reqData io.Reader, command string) ([]byte, string, int) {
|
||||
func MakeRequest(client http.Client, method, target string, timeout int64, reqData io.Reader) ([]byte, string, int) {
|
||||
if quiet {
|
||||
avoidDangerousRequests = "y"
|
||||
}
|
||||
|
||||
// Handling of dangerous keywords
|
||||
u, _ := url.Parse(target)
|
||||
endpoint := u.RawPath + "?" + u.RawQuery
|
||||
for _, v := range dangerousStrings {
|
||||
if command == "automate" && strings.Contains(endpoint, v) && !strings.Contains(strings.Join(safeWords, ","), v) {
|
||||
if os.Args[1] == "automate" && strings.Contains(endpoint, v) && !strings.Contains(strings.Join(safeWords, ","), v) {
|
||||
userChoice = ""
|
||||
if avoidDangerousRequests == "y" {
|
||||
return nil, "", 0
|
||||
} else {
|
||||
fmt.Printf("[!] Dangerous keyword '%s' detected in URL (%s). Do you still want to test this endpoint? (y/N)", v, target)
|
||||
log.Warnf("Dangerous keyword '%s' detected in URL (%s). Do you still want to test this endpoint? (y/N)", v, target)
|
||||
fmt.Scanln(&userChoice)
|
||||
if strings.ToLower(userChoice) != "y" {
|
||||
if !riskSurveyed {
|
||||
avoidDangerousRequests = "y"
|
||||
fmt.Printf("[!] Do you want to avoid all dangerous requests? (Y/n)")
|
||||
log.Warnf("Do you want to avoid all dangerous requests? (Y/n)")
|
||||
fmt.Scanln(&avoidDangerousRequests)
|
||||
avoidDangerousRequests = strings.ToLower(avoidDangerousRequests)
|
||||
riskSurveyed = true
|
||||
@@ -106,6 +108,7 @@ func MakeRequest(client http.Client, method, target string, timeout int64, reqDa
|
||||
}
|
||||
}
|
||||
|
||||
// User-Agent handling
|
||||
if randomUserAgent {
|
||||
if UserAgent != "Swagger Jacker (github.com/BishopFox/sj)" {
|
||||
log.Fatalf("Cannot set a User Agent while supplying the 'random-user-agent' flag.")
|
||||
@@ -137,9 +140,12 @@ func MakeRequest(client http.Client, method, target string, timeout int64, reqDa
|
||||
log.Printf("Error: %s - skipping request.", err)
|
||||
return nil, "", 0
|
||||
} else if err != nil && err != context.Canceled && err != io.EOF {
|
||||
log.Error("Error: response not received.\n", err)
|
||||
if strings.Contains(fmt.Sprint(err), "tls") && !strings.Contains(fmt.Sprint(err), "user canceled") {
|
||||
log.Fatal("Try supplying the --insecure flag.")
|
||||
} else if strings.Contains(fmt.Sprint(err), "user canceled") {
|
||||
return nil, "skipped", 1
|
||||
} else {
|
||||
log.Error("Error: response not received.\n", err)
|
||||
}
|
||||
return nil, "", 0
|
||||
}
|
||||
|
||||
+4
-4
@@ -32,7 +32,7 @@ Example usage:
|
||||
Perform a quick check of endpoints which require authentication:
|
||||
$ sj automate -u https://petstore.swagger.io/v2/swagger.json
|
||||
|
||||
Generate a list of curl commands to use for manual testing:
|
||||
Generate a list of commands to use for manual testing:
|
||||
$ sj prepare -u https://petstore.swagger.io/v2/swagger.json
|
||||
|
||||
Generate a list of raw API routes for use with custom scripts:
|
||||
@@ -46,7 +46,7 @@ $ sj brute -u https://petstore.swagger.io`,
|
||||
log.Error("Command not specified. See the --help flag for usage.")
|
||||
}
|
||||
},
|
||||
Version: "1.3.4", // Also change in .goreleaser.yaml !
|
||||
Version: "1.4.2",
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
@@ -59,8 +59,8 @@ func init() {
|
||||
rootCmd.AddCommand(prepareCmd)
|
||||
rootCmd.AddCommand(bruteCmd)
|
||||
rootCmd.PersistentFlags().StringVarP(&UserAgent, "agent", "a", "Swagger Jacker (github.com/BishopFox/sj)", "Set the User-Agent string.")
|
||||
rootCmd.PersistentFlags().StringVarP(&basePath, "base-path", "b", "", "Set the API base path if not defined in the spec (i.e. /V2/)")
|
||||
rootCmd.PersistentFlags().StringVarP(&format, "format", "f", "json", "Declare the format of the documentation (json/yaml/yml/js).")
|
||||
rootCmd.PersistentFlags().StringVarP(&basePath, "base-path", "b", "", "Set the API base path if not defined in the definition file (i.e. /V2/).")
|
||||
rootCmd.PersistentFlags().StringVarP(&format, "format", "f", "json", "Declare the format of the definition file (json/yaml/yml/js).")
|
||||
rootCmd.PersistentFlags().StringArrayVarP(&Headers, "headers", "H", nil, "Add custom headers, separated by a colon (\"Name: Value\"). Multiple flags are accepted.")
|
||||
rootCmd.PersistentFlags().BoolVarP(&insecure, "insecure", "i", false, "Ignores server certificate validation.")
|
||||
rootCmd.PersistentFlags().StringVarP(&localFile, "local-file", "l", "", "Loads the documentation from a local file.")
|
||||
|
||||
+62
-20
@@ -93,7 +93,7 @@ func ExtractSpecFromJS(bodyBytes []byte) []byte {
|
||||
return bodyBytes
|
||||
}
|
||||
|
||||
func GenerateRequests(bodyBytes []byte, client http.Client, command string) []string {
|
||||
func GenerateRequests(bodyBytes []byte, client http.Client) []string {
|
||||
var apiKey string
|
||||
var apiKeyName string
|
||||
var apiInQuery bool = false
|
||||
@@ -107,16 +107,19 @@ func GenerateRequests(bodyBytes []byte, client http.Client, command string) []st
|
||||
|
||||
// BuildObjectsFromSchemaDefinitions(*newDoc) TODO
|
||||
|
||||
if command != "endpoints" {
|
||||
if os.Args[1] != "endpoints" {
|
||||
// Prints Title/Description values if they exist
|
||||
PrintSpecInfo(*newDoc.Info)
|
||||
apiInQuery, apiKey, apiKeyName = CheckSecDefs(*newDoc)
|
||||
}
|
||||
|
||||
if command == "automate" && outfile != "" {
|
||||
if os.Args[1] == "automate" && outfile != "" {
|
||||
WriteJSONFile(`"results":[`, false)
|
||||
}
|
||||
|
||||
if newDoc.Paths == nil {
|
||||
log.Fatalf("Could not find any defined operations. Review the file manually.")
|
||||
}
|
||||
for path, pathItem := range newDoc.Paths {
|
||||
operations := map[string]*openapi3.Operation{
|
||||
"CONNECT": pathItem.Connect,
|
||||
@@ -201,8 +204,8 @@ func GenerateRequests(bodyBytes []byte, client http.Client, command string) []st
|
||||
|
||||
u.Path = u.Path + newPath
|
||||
u.RawQuery = query.Encode()
|
||||
if command == "automate" {
|
||||
_, _, sc := MakeRequest(client, method, u.String(), timeout, bytes.NewReader([]byte(bodyData)), command)
|
||||
if os.Args[1] == "automate" {
|
||||
_, _, sc := MakeRequest(client, method, u.String(), timeout, bytes.NewReader([]byte(bodyData)))
|
||||
if sc == 200 {
|
||||
accessibleEndpointFound = true
|
||||
accessibleEndpoints = append(accessibleEndpoints, u.String())
|
||||
@@ -225,31 +228,56 @@ func GenerateRequests(bodyBytes []byte, client http.Client, command string) []st
|
||||
resultsJSON = append(resultsJSON, fmt.Sprintf(`{"status_code":"%d","url":"%s","method":"%s","details":"%s"}`, sc, u.String(), method, errorDescriptions[fmt.Sprint(sc)]))
|
||||
}
|
||||
} else {
|
||||
resultsJSON = append(resultsJSON, fmt.Sprintf(`{"status_code":"%d","url":"%s","method":"%s","details":"%s"}`, sc, u.String(), method, errorDescriptions[fmt.Sprint(sc)]))
|
||||
if sc == 1 {
|
||||
resultsJSON = append(resultsJSON, fmt.Sprintf(`{"status_code":"%d","url":"%s","method":"%s","details":"Skipped due to dangerous keyword in request"}`, sc, u.String(), method))
|
||||
} else {
|
||||
resultsJSON = append(resultsJSON, fmt.Sprintf(`{"status_code":"%d","url":"%s","method":"%s","details":"%s"}`, sc, u.String(), method, errorDescriptions[fmt.Sprint(sc)]))
|
||||
}
|
||||
}
|
||||
} else if !getAccessibleEndpoints && strings.ToLower(outputFormat) == "console" {
|
||||
writeLog(sc, u.String(), method, errorDescriptions[fmt.Sprint(sc)])
|
||||
}
|
||||
}
|
||||
} else if command == "prepare" {
|
||||
if bodyData == nil {
|
||||
if len(Headers) == 0 {
|
||||
fmt.Printf("curl -sk -X %s '%s'\n", method, u.String())
|
||||
} else if os.Args[1] == "prepare" {
|
||||
if strings.ToLower(prepareFor) == "curl" {
|
||||
if bodyData == nil {
|
||||
if len(Headers) == 0 {
|
||||
fmt.Printf("curl -sk -X %s '%s'\n", method, u.String())
|
||||
} else {
|
||||
fmt.Printf("curl -sk -X %s '%s' -H '%s'\n", method, u.String(), strings.Join(Headers, "' -H '"))
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("curl -sk -X %s '%s' -H '%s'\n", method, u.String(), strings.Join(Headers, "' -H '"))
|
||||
if len(Headers) == 0 {
|
||||
fmt.Printf("curl -sk -X %s '%s' -d '%s'\n", method, u.String(), bodyData)
|
||||
} else {
|
||||
fmt.Printf("curl -sk -X %s '%s' -d '%s' -H '%s'\n", method, u.String(), bodyData, strings.Join(Headers, "' -H '"))
|
||||
}
|
||||
}
|
||||
} else if strings.ToLower(prepareFor) == "sqlmap" {
|
||||
if bodyData == nil {
|
||||
if len(Headers) == 0 {
|
||||
fmt.Printf("sqlmap -u %s\n", u.String())
|
||||
} else {
|
||||
fmt.Printf("sqlmap -u %s -H '%s'\n", u.String(), strings.Join(Headers, "' -H '"))
|
||||
}
|
||||
} else {
|
||||
if len(Headers) == 0 {
|
||||
fmt.Printf("sqlmap -u %s --data='%s'\n", u.String(), bodyData)
|
||||
} else {
|
||||
fmt.Printf("sqlmap -u %s --data='%s' -H '%s'\n", u.String(), bodyData, strings.Join(Headers, "' -H '"))
|
||||
}
|
||||
}
|
||||
} else if strings.ToLower(prepareFor) == "ffuf" {
|
||||
// TODO
|
||||
} else {
|
||||
if len(Headers) == 0 {
|
||||
fmt.Printf("curl -sk -X %s '%s' -d '%s'\n", method, u.String(), bodyData)
|
||||
} else {
|
||||
fmt.Printf("curl -sk -X %s '%s' -d '%s' -H '%s'\n", method, u.String(), bodyData, strings.Join(Headers, "' -H '"))
|
||||
}
|
||||
log.Fatal("External tool not supported. Only 'curl' and 'sqlmap' are supported options for the '-e' flag at this time.")
|
||||
}
|
||||
} else if command == "endpoints" {
|
||||
|
||||
} else if os.Args[1] == "endpoints" {
|
||||
|
||||
for k := range newDoc.Paths {
|
||||
if !pathMap[k] {
|
||||
paths = append(paths, k)
|
||||
paths = append(paths, basePathResult+k)
|
||||
pathMap[k] = true
|
||||
}
|
||||
}
|
||||
@@ -259,7 +287,7 @@ func GenerateRequests(bodyBytes []byte, client http.Client, command string) []st
|
||||
}
|
||||
}
|
||||
|
||||
if command == "automate" {
|
||||
if os.Args[1] == "automate" {
|
||||
if outfile == "" && getAccessibleEndpoints && strings.ToLower(outputFormat) == "console" {
|
||||
var isDuplicateEndpoint bool
|
||||
var printedEndpoints []string
|
||||
@@ -312,6 +340,10 @@ func GetBasePath(servers openapi3.Servers, host string) (bp string) {
|
||||
basePath = "/"
|
||||
} else {
|
||||
basePath = servers[0].URL
|
||||
if strings.Contains(host, ":") {
|
||||
hostPortStart := strings.Index(host, ":")
|
||||
host = host[0:hostPortStart]
|
||||
}
|
||||
if strings.Contains(basePath, host) || strings.Contains(basePath, "http") {
|
||||
basePath = strings.ReplaceAll(basePath, host, "")
|
||||
basePath = strings.ReplaceAll(basePath, "http://", "")
|
||||
@@ -338,6 +370,10 @@ func PrintSpecInfo(i openapi3.Info) {
|
||||
if i.Description != "" {
|
||||
fmt.Printf("Description: %s\n\n", i.Description)
|
||||
}
|
||||
|
||||
if i.Title == "" && i.Description == "" {
|
||||
log.Warnf("Detected possible error in parsing the definition file. Title and description values are empty.\n\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,12 +420,18 @@ func UnmarshalSpec(bodyBytes []byte) (newDoc *openapi3.T) {
|
||||
if strings.HasPrefix(doc3.OpenAPI, "3") {
|
||||
newDoc := &doc3
|
||||
return newDoc
|
||||
} else {
|
||||
} else if strings.HasPrefix(doc.Swagger, "2") {
|
||||
newDoc, err := openapi2conv.ToV3(&doc)
|
||||
if err != nil {
|
||||
fmt.Printf("Error converting v2 document to v3: %s\n", err)
|
||||
}
|
||||
return newDoc
|
||||
} else if os.Args[1] == "brute" {
|
||||
var noDoc openapi3.T
|
||||
return &noDoc
|
||||
} else {
|
||||
log.Fatal("Error parsing definition file.\n")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user