mirror of
https://github.com/BishopFox/sj.git
synced 2026-11-09 01:49:38 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9fac2e9fe | ||
|
|
10fe0376c0 | ||
|
|
baf4ef6c51 | ||
|
|
8e2e5fbebc | ||
|
|
a77f9f46bb | ||
|
|
5554e2bd30 | ||
|
|
09c460e768 | ||
|
|
ba45c6da26 |
No files matched your search
@@ -14,6 +14,7 @@ import (
|
||||
var getAccessibleEndpoints bool
|
||||
var outputFormat string
|
||||
var responsePreviewLength int
|
||||
var testString string
|
||||
var verbose bool
|
||||
|
||||
var automateCmd = &cobra.Command{
|
||||
@@ -74,6 +75,7 @@ responds in an abnormal way, manual testing should be conducted (prepare manual
|
||||
func init() {
|
||||
automateCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "F", "console", "The output format. Only 'console' (default) and 'json' are supported at the moment.")
|
||||
automateCmd.PersistentFlags().BoolVar(&getAccessibleEndpoints, "get-accessible-endpoints", false, "Only output the accessible endpoints (those that return a 200 status code).")
|
||||
automateCmd.PersistentFlags().StringVar(&testString, "test-string", "bishopfox", "The string to use when testing endpoints with string values.")
|
||||
automateCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "enable verbose mode, which shows a preview of each response.")
|
||||
automateCmd.PersistentFlags().IntVar(&responsePreviewLength, "response-preview-length", 50, "sets the response preview length when using verbose output.")
|
||||
|
||||
|
||||
+22
-10
@@ -26,6 +26,7 @@ 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 priorityURLs []string = []string{"/swagger.json", "/openapi.json", "/api-docs", "/swagger", "/docs", "/api/swagger.json", "/api/openapi.json", "/api-docs/swagger.json", "/api/schema/", "/webjars/swagger-ui/index.html", "/API/swagger/ui/index", "/swagger/ui/index", "/v2/swagger.json", "/v2/openapi.json", "/v2/api-docs", "/v3/api-docs", "/v3/openapi.json", "/public/api-merged.json", "/analytics/v1/swagger", "/api.json", "/api/4.0/swagger.json", "/api/api-doc/openapi.json", "/api/api-doc/openapi.yaml", "/api/doc.json", "/api/docs.json", "/api/swagger", "/api/swagger/ui/index", "/api/v1/swagger", "/api/v2/api-docs", "/api/v2/openapi.json", "/api/v2/swagger.json", "/api/v3/api-docs", "/api/v3/apispec", "/api/workorder/openapi.json", "/apidocs", "/audiences/v1/swagger", "/audittrail/v1/swagger", "/certification/v1/swagger", "/citrixapi/store/swagger.json", "/conferencetool/v1/swagger", "/course/v1/swagger", "/dcl_swagger.yaml", "/doc/doc.json", "/doc/swagger.json", "/docs/swagger.json", "/docs/v1/swagger.json", "/ecommerce/v1/swagger", "/enrollment/v1/swagger", "/externalids/v1/swagger", "/impact/v1/swagger", "/learn/v1/swagger", "/learningplan/v1/swagger", "/manage/v1/swagger", "/management/info", "/marketplace/v1/swagger", "/messenger/v1/swagger", "/notifications/v1/swagger", "/openapi", "/openapi/spec.json", "/otj/v1/swagger", "/pages/v1/swagger", "/poweruser/v1/swagger", "/proctoring/v1/swagger", "/report/v1/swagger", "/swagger-ui/index.html", "/swagger-ui/openapi.json", "/swagger.yaml", "/swagger/0.1.0/swagger.json", "/swagger/doc.json", "/swagger/latest/swagger.json", "/swagger/swagger.json", "/swagger/test/swagger.json", "/swagger/ui/index.html", "/swagger/v1/openapiv2.json", "/swagger/v1/swagger.json", "/swagger/v2/swagger.json", "/swagger/v4/swagger.json", "/v1/openapi.json", "/v1/swagger", "/v1/swagger.json", "/swagger/docs/v1", "/swagger/docs/v1.json", "/Api/swagger/docs/v1", "/swagger/v1/swagger.json", "/api/api-docs/swagger.json", "/api/docs/", "/api/docs", "/swagger-ui"}
|
||||
|
||||
var bruteCmd = &cobra.Command{
|
||||
Use: "brute",
|
||||
@@ -54,10 +55,11 @@ var bruteCmd = &cobra.Command{
|
||||
}
|
||||
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, "/")...)
|
||||
allURLs = append(allURLs, makeURLs(target, priorityURLs, "", true)...)
|
||||
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, "", false)...)
|
||||
allURLs = append(allURLs, makeURLs(target, javascriptEndpoints, ".js", false)...)
|
||||
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, ".json", false)...)
|
||||
allURLs = append(allURLs, makeURLs(target, jsonEndpoints, "/", false)...)
|
||||
} else {
|
||||
endpointList, err := os.Open(endpointWordlist)
|
||||
if err != nil {
|
||||
@@ -114,21 +116,31 @@ var bruteCmd = &cobra.Command{
|
||||
}
|
||||
// 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)
|
||||
log.Errorf("\nNo definition file found for:\t%s\n", swaggerURL)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func makeURLs(target string, endpoints []string, fileExtension string) []string {
|
||||
func makeURLs(target string, endpoints []string, fileExtension string, skipPrefix bool) []string {
|
||||
urls := []string{}
|
||||
for _, dir := range prefixDirs {
|
||||
if !skipPrefix {
|
||||
for _, dir := range prefixDirs {
|
||||
for _, endpoint := range endpoints {
|
||||
if dir == "" && endpoint == "" {
|
||||
continue
|
||||
}
|
||||
targetURL := target + dir + endpoint + fileExtension
|
||||
urls = append(urls, targetURL)
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, endpoint := range endpoints {
|
||||
if dir == "" && endpoint == "" {
|
||||
if endpoint == "" {
|
||||
continue
|
||||
}
|
||||
targetURL := target + dir + endpoint + fileExtension
|
||||
targetURL := target + endpoint + fileExtension
|
||||
urls = append(urls, targetURL)
|
||||
|
||||
}
|
||||
}
|
||||
return urls
|
||||
|
||||
+11
-14
@@ -98,22 +98,19 @@ func MakeRequest(client http.Client, method, target string, timeout int64, reqDa
|
||||
continue
|
||||
}
|
||||
|
||||
key := Headers[i][:delimIndex]
|
||||
value := Headers[i][delimIndex+1:]
|
||||
key := strings.TrimSpace(Headers[i][:delimIndex])
|
||||
value := strings.TrimSpace(Headers[i][delimIndex+1:])
|
||||
|
||||
if len(Headers) == 2 {
|
||||
if key == "User-Agent" {
|
||||
UserAgent = value
|
||||
}
|
||||
if key == "Content-Type" {
|
||||
contentType = value
|
||||
}
|
||||
if key == "Accept" {
|
||||
accept = value
|
||||
}
|
||||
} else {
|
||||
req.Header.Set(key, value)
|
||||
if key == "User-Agent" {
|
||||
UserAgent = value
|
||||
}
|
||||
if key == "Content-Type" {
|
||||
contentType = value
|
||||
}
|
||||
if key == "Accept" {
|
||||
accept = value
|
||||
}
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
// User-Agent handling
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ $ sj convert -u https://petstore.swagger.io/v2/swagger.json -o openapi.json`,
|
||||
log.Error("Command not specified. See the --help flag for usage.")
|
||||
}
|
||||
},
|
||||
Version: "2.0.1",
|
||||
Version: "2.2.0",
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
|
||||
+27
-11
@@ -62,7 +62,9 @@ func GenerateRequests(bodyBytes []byte, client http.Client) {
|
||||
// Swagger (v2)
|
||||
host, _ := spec["host"].(string)
|
||||
bp, _ := spec["basePath"].(string)
|
||||
if bp != "" {
|
||||
if bp == "/" {
|
||||
basePath = ""
|
||||
} else if bp != "" {
|
||||
basePath = bp
|
||||
}
|
||||
|
||||
@@ -96,6 +98,8 @@ func GenerateRequests(bodyBytes []byte, client http.Client) {
|
||||
if serverURL, ok := srv["url"].(string); ok {
|
||||
if strings.Contains(serverURL, "://") {
|
||||
apiTarget = serverURL
|
||||
} else if serverURL == "/" {
|
||||
basePath = ""
|
||||
} else {
|
||||
basePath = serverURL
|
||||
apiTarget = u.Scheme + "://" + u.Host
|
||||
@@ -167,7 +171,7 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
pType = schema["type"].(string)
|
||||
// Attempt to prevent version strings from being improperly supplied (i.e. v1)
|
||||
if pType == "string" && pMap["name"] != "version" {
|
||||
pValue = "bishopfox"
|
||||
pValue = testString
|
||||
} else {
|
||||
pValue = "1"
|
||||
}
|
||||
@@ -181,18 +185,31 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
var pValue string
|
||||
if propertyName, ok := properties[propertyItem].(map[string]interface{}); ok {
|
||||
if exampleValue, ok := propertyName["example"]; ok {
|
||||
pValue = exampleValue.(string)
|
||||
switch ex := exampleValue.(type) {
|
||||
case string:
|
||||
pValue = exampleValue.(string)
|
||||
case []interface{}:
|
||||
if len(ex) > 0 {
|
||||
if v, ok := ex[0].(string); ok {
|
||||
pValue = v
|
||||
} else {
|
||||
pValue = "1"
|
||||
}
|
||||
}
|
||||
default:
|
||||
pValue = "1"
|
||||
}
|
||||
} else if propertyType, ok := propertyName["type"].(string); ok {
|
||||
// Attempt to prevent version strings from being improperly supplied (i.e. v1)
|
||||
if propertyType == "string" && propertyName["name"] != "version" {
|
||||
pValue = "bishopfox"
|
||||
pValue = testString
|
||||
} else {
|
||||
pValue = "1"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if strings.Contains(curl, "-d") {
|
||||
if strings.Contains(curl, "-d '") {
|
||||
bodyData += fmt.Sprintf("&%s=%s", propertyItem, pValue)
|
||||
curl = strings.TrimSuffix(curl, "'")
|
||||
curl += fmt.Sprintf("&%s=%s'", propertyItem, pValue)
|
||||
@@ -200,7 +217,6 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
bodyData += fmt.Sprintf("%s=%s", propertyItem, pValue)
|
||||
curl += fmt.Sprintf(" -d '%s=%s'", propertyItem, pValue)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +227,7 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
} else if pType, ok := pMap["type"].(string); ok {
|
||||
// Attempt to prevent version strings from being improperly supplied (i.e. v1)
|
||||
if pType == "string" && pMap["name"] != "version" {
|
||||
pValue = "bishopfox"
|
||||
pValue = testString
|
||||
} else {
|
||||
pValue = "1"
|
||||
}
|
||||
@@ -229,7 +245,7 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
case "header":
|
||||
curl += fmt.Sprintf(" -H \"%s: %s\"", name, pValue)
|
||||
case "body":
|
||||
if strings.Contains(curl, "-d") {
|
||||
if strings.Contains(curl, "-d '") {
|
||||
bodyData += fmt.Sprintf("&%s=%s", name, pValue)
|
||||
curl = strings.TrimSuffix(curl, "'")
|
||||
curl += fmt.Sprintf("&%s=%s'", name, pValue)
|
||||
@@ -270,7 +286,7 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
case "string":
|
||||
// Attempt to prevent version strings from being improperly supplied (i.e. v1)
|
||||
if propertyName["name"] != "version" {
|
||||
pValue = "bishopfox"
|
||||
pValue = testString
|
||||
} else {
|
||||
pValue = "1"
|
||||
}
|
||||
@@ -384,7 +400,7 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
jsonResultsStringArray = append(jsonResultsStringArray, ","+string(result))
|
||||
}
|
||||
if outputFormat == "console" {
|
||||
writeLog(sc, basePath+logURL.Path, strings.ToUpper(method), errorDescriptions[sc], resp[:tempResponsePreviewLength])
|
||||
writeLog(sc, logURL.Path, strings.ToUpper(method), errorDescriptions[sc], resp[:tempResponsePreviewLength])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -394,7 +410,7 @@ func BuildRequestsFromPaths(spec map[string]interface{}, client http.Client) {
|
||||
jsonResultsStringArray = append(jsonResultsStringArray, ","+string(result))
|
||||
}
|
||||
if outputFormat == "console" {
|
||||
writeLog(sc, basePath+logURL.Path, strings.ToUpper(method), errorDescriptions[sc], resp[:tempResponsePreviewLength])
|
||||
writeLog(sc, logURL.Path, strings.ToUpper(method), errorDescriptions[sc], resp[:tempResponsePreviewLength])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user