返回更新列表
新发布Sep 13, 2026

sj v2.8.2

用于审计暴露的(Swagger/OpenAPI)定义文件中定义的端点的工具。

分享

sj (Swagger Jacker)

sj 是一款命令行工具,旨在通过检查关联的 API 端点是否存在弱身份验证,来协助审计暴露的 Swagger/OpenAPI 定义文件。它还提供用于手动漏洞测试的命令模板。

它通过解析定义文件中的路径、参数和可接受的方法,然后将结果用于以下五个子命令之一:

  • automate - 构造一系列请求并分析响应的状态码。
  • prepare - 生成用于手动测试的命令列表。
  • endpoints - 生成原始 API 路由列表。路径值不会替换为测试数据。
  • brute - 向目标发送一系列请求,以基于常用文件路径查找操作定义。
  • convert - 将定义文件从 v2 转换为 v3。

构建

要从源代码编译,请确保已安装 Go 版本 >= 1.22.5,并在仓库内运行 go build:

$ git clone https://github.com/BishopFox/sj.git
$ cd sj/
$ go build .

安装

要安装该工具的最新版本,请运行:

$ go install github.com/BishopFox/sj@latest

# Note: you may also need to place the path to your Go binaries within your PATH environment variable:
$ export PATH=$PATH:~/go/bin

用法

使用 automate 命令向每个已定义的端点发送一系列请求,并分析每个响应的状态码。

$ sj automate -u https://petstore.swagger.io/v2/swagger.json -qi -p http://127.0.0.1:8080               

Gathering API details.
⚠  POST     500  /v2/pet
⚠  PUT      500  /v2/pet
✓  GET      200  /v2/pet/findByStatus
✓  GET      200  /v2/pet/findByTags
✓  GET      200  /v2/pet/1
✓  POST     200  /v2/pet/1
⚠  POST     N/A  /v2/pet/1/uploadImage
✓  GET      200  /v2/store/inventory
⚠  POST     N/A  /v2/store/order
⚠  GET      N/A  /v2/store/order/1
✓  POST     200  /v2/user
⚠  POST     N/A  /v2/user/createWithArray
⚠  POST     N/A  /v2/user/createWithList
✓  GET      200  /v2/user/login
✓  GET      200  /v2/user/logout
✓  GET      200  /v2/user/bishopfox
✓  PUT      200  /v2/user/bishopfox

你可以使用 --replay-proxy 标志,通过单独的代理(例如 Burp Suite)重放匹配的请求。这样,你可以将所有流量路由到一个代理(或直连),同时只将感兴趣的结果发送到你的拦截代理:

$ sj automate -u https://petstore.swagger.io/v2/swagger.json -qi --replay-proxy http://127.0.0.1:8080

你还可以将其与 --proxy 结合使用,将扫描流量路由到不同的代理,同时将匹配项重放到 Burp:

$ sj automate -u https://petstore.swagger.io/v2/swagger.json -qi -p http://proxy:9090 --replay-proxy http://127.0.0.1:8080

你还可以请求详细输出,以查看部分(或完整)响应:

$ sj automate -u https://petstore.swagger.io/v2/swagger.json -qi -p http://127.0.0.1:8080 -v           

