func OpenStream(conn ssh.Conn, remote string) (io.ReadWriteCloser, error) { stream, reqs, err := conn.OpenChannel("chisel", []byte(remote)) if err != nil { return nil, err } go ssh.DiscardRequests(reqs) return stream, nil }
func ProxyChannels(logger lager.Logger, conn ssh.Conn, channels <-chan ssh.NewChannel) { logger = logger.Session("proxy-channels") logger.Info("started") defer logger.Info("completed") defer conn.Close() for newChannel := range channels { logger.Info("new-channel", lager.Data{ "channelType": newChannel.ChannelType(), "extraData": newChannel.ExtraData(), }) targetChan, targetReqs, err := conn.OpenChannel(newChannel.ChannelType(), newChannel.ExtraData()) if err != nil { logger.Error("failed-to-open-channel", err) if openErr, ok := err.(*ssh.OpenChannelError); ok { newChannel.Reject(openErr.Reason, openErr.Message) } else { newChannel.Reject(ssh.ConnectionFailed, err.Error()) } continue } sourceChan, sourceReqs, err := newChannel.Accept() if err != nil { targetChan.Close() continue } toTargetLogger := logger.Session("to-target") toSourceLogger := logger.Session("to-source") go func() { helpers.Copy(toTargetLogger, nil, targetChan, sourceChan) targetChan.CloseWrite() }() go func() { helpers.Copy(toSourceLogger, nil, sourceChan, targetChan) sourceChan.CloseWrite() }() go ProxyRequests(toTargetLogger, newChannel.ChannelType(), sourceReqs, targetChan) go ProxyRequests(toSourceLogger, newChannel.ChannelType(), targetReqs, sourceChan) } }
/* handleChan handles a single channel request from sc, proxying it to the client. General logging messages will be written to lg, and channel-specific data and messages will be written to a new file in ldir. */ func handleChan( nc ssh.NewChannel, client ssh.Conn, ldir string, lg *log.Logger, direction string, ) { /* Log the channel request */ crl := fmt.Sprintf( "Type:%q Data:%q Direction:%q", nc.ChannelType(), nc.ExtraData(), direction, ) /* Pass to server */ cc, creqs, err := client.OpenChannel( nc.ChannelType(), nc.ExtraData(), ) if nil != err { go rejectChannel(err, crl, nc, lg) return } defer cc.Close() /* Make channel to attacker, defer close */ ac, areqs, err := nc.Accept() if nil != err { lg.Printf( "Unable to accept channel request of type %q: %v", nc.ChannelType(), err, ) return } defer ac.Close() /* Channel worked, make a logger for it */ clg, lf, clgn, err := logChannel(ldir, nc) if nil != err { lg.Printf( "Unable to open log file for channel of type %q:%v", nc.ChannelType(), err, ) return } defer lf.Close() clg.Printf("Start of log") /* Proxy requests on channels */ go handleReqs(areqs, Channel{oc: cc}, clg, "attacker->server") go handleReqs(creqs, Channel{oc: ac}, clg, "server->attacker") /* Log the channel */ lg.Printf("Channel %s Log:%q", crl, clgn) /* Proxy comms */ wg := make(chan int, 4) go ProxyChannel( ac, cc, clg, "server->attacker", wg, 1, ) go ProxyChannel( cc, ac, clg, "attacker->server", wg, 1, ) go ProxyChannel( cc.Stderr(), ac.Stderr(), clg, "attacker-(err)->server", wg, 0, ) go ProxyChannel( ac.Stderr(), cc.Stderr(), clg, "server-(err)->attacker", wg, 0, ) sum := 0 for i := range wg { sum += i if 2 <= sum { break } } /* TODO: Proxy comms */ }
/* handleChannel proxies a channel request command or shell to the ssh connection sc. */ func handleNewChannel(cr ssh.NewChannel, sc ssh.Conn, info string) { log.Printf( "%v Type:%q Data:%q NewChannel", info, cr.ChannelType(), cr.ExtraData(), ) /* Make the same request to the other side */ och, oreqs, err := sc.OpenChannel(cr.ChannelType(), cr.ExtraData()) if nil != err { /* If we can't log it, and reject the client */ oe, ok := err.(*ssh.OpenChannelError) var ( reason ssh.RejectionReason message string ) if !ok { log.Printf( "%v Type:%q Data:%q Unable to open channel: "+ "%v", info, cr.ChannelType(), cr.ExtraData(), err, ) reason = ssh.ConnectionFailed message = "Fail" message = err.Error() } else { log.Printf( "%v Type:%q Data:%q Reason:%q Message:%q "+ "Unable to open channel", info, cr.ChannelType(), cr.ExtraData(), oe.Reason.String(), oe.Message, ) reason = oe.Reason message = oe.Message } if err := cr.Reject(reason, message); nil != err { log.Printf( "%v Unable to pass on channel rejecton "+ "request: %v", info, err, ) } return } defer och.Close() /* Accept the channel request from the requestor */ rch, rreqs, err := cr.Accept() if nil != err { log.Printf( "%v Unable to accept request for a channel of type "+ "%q: %v", cr.ChannelType(), info, err, ) return } defer rch.Close() /* Handle passing requests between channels */ hcrinfo := fmt.Sprintf(" %v ChannelType:%q", info, cr.ChannelType()) go handleChannelRequests( rreqs, och, hcrinfo+" ReqDir:AsDirection", ) go handleChannelRequests( oreqs, rch, hcrinfo+" ReqDir:AgainstDirection", ) log.Printf( "%v Type:%q Data:%q Opened", info, cr.ChannelType(), cr.ExtraData(), ) /* For now, print out read data */ done := make(chan struct{}, 4) go copyOut(och, rch, done) go copyOut(rch, och, done) go copyOut(och.Stderr(), rch.Stderr(), done) go copyOut(rch.Stderr(), och.Stderr(), done) /* Wait for a pipe to break */ <-done fmt.Printf("\nDone.\n") }