mirror of
https://github.com/BishopFox/sj.git
synced 2026-11-12 18:16:39 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75da0224d3 | ||
|
|
540d6064dc | ||
|
|
686022c827 |
No files matched your search
+4
-4
@@ -32,11 +32,11 @@ changelog:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
groups:
|
||||
- title: New Features
|
||||
regexp: '(?i)^adds*'
|
||||
- title: "New Features"
|
||||
regexp: '^(Add|add)(s|ed|ing)?'
|
||||
order: 0
|
||||
- title: "Bug Fixes"
|
||||
regexp: '(?i)^fix*'
|
||||
regexp: '^(Fix|fix)(es|ed|ing)?'
|
||||
order: 1
|
||||
- title: Others
|
||||
- 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.
|
||||
|
||||

|
||||
|
||||
|
||||
+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 {
|
||||
|
||||
+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.")
|
||||
}
|
||||
+3
-2
@@ -7,6 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -51,7 +52,7 @@ 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"
|
||||
}
|
||||
@@ -60,7 +61,7 @@ func MakeRequest(client http.Client, method, target string, timeout int64, reqDa
|
||||
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
|
||||
|
||||
+2
-2
@@ -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.6",
|
||||
Version: "1.4.2",
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
|
||||
+43
-18
@@ -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,13 +107,13 @@ 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)
|
||||
}
|
||||
|
||||
@@ -204,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())
|
||||
@@ -238,25 +238,46 @@ func GenerateRequests(bodyBytes []byte, client http.Client, command string) []st
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -266,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
|
||||
@@ -319,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://", "")
|
||||
|
||||
Reference in new issue
Block a user