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$").
This commit is contained in:
Eric Sunshine
2018-12-21 15:37:36 -05:00
parent 8724c90273
commit a11a3dd2dd
5 changed files with 31 additions and 7 deletions
+6 -1
View File
@@ -104,7 +104,9 @@ $ chisel server --help
when <user> connects, their <pass> 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 "<host/ip>:<port>".
always come in the form "<remote-host>:<remote-port>" for normal remotes
and "R:<local-interface>:<local-port>" 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 <user:pass>. 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
+3 -2
View File
@@ -7,6 +7,7 @@
],
"ping:pong": [
"^0.0.0.0:[45]000$",
"^example.com:80$"
"^example.com:80$",
"^R:0.0.0.0:7000$"
]
}
}
+8 -2
View File
@@ -107,8 +107,9 @@ var serverHelp = `
when <user> connects, their <pass> 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 "<host/ip>:<port>". This file will be
automatically reloaded on change.
always come in the form "<remote-host>:<remote-port>" for normal remotes
and "R:<local-interface>:<local-port>" 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 <user:pass>. 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)
+11 -2
View File
@@ -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
+3
View File
@@ -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)