I want to tunnel a sub-command through a connection by listening to a port, running the sub-command (to connect to that port), and then forwarding the data through the connection:
package main
import (
"fmt"
"net"
"os"
"os/exec"
)
func main() {
ln, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: localhost})
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer ln.Close()
port := ln.Addr().(*net.TCPAddr).Port
cmd := exec.Command(
"git",
"clone",
fmt.Sprintf("git://127.0.0.1:%d/project.git", port),
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer cmd.Process.Kill()
errs := make(chan error, 1)
go func() {
errs <- cmd.Wait()
}()
conns := make(chan net.Conn, 1)
go func() {
conn, err := ln.Accept()
if err == nil {
conns <- conn
} else {
fmt.Println(err)
errs <- err
}
}()
select {
case err := <-errs:
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
case conn := <-conns:
defer conn.Close()
// TODO Tunnel data from `conn` through another connection.
}
fmt.Println("done.")
}
var localhost = net.IPv4(127, 0, 0, 1)
However, there's a race here between the time that we start listening and the time when the sub-command actually connects to the listener, where another process can connect to the listener. I believe this race could be exploited by an attacker to communicate with the process at the other end of the connection and achieve results that would otherwise require privilege escalation to perform (example attacks that require special permissions are replacing the git
command with a malicious program or simply reading the contents of the cloned directory, in this instance).
Should this be a concern? If so, is there a way it can be prevented? Though the question is asked using Go as an example, answers and comments in any language are welcome.
Yes it is a concern. It can be prevented by using some form of authentication so that your server only allows connections from legitimate clients.