From a11a3dd2dd5131caa4e681f1920407fbeeb04b71 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Fri, 21 Dec 2018 15:37:36 -0500 Subject: [PATCH] server: add reverse port forwarding restrictions Although reverse port forwarding (sharing client ports with the server) should not generally leak any resources from the server to the client, the facility may nevertheless be abused if the client is able to open a server port which is otherwise meant for some other purpose on the server. (This might happen, for instance, if a service on the server has crashed or becomes somehow disabled, thus freeing the port which would otherwise be occupied by the service.) To mitigate such potential abuse, disable reverse port forwarding by default and introduce server option --reverse to enable it explicitly. Additionally, subject reverse port forwarding remotes to server-side --authfile restrictions (for instance, "^R:0.0.0.0:7000$"). --- README.md | 7 ++++++- example/users.json | 5 +++-- main.go | 10 ++++++++-- server/handler.go | 13 +++++++++++-- server/server.go | 3 +++ 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 73202f4..348d8fa 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,9 @@ $ chisel server --help when connects, their will be verified and then each of the remote addresses will be compared against the list of address regular expressions for a match. Addresses will - always come in the form ":". + always come in the form ":" for normal remotes + and "R::" for reverse port forwarding + remotes. This file will be automatically reloaded on change. --auth, An optional string representing a single user with full access, in the form of . This is equivalent to creating an @@ -117,6 +119,9 @@ $ chisel server --help --socks5, Allows client to access the internal SOCKS5 proxy. See chisel client --help for more information. + --reverse, Allows client to specify reverse port forwarding remotes + in addition to normal remotes. + --pid Generate pid file in current directory -v, Enable verbose logging diff --git a/example/users.json b/example/users.json index 5fd8ab2..23039cc 100644 --- a/example/users.json +++ b/example/users.json @@ -7,6 +7,7 @@ ], "ping:pong": [ "^0.0.0.0:[45]000$", - "^example.com:80$" + "^example.com:80$", + "^R:0.0.0.0:7000$" ] -} \ No newline at end of file +} diff --git a/main.go b/main.go index 9e2c594..f8e8761 100644 --- a/main.go +++ b/main.go @@ -107,8 +107,9 @@ var serverHelp = ` when connects, their will be verified and then each of the remote addresses will be compared against the list of address regular expressions for a match. Addresses will - always come in the form ":". This file will be - automatically reloaded on change. + always come in the form ":" for normal remotes + and "R::" for reverse port forwarding + remotes. This file will be automatically reloaded on change. --auth, An optional string representing a single user with full access, in the form of . This is equivalent to creating an @@ -120,6 +121,9 @@ var serverHelp = ` --socks5, Allows client to access the internal SOCKS5 proxy. See chisel client --help for more information. + + --reverse, Allows client to specify reverse port forwarding remotes + in addition to normal remotes. ` + commonHelp func server(args []string) { @@ -134,6 +138,7 @@ func server(args []string) { auth := flags.String("auth", "", "") proxy := flags.String("proxy", "", "") socks5 := flags.Bool("socks5", false, "") + reverse := flags.Bool("reverse", false, "") pid := flags.Bool("pid", false, "") verbose := flags.Bool("v", false, "") @@ -167,6 +172,7 @@ func server(args []string) { Auth: *auth, Proxy: *proxy, Socks5: *socks5, + Reverse: *reverse, }) if err != nil { log.Fatal(err) diff --git a/server/handler.go b/server/handler.go index 5a976f8..7489ce1 100644 --- a/server/handler.go +++ b/server/handler.go @@ -95,14 +95,23 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, req *http.Request) { clog.Infof("Client version (%s) differs from server version (%s)", v, chshare.BuildVersion) } + for _, r := range c.Remotes { + if r.Reverse && !s.reverseOk { + clog.Debugf("Denied reverse port forwarding request, please enable --reverse") + failed(s.Errorf("Reverse port forwaring not enabled on server")) + return + } + } //if user is provided, ensure they have //access to the desired remotes if user != nil { for _, r := range c.Remotes { + var addr string if r.Reverse { - continue + addr = "R:" + r.LocalHost + ":" + r.LocalPort + } else { + addr = r.RemoteHost + ":" + r.RemotePort } - addr := r.RemoteHost + ":" + r.RemotePort if !user.HasAccess(addr) { failed(s.Errorf("access to '%s' denied", addr)) return diff --git a/server/server.go b/server/server.go index e109d17..08257bd 100644 --- a/server/server.go +++ b/server/server.go @@ -25,6 +25,7 @@ type Config struct { Auth string Proxy string Socks5 bool + Reverse bool } // Server respresent a chisel service @@ -39,6 +40,7 @@ type Server struct { socksServer *socks5.Server sshConfig *ssh.ServerConfig users *chshare.UserIndex + reverseOk bool } var upgrader = websocket.Upgrader{ @@ -53,6 +55,7 @@ func NewServer(config *Config) (*Server, error) { httpServer: chshare.NewHTTPServer(), Logger: chshare.NewLogger("server"), sessions: chshare.Users{}, + reverseOk: config.Reverse, } s.Info = true s.users = chshare.NewUserIndex(s.Logger)