Compare commits

..
8 Commits
5 changed files with 63 additions and 36 deletions

No files matched your search

+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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])
}
}