-
Notifications
You must be signed in to change notification settings - Fork 44
develop
为保证项目的结构化性与完整性,建议二次开发时严格遵守开发规范。非规范开发将会被拒绝merge!
| 类型 | 开发规范 |
|---|---|
| 文件&package命名 | 所有文件&package默认遵从小驼峰式命名方式,针对特殊专有名词可以忽略,例如CSRFDetector |
| 日志打印 | 所有核心模块加载时,实例化方法&处理方法必须按格式打印(可参考已有代码),且标识必须保证首字母大写,其余描述信息小写,例如:[Load Filter] load http filter |
| 注释 | 1. 代码通用注释,全部小写 2. 方法、函数,全部采用格式化 |
先clone项目源码,根据食用wiki中将环境搭建好,能跑通即为成功
对项目进行二次开发时,如果需要从config.yaml中读取配置,请查看此部分
- 首先在config.yaml中根据结构app.功能.模块.xxx进行结构化配置【重要】
- 在需要使用的地方,直接调用viper.GETxxx("app.功能.模块.xxx")进行配置读取
通过对Origin接口的实现,可以完成不同方式、不同来源的Origin数据加载
以加载burpsuite文件来作为加载源进行演示
-
先在首先在APIKiller/core/origin/ 创建对应的包目录,例如fileInputOrigin,再创建对应的处理文件

