# 开发文档

# 0x01 技术栈

需求 实现
命令行工具 github.com/urfave/cli/v2
加载配置文件 github.com/spf13/viper
服务端框架 github.com/gin-gonic/gin
身份认证 jwt github.com/dgrijalva/jwt-go
orm gorm.io/gorm
规则表达式 github.com/google/cel-go/cel
sqlite数据库驱动 gorm.io/driver/sqlite
mysql数据库驱动 gorm.io/driver/mysql
日志 go.uber.org/zap
http请求 github.com/valyala/fasthttp
限速 golang.org/x/time/rate
并发控制 sync.WaitGroup
swag github.com/swaggo/gin-swagger
前端 antd (opens new window)
静态资源打包至go二进制 github.com/elazarl/go-bindata-assetfs

# 0x02 项目布局

pocassist 遵循 Golang 应⽤程序项⽬的基本布局 (opens new window)

在二次开发前建议先阅读 Go项目标准布局 (opens new window)

# 0x03 cmd

/cmd 是项目入口

  • InitAll方法在项目启动时最先执行:加载配置以及各个包的初始化工作
  • HotConf方法通过viper实现了配置文件实时监控,配置文件发生变更之后会重新InitAll,实现热加载

目录结构

└── pocassist.go	入口函数 加载全局配置 初始化
1

# 0x04 api

/api 是 api 框架,基于 gin 开发。

为方便开发过程测试接口,源码中每个接口均编写了详细的注释。同时,当config.yaml 中 run_mode: "debug"(debug模式)下将开启swagger。访问:

http://127.0.0.1:1231/swagger/index.html

目录结构

├── middleware
│   └── jwt
│       └── jwt.go				jwt身份验证
├── msg
│   └── msg.go					定义api数据交互格式
└── routers
    ├── route.go				注册路由
    ├── ui.go					加载go-bindata-assetfs打包的静态页面
    └── v1
        ├── auth
        │   └── auth.go			登录/登出/改密/个人详情
        ├── plugin
        │   └── plugin.go		poc 增/删/改/查/列表/详情/运行(单个)
        ├── scan
        │   ├── result
        │   │   └── result.go	poc批量运行结果
        │   ├── scan
        │   │   └── scan.go		poc批量运行。支持定义三种目标:单个url / 单个请求报文(文件形式上传) / url列表(文件形式上传)
        │   └── task
        │       └── task.go		任务状态
        ├── vulnerability
        │   └── vulnerability.go	漏洞详情 增/删/改/查/列表/详情
        └── webapp
            └── webapp.go		漏洞详情中的”影响组件“ 增/列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 0x05 pkg

/pkg 是整个项目的工具包。其中包含:

  • cel表达式实现:cel变量注入、cel方法注入
  • 配置文件:配置文件的加载、默认配置文件的生成
  • 数据库:orm model
  • 文件操作
├── cel
│   ├── cel.go				cel表达式:注入函数、表达式计算
│   ├── proto
│   │   ├── http.pb.go		注入到cel中的类型(go-cel要求必须为protobuf格式)
│   │   └── http.proto		生成http.pb.go的原始proto文件
│   └── reverse
│       └── reverse.go		实现cel中的Reverse(反连平台,dnslog/weblog)变量和方法
├── conf
│   ├── config.go			定义config结构体,Setup方法将加载配置文件至GlobalConfig。当前目录没有配置文件时,将创建默认的配置文件
│   └── default.go			默认配置文件内容
├── db
│   ├── auth.go				身份认证相关的数据库操作
│   ├── conn.go				数据库连接,当配置了sqlite时优先使用sqlite
│   ├── plugin.go			poc相关的数据库操作
│   ├── scanResult.go		扫描结果相关的数据库操作
│   ├── scanTask.go			扫描任务状态相关的数据库操作
│   ├── vulnerability.go	漏洞描述相关的数据库操作
│   └── webapp.go			漏洞描述中所属组件相关的数据库操作
├── file
│   └── file.go				处理文件:处理批量扫描时上传的文件
├── logging
│   └── log.go				处理日志
└── util
    ├── jwt.go				生成和解析jwt token
    ├── rand.go				随机数 随机字符
    ├── request.go			fasthttp请求与响应
    ├── result.go			定义poc检测结果格式
    ├── tcp.go				tcp请求与响应
    └── util.go				util初始化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

如何生成protobuf:

go get github.com/golang/protobuf
cd /pkg/cel/proto
protoc --go_out=. http.proto
1
2
3

# 0x06 poc

image-20210612201813017

├── rule
│   ├── handle.go			  单个poc的流程控制
│   ├── controller.go		cel表达式规则运行controller
│   ├── run.go			    单个poc运行逻辑
│   ├── parallel.go			并发控制
│   ├── rule.go			    poc model 以及 set/search处理
│   ├── cel.go				  cel控制器
│   └── request.go			原始请求/构造的请求控制器
└── scripts
    ├── poc-go-memcached-unauth.go		demo脚本1
    ├── poc-go-tomcat-weak-pass.go		demo脚本2
    └── scripts.go						脚本注册、脚本调度

1
2
3
4
5
6
7
8
9
10
11
12
13

面向web的 poc 框架占用的内存资源绝大多数来源于开辟请求响应。目前常见的 poc 框架并发都是在同时运行poc数量控制的。这里就会产生几个问题:

  • 单纯控制 poc 并发,在每个 poc 内部是面向过程的。在一个 poc 结束之前,这个 poc 所占用的资源不会被立即释放,就可能造成资源浪费。例如:一个 poc 通常会发多个请求,而且要对每个请求的响应进行解析。每一个请求和响应在使用之后都进行初始化,下一个请求/响应复用这块内存,是不是就降低了内存开销。
  • 单纯控制 poc 并发,占用资源的总量是无法预估的,容易造成崩溃。
  • 我们知道发送一个请求是很快的,而解析响应的开销要多的多。实际上解析响应时,已经不再需要request对象了,这里也会有资源浪费。

go 语言中有一个神奇的对象池 sync.Pool。神奇的地方在于,一开始这个池子会初始化一些对象供你使用,如果不够了呢,自己会通过new产生一些,当你放回去了之后这些对象会被别人进行复用。

所以:

pocassist 把使用频率高的对象(如poc对象、请求、响应、响应处理等)均使用对象池 sync.Pool 进行管理,大幅度减少对象的创建和回收的时间,内存使用效率极大提高

TIP

poc/rule/controller.go 将controller 用 sync.Pool管理

pkg/util/requests 将 request / response / 响应处理 用 sync.Pool管理