Gathering API details.
⚠  POST     500  /v2/pet
   {"code":500,"type":"unknown","message":"something 
⚠  PUT      500  /v2/pet
   {"code":500,"type":"unknown","message":"something 
✓  GET      200  /v2/pet/findByStatus
   []
✓  GET      200  /v2/pet/findByTags
   []
✓  GET      200  /v2/pet/1
   {"id":1,"category":{"id":1,"name":"cat"},"name":"d
✓  POST     200  /v2/pet/1
   {"code":200,"type":"unknown","message":"1"}
⚠  POST     N/A  /v2/pet/1/uploadImage
✓  GET      200  /v2/store/inventory
   {"sold":115,"bishopfox":1,"SOLD":1,"string":224,"d
⚠  POST     N/A  /v2/store/order
⚠  GET      N/A  /v2/store/order/1
✓  POST     200  /v2/user
   {"code":200,"type":"unknown","message":"1"}
⚠  POST     N/A  /v2/user/createWithArray
⚠  POST     N/A  /v2/user/createWithList
✓  GET      200  /v2/user/login
   {"code":200,"type":"unknown","message":"logged in 
✓  GET      200  /v2/user/logout
   {"code":200,"type":"unknown","message":"ok"}
✓  GET      200  /v2/user/bishopfox
   {"id":1,"username":"bishopfox","firstName":"bishop
✓  PUT      200  /v2/user/bishopfox
   {"code":200,"type":"unknown","message":"1"}

使用 prepare 命令准备用于手动测试的命令列表。目前支持 curl 和 sqlmap。你可能需要对这些命令稍作修改。

$ sj prepare -u https://petstore.swagger.io/v2/swagger.json -qi -p http://127.0.0.1:8080

$ curl -X POST "https://petstore.swagger.io/v2/pet" -H 'Content-Type: application/json' -d '{"category":{"id":1,"name":"bishopfox"},"id":1,"name":"doggie","photoUrls":"https://bishopfox.com","status":"available","tags":[{"id":1,"name":"bishopfox"}]}'
$ curl -X PUT "https://petstore.swagger.io/v2/pet" -H 'Content-Type: application/json' -d '{"category":{"id":1,"name":"bishopfox"},"id":1,"name":"doggie","photoUrls":"https://bishopfox.com","status":"available","tags":[{"id":1,"name":"bishopfox"}]}'
$ curl -X GET "https://petstore.swagger.io/v2/pet/findByStatus?status=1"
$ curl -X GET "https://petstore.swagger.io/v2/pet/findByTags?tags=1"
$ curl -X GET "https://petstore.swagger.io/v2/pet/1"
$ curl -X POST "https://petstore.swagger.io/v2/pet/1" -H 'Content-Type: application/x-www-form-urlencoded' -d 'name=bishopfox&status=bishopfox'
$ curl -X POST "https://petstore.swagger.io/v2/pet/1/uploadImage" -H 'Content-Type: application/x-www-form-urlencoded' -d 'additionalMetadata=bishopfox&file=1'
$ curl -X GET "https://petstore.swagger.io/v2/store/inventory"
$ curl -X POST "https://petstore.swagger.io/v2/store/order" -H 'Content-Type: application/json' -d '{"complete":true,"id":1,"petId":1,"quantity":1,"shipDate":"1990-01-01","status":"placed"}'
$ curl -X GET "https://petstore.swagger.io/v2/store/order/1"
$ curl -X POST "https://petstore.swagger.io/v2/user" -H 'Content-Type: application/json' -d '{"email":"[email protected]","firstName":"bishopfox","id":1,"lastName":"bishopfox","password":"bishopfox","phone":"bishopfox","userStatus":1,"username":"bishopfox"}'
$ curl -X POST "https://petstore.swagger.io/v2/user/createWithArray" -H 'Content-Type: application/json' -d '[{"email":"[email protected]","firstName":"bishopfox","id":1,"lastName":"bishopfox","password":"bishopfox","phone":"bishopfox","userStatus":1,"username":"bishopfox"}]'
$ curl -X POST "https://petstore.swagger.io/v2/user/createWithList" -H 'Content-Type: application/json' -d '[{"email":"[email protected]","firstName":"bishopfox","id":1,"lastName":"bishopfox","password":"bishopfox","phone":"bishopfox","userStatus":1,"username":"bishopfox"}]'
$ curl -X GET "https://petstore.swagger.io/v2/user/login?username=bishopfox&password=bishopfox"
$ curl -X GET "https://petstore.swagger.io/v2/user/logout"
$ curl -X GET "https://petstore.swagger.io/v2/user/bishopfox"
$ curl -X PUT "https://petstore.swagger.io/v2/user/bishopfox" -H 'Content-Type: application/json' -d '{"email":"[email protected]","firstName":"bishopfox","id":1,"lastName":"bishopfox","password":"bishopfox","phone":"bishopfox","userStatus":1,"username":"bishopfox"}'

多个请求正文内容类型

一个操作通常会在多个内容类型下声明相同的正文。默认情况下,sj 会发送最有可能被接受的那个,优先选择 application/json,然后是 application/x-www-form-urlencoded,再然后是 multipart/form-data,最后是 XML。该选择是确定性的,因此重复运行会产生相同的命令。

由于 JSON 解析器和 XML 解析器是不同的攻击面,--all-content-types 会发送所有已声明的类型,而不仅仅是首选的那个:

$ sj prepare -l spec.yaml -T https://api.example.com -q --all-content-types

$ curl -X POST "https://api.example.com/multi" -H 'Content-Type: application/json' -d '{"name":"bishopfox","size":1}'
$ curl -X POST "https://api.example.com/multi" -H 'Content-Type: application/x-www-form-urlencoded' -d 'name=bishopfox&size=1'
$ curl -X POST "https://api.example.com/multi" -F 'name=bishopfox' -F 'size=1'
$ curl -X POST "https://api.example.com/multi" -H 'Content-Type: application/xml' -d '<name>bishopfox</name><size>1</size>'

请注意,这会使发送到目标的请求数量成倍增加,并且 --replay-proxy 会接收到其中的每一个请求。

要测试单个特定的编码,请使用 -H 传入它。当操作声明了该类型时,sj 会在该类型下发送匹配的正文:

$ sj prepare -l spec.yaml -T https://api.example.com -q -H "Content-Type: application/xml"

当操作未声明该类型时,sj 会发出警告,并仍然在你的标头下发送首选正文,这对于解析器差异测试很有用。sj 无法为其编码正文的内容类型(application/octet-stream、text/plain)会被跳过,而不是在误导性的标头下作为空正文发送。

使用 endpoints 命令从提供的定义文件生成原始端点列表。

$ sj endpoints -u https://petstore.swagger.io/v2/swagger.json -qi -p http://127.0.0.1:8080

INFO[0000] Gathering endpoints.
                        
/v2/store/inventory
/v2/store/order/{orderId}
/v2/pet
/v2/pet
/v2/store/order
/v2/user/createWithList
/v2/pet/{petId}/uploadImage
/v2/pet/findByTags
/v2/pet/{petId}
/v2/pet/{petId}
/v2/user/{username}
/v2/user/{username}
/v2/user/createWithArray
/v2/pet/findByStatus
/v2/user/login
/v2/user/logout
/v2/user

使用 brute 命令发送一系列请求,尝试在目标上查找定义文件。

分类