-
创建FileInputOrigin类,实现APIKiller/core/Origin中的接口
type FileInputOrigin struct { path string } func (o *FileInputOrigin) LoadOriginRequest(ctx context.Context, httpItemQueue chan *Origin.TransferItem) { logger.Infoln("[Load Request] load request from file input Origin") //统一标准必须打印日志 // 1. 解析静态文本成 *http.Request 以及 &http.Response 对象 // ... code // 2. 构建httpItem结构体,然后扔进httpItemQueue channel即可 httpItemQueue <- &Origin.TransferItem{ Req: req, Resp: resp, } }
注意:由于body的特殊性,不管以什么形式成功加载了http.Request或者http.Response对象后,必须调用aio.TransformReadCloser(),将request.body和response.body进行类型转换
-
完成类构造后,创建实例化函数,并在main中进行Origin来源逻辑的更改

-
完成上述部分,即可进行调试判断是否成功切换到新的Origin加载方式
通过Filter接口的实现,可以完成对origin加载的流量进行过滤
- 首先在APIKiller/core/filter目录下创建对应的filter 文件(以staticResourceFilter为例)
- 创建StaticResourceFilter类,并实现APIKiller/core/filter/Filter接口
通过对*http.Request对象中属性的判断,来返回FilterBlocked\FilterPass,分别代表过滤当前流量\流量放行,对于过滤掉的流量,将不会进入后续的处理引擎
type StaticResourceFilter struct { forbidenExts []string } func (f *StaticResourceFilter) Filter(ctx context.Context, req *http.Request) bool { logger.Debugln("[Filter] static file filter") // 此处必须统一打印加载debug级别日志 // get request path extension lastIndex := strings.LastIndex(req.URL.Path, ".") if lastIndex == -1 { return FilterPass } ext := req.URL.Path[lastIndex+1:] // filter for _, forbidenExt := range f.forbidenExts { if forbidenExt == ext { return FilterBlocked } } return FilterPass }
- 创建对应的构造器
func NewStaticFileFilter(ctx context.Context) Filter { logger.Infoln("[Load Filter] static file filter") //构造器类必须完成日志打印 return &StaticResourceFilter{ forbidenExts: viper.GetStringSlice("app.filter.staticFileFilter.ext"), } }
- 通过修改main.go将过滤器模块添加到context中,启动项目正常运行,则代表成功添加Filter
通过对Detect接口的实现,可以拓展核心检测引擎集群,扩大检测范围
-
先在APIKiller/core/module/ 创建对应检测模块包目录,例如openRedirectDetector/

-
构建对应的类,并继承Detect接口
type OpenRedirectDetector struct { rawQueryParams []string failFlag []string evilLink string } func (d *OpenRedirectDetector) Detect(ctx context.Context, item *data.DataItem) { logger.Debugln("[Detect] Open-Redirect detect") // 规范格式需求 srcResp := item.SourceResponse srcReq := item.SourceRequest // get raw query parameter list for key, _ := range srcReq.URL.Query() { if slices.Contains(d.rawQueryParams, key) { // clone a new newReq newReq := ahttp.RequestClone(srcReq) // replace value of params in new newReq newReq.URL.Query()[key] = []string{d.evilLink} // do newReq newResp := ahttp.DoRequest(newReq) // judge if d.judge(srcResp, newResp) { item.VulnType = append(item.VulnType, "open-redirect") item.VulnRequest = append(item.VulnRequest, newReq) item.VulnResponse = append(item.VulnResponse, newResp) } return } } }
-
在Detect引擎中写检测规则
- 如果需要对srcRequest进行修改,必须先进行 newReq := ahttp.RequestClone(srcReq) ,复制出一个*http.Request对象
- 如果需要进行http/https发包测试,必须 使用内部提供的 ahttp.DoRequest(newReq) 进行发包探测
- 如果需要修改http 请求报文中的参数,建议使用内部 ModifyURLQueryParameter 、ModifyPostJsonParameter、ModifyPostFormParameter进行参数修改,暂不支持multipart类型body进行参数修改
-
判定引擎逻辑添加
- 这个比较随意,主要看你这边怎么判定是否存在漏洞的
-
检测结果保存。如果检测结果是存在xx漏洞,需要进行数据保存
// judge if d.judge(srcResp, newResp) { item.VulnType = append(item.VulnType, "open-redirect") item.VulnRequest = append(item.VulnRequest, newReq) item.VulnResponse = append(item.VulnResponse, newResp) }
-
构建构造器,并通过修改将检测模块添加到context中
func NewOpenRedirectDetector(ctx context.Context) module.Detecter { if viper.GetInt("app.module.openRedirectDetector.option") == 0 { //规范化,通过在配置中添加option,来调度核心检测模块 return nil } logger.Infoln("[Load Module] Open-Redirect detect module") d := &OpenRedirectDetector{ rawQueryParams: viper.GetStringSlice("app.module.openRedirectDetector.rawQueryParams"), evilLink: "https://www.baidu.com", failFlag: viper.GetStringSlice("app.module.openRedirectDetector.failFlag"), } return d }

-
调试新增检测引擎的检测能力
通过Notify接口的实现,可以实现以不同的方式对漏洞探测结果进行及时通知
-
先在APIKiller/core/notify/ 创建对应notify文件,例如Dingding

-
构建通知类,且其中必须要有 notifyQueue chan *data.DataItem 成员变量
type Dingding struct { webhookUrl string notifyQueue chan *data.DataItem }
-
实现Notify接口,完成发送逻辑的书写。其中NotifyQueue和SetNotifyQueue均采用默认的getter、setter方式即可
func (d *Dingding) NotifyQueue() chan *data.DataItem { return d.notifyQueue } func (d *Dingding) SetNotifyQueue(NotifyQueue chan *data.DataItem) { d.notifyQueue = NotifyQueue } func (d *Dingding) Notify(item *data.DataItem) { logger.Infoln("notify dingding robot") //规范化日志打印 // ... processing logic code }
-
书写对应的构造类,并通过修改main.go将通知模块添加到context中
func NewDingdingNotifer(ctx context.Context) *Dingding { // get config webhookUrl := viper.GetString("app.notifier.Dingding.webhookUrl") // create notifer := &Dingding{webhookUrl: webhookUrl} return notifer }

-
调试成功即代表成功拓展通知方式
为避免扫描时造成过无效流量,可以通过提供的HTTP HOOK机制,对请求流量自定义修改,例如添加header,来区分测试流量和实际流量
【注意】当前由于golang plugin机制特性,暂不支持windows下的流量修改
- HTTP HOOK 样例
package main import ( "fmt" "net/http" ) type RequestHook interface { HookBefore(*http.Request) // hook before initiating http request HookAfter(*http.Request) // hook after finishing http request } type AddHeaderHook struct { } func (a AddHeaderHook) HookBefore(request *http.Request) { fmt.Println("HOOK Before: hhhhhhh") // .... } func (a AddHeaderHook) HookAfter(request *http.Request) { } // Hook this is exported, and this name must be set Hook var Hook AddHeaderHook
【严格按照上面的代码规范,其中最后一行代码,命名必须设置为Hook】
-
生成对应的so链接库
go build -buildmode=plugin APIKillerHookSample.go
$ ls APIKillerHookSample.go APIKillerHookSample.so go.mod
-
将生成的so放置到项目的hooks目录下
$ ls ./hooks APIKillerHookSample.so
-
启动项目即可完成流量更改