CVE-2023-37265: Missing Authentication for Critical Function (CWE-306)
value: CasaOS is an open-source Personal Cloud system. Due to a lack of IP address verification an unauthenticated attackers can execute arbitrary commands as `root` on CasaOS instances. The problem was addressed by improving the detection of client IP addresses in `391dd7f`. This patch is part of CasaOS 0.4.4. Users should upgrade to CasaOS 0.4.4. If they can't, they should temporarily restrict access to CasaOS to untrusted users, for instance by not exposing it publicly. 
CWE description: The product does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.
CVSS v3 base score: 9.8
Published: 2023-07-17T21:15Z
Repository: https://github.com/IceWhaleTech/CasaOS-Gateway
Language: Go
Files changed: route/gateway_route.go
Commit date: 2023-07-06 20:59:02 -0400
Commit message: Merge pull request from GHSA-vjh7-5r6x-xh6g

* fix:Incorrect identification of source IP addresses

* feat: support reverse proxy

* stash

* stash

* fix: the bug

* fix: the bug

* fix: the bug

* fix: the bug

* delete unused comment

* refacotr the proccess

* add comment to notice user to config correct proxy setting

* fix:some problems

* refactor the ip

* Update gateway_route.go
Diff: diff --git a/route/gateway_route.go b/route/gateway_route.go
index 5aed2bd..cc576bd 100644
--- a/route/gateway_route.go
+++ b/route/gateway_route.go
@@ -1,9 +1,10 @@
 package route
 
 import (
 	"net/http"
+	"strings"
 
 	"github.com/IceWhaleTech/CasaOS-Common/utils/logger"
 	"github.com/IceWhaleTech/CasaOS-Gateway/service"
 	"go.uber.org/zap"
 )
@@ -16,10 +17,42 @@ func NewGatewayRoute(management *service.Management) *GatewayRoute {
 	return &GatewayRoute{
 		management: management,
 	}
 }
 
+// the function is to ensure the request source IP is correct.
+func rewriteRequestSourceIP(r *http.Request) {
+	// we may receive two kinds of requests. a request from reverse proxy. a request from client.
+
+	// in reverse proxy, X-Forwarded-For will like
+	// `X-Forwarded-For:[192.168.6.102]`(normal)
+	// `X-Forwarded-For:[::1, 192.168.6.102]`(hacked) Note: the ::1 is inject by attacker.
+	// `X-Forwarded-For:[::1]`(normal or hacked) local request. But it from browser have JWT. So we can and need to verify it
+	// `X-Forwarded-For:[::1,::1]`(normal or hacked) attacker can build the request to bypass the verification.
+	// But in the case. the remoteAddress should be the real ip. So we can use remoteAddress to verify it.
+
+	ipList := strings.Split(r.Header.Get("X-Forwarded-For"), ",")
+
+	r.Header.Del("X-Forwarded-For")
+	r.Header.Del("X-Real-IP")
+
+	// Note: the X-Forwarded-For depend the correct config from reverse proxy.
+	// otherwise the X-Forwarded-For may be empty.
+	remoteIP := r.RemoteAddr[:strings.LastIndex(r.RemoteAddr, ":")]
+	if len(ipList) > 0 && (remoteIP == "127.0.0.1" || remoteIP == "::1") {
+		// to process the request from reverse proxy
+
+		// in reverse proxy, X-Forwarded-For will container multiple IPs.
+		// if the request is from reverse proxy, the r.RemoteAddr will be 127.0.0.1.
+		// So we need get ip from X-Forwarded-For
+		r.Header.Add("X-Forwarded-For", ipList[len(ipList)-1])
+	}
+	// to process the request from client.
+	// the gateway will add the X-Forwarded-For to request header.
+	// So we didn't need to add it.
+}
+
 func (g *GatewayRoute) GetRoute() *http.ServeMux {
 	gatewayMux := http.NewServeMux()
 	gatewayMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 		if r.URL.Path == "/ping" {
 			w.WriteHeader(http.StatusOK)
@@ -34,10 +67,14 @@ func (g *GatewayRoute) GetRoute() *http.ServeMux {
 		if proxy == nil {
 			w.WriteHeader(http.StatusNotFound)
 			return
 		}
 
+		// to fix https://github.com/IceWhaleTech/CasaOS/security/advisories/GHSA-32h8-rgcj-2g3c#event-102885
+		// API V1 and V2 both read ip from request header. So the fix is effective for v1 and v2.
+		rewriteRequestSourceIP(r)
+
 		proxy.ServeHTTP(w, r)
 	})
 
 	return gatewayMux
 }

Fixed code: 	"strings"
// the function is to ensure the request source IP is correct.
func rewriteRequestSourceIP(r *http.Request) {
	// we may receive two kinds of requests. a request from reverse proxy. a request from client.

	// in reverse proxy, X-Forwarded-For will like
	// `X-Forwarded-For:[192.168.6.102]`(normal)
	// `X-Forwarded-For:[::1, 192.168.6.102]`(hacked) Note: the ::1 is inject by attacker.
	// `X-Forwarded-For:[::1]`(normal or hacked) local request. But it from browser have JWT. So we can and need to verify it
	// `X-Forwarded-For:[::1,::1]`(normal or hacked) attacker can build the request to bypass the verification.
	// But in the case. the remoteAddress should be the real ip. So we can use remoteAddress to verify it.

	ipList := strings.Split(r.Header.Get("X-Forwarded-For"), ",")

	r.Header.Del("X-Forwarded-For")
	r.Header.Del("X-Real-IP")

	// Note: the X-Forwarded-For depend the correct config from reverse proxy.
	// otherwise the X-Forwarded-For may be empty.
	remoteIP := r.RemoteAddr[:strings.LastIndex(r.RemoteAddr, ":")]
	if len(ipList) > 0 && (remoteIP == "127.0.0.1" || remoteIP == "::1") {
		// to process the request from reverse proxy

		// in reverse proxy, X-Forwarded-For will container multiple IPs.
		// if the request is from reverse proxy, the r.RemoteAddr will be 127.0.0.1.
		// So we need get ip from X-Forwarded-For
		r.Header.Add("X-Forwarded-For", ipList[len(ipList)-1])
	}
	// to process the request from client.
	// the gateway will add the X-Forwarded-For to request header.
	// So we didn't need to add it.
}

		// to fix https://github.com/IceWhaleTech/CasaOS/security/advisories/GHSA-32h8-rgcj-2g3c#event-102885
		// API V1 and V2 both read ip from request header. So the fix is effective for v1 and v2.
		rewriteRequestSourceIP(r)