Пример #1
0
func (beacon *Beacon) keepAlive(conn ssh.Conn) (<-chan error, chan<- struct{}) {
	logger := beacon.Logger.Session("keepalive")

	errs := make(chan error, 1)

	kas := time.NewTicker(5 * time.Second)
	cancel := make(chan struct{})

	go func() {
		for {
			// ignore reply; server may just not have handled it, since there's no
			// standard keepalive request name

			_, _, err := conn.SendRequest("keepalive", true, []byte("sup"))
			if err != nil {
				logger.Error("failed", err)
				errs <- err
				return
			}

			logger.Debug("ok")

			select {
			case <-kas.C:
			case <-cancel:
				errs <- nil
				return
			}
		}
	}()

	return errs, cancel
}
Пример #2
0
//DialClient returns two channels where one returns a ssh.Client and the other and error
func DialClient(dial, expire time.Duration, ip string, conf *ssh.ClientConfig, retry <-chan struct{}) (*ssh.Client, error) {

	flux.Report(nil, fmt.Sprintf("MakeDial for %s for dailing at %+s and expiring in %+s", conf.User, dial, expire))

	cons := make(chan *ssh.Client)
	errs := make(chan error)

	var con net.Conn
	var sc ssh.Conn
	var chans <-chan ssh.NewChannel
	var req <-chan *ssh.Request
	var err error

	flux.GoDefer("MakeDial", func() {
		con, err = net.DialTimeout("tcp", ip, dial)

		if err != nil {
			flux.Report(err, fmt.Sprintf("MakeDial:Before for %s net.DailTimeout", ip))
			errs <- err
			return
		}

		sc, chans, req, err = ssh.NewClientConn(con, ip, conf)

		if err != nil {
			flux.Report(err, fmt.Sprintf("MakeDial:After for %s ssh.NewClientConn", ip))
			errs <- err
			return
		}

		flux.Report(nil, fmt.Sprintf("MakeDial initiating NewClient for %s", ip))
		cons <- ssh.NewClient(sc, chans, req)
		return
	})

	expiration := threshold(expire)

	go func() {
		for _ = range retry {
			expiration = threshold(expire)
		}
	}()

	select {
	case err := <-errs:
		flux.Report(err, fmt.Sprintf("NewClient Ending!"))
		return nil, err
	case som := <-cons:
		flux.Report(nil, fmt.Sprintf("NewClient Created!"))
		expiration = nil
		return som, nil
	case <-expiration:
		flux.Report(nil, fmt.Sprintf("MakeDial Expired for %s!", ip))
		defer con.Close()
		if sc != nil {
			sc.Close()
		}
		return nil, ErrTimeout
	}
}
Пример #3
0
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
}
Пример #4
0
func keepalive(conn ssh.Conn, ticker *time.Ticker, stopCh chan struct{}) {
	for {
		select {
		case <-ticker.C:
			_, _, _ = conn.SendRequest("*****@*****.**", true, nil)
		case <-stopCh:
			ticker.Stop()
			return
		}
	}
}
Пример #5
0
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)
	}
}
Пример #6
0
/* handleConnRequests handles proxying requests read from reqs to the SSH
connection sc.  info is used for logging */
func handleConnRequests(
	reqs <-chan *ssh.Request,
	c ssh.Conn,
	info string,
) {
	for r := range reqs {
		go handleRequest(
			r,
			func(
				name string,
				wantReply bool,
				payload []byte,
			) (bool, []byte, error) {
				return c.SendRequest(name, wantReply, payload)
			},
			func() error { return c.Close() },
			info,
		)
	}
}
Пример #7
0
func ProxyGlobalRequests(logger lager.Logger, conn ssh.Conn, reqs <-chan *ssh.Request) {
	logger = logger.Session("proxy-global-requests")

	logger.Info("started")
	defer logger.Info("completed")

	for req := range reqs {
		logger.Info("request", lager.Data{
			"type":      req.Type,
			"wantReply": req.WantReply,
			"payload":   req.Payload,
		})
		success, reply, err := conn.SendRequest(req.Type, req.WantReply, req.Payload)
		if err != nil {
			logger.Error("send-request-failed", err)
			continue
		}

		if req.WantReply {
			req.Reply(success, reply)
		}
	}
}
Пример #8
0
func (c *comm) reconnect() (err error) {
	if c.conn != nil {
		c.conn.Close()
	}

	// Set the conn and client to nil since we'll recreate it
	c.conn = nil
	c.client = nil

	log.Printf("reconnecting to TCP connection for SSH")
	c.conn, err = c.config.Connection()
	if err != nil {
		// Explicitly set this to the REAL nil. Connection() can return
		// a nil implementation of net.Conn which will make the
		// "if c.conn == nil" check fail above. Read here for more information
		// on this psychotic language feature:
		//
		// http://golang.org/doc/faq#nil_error
		c.conn = nil

		log.Printf("reconnection error: %s", err)
		return
	}

	log.Printf("handshaking with SSH")

	// Default timeout to 1 minute if it wasn't specified (zero value). For
	// when you need to handshake from low orbit.
	var duration time.Duration
	if c.config.HandshakeTimeout == 0 {
		duration = 1 * time.Minute
	} else {
		duration = c.config.HandshakeTimeout
	}

	connectionEstablished := make(chan struct{}, 1)

	var sshConn ssh.Conn
	var sshChan <-chan ssh.NewChannel
	var req <-chan *ssh.Request

	go func() {
		sshConn, sshChan, req, err = ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
		close(connectionEstablished)
	}()

	select {
	case <-connectionEstablished:
		// We don't need to do anything here. We just want select to block until
		// we connect or timeout.
	case <-time.After(duration):
		if c.conn != nil {
			c.conn.Close()
		}
		if sshConn != nil {
			sshConn.Close()
		}
		return ErrHandshakeTimeout
	}

	if err != nil {
		log.Printf("handshake error: %s", err)
		return
	}
	log.Printf("handshake complete!")
	if sshConn != nil {
		c.client = ssh.NewClient(sshConn, sshChan, req)
	}
	c.connectToAgent()

	return
}
Пример #9
0
/* 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 */
}
Пример #10
0
/* 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")
}
Пример #11
0
/* waitChan puts an empty struct in wc when c's Wait method returns. */
func waitChan(c ssh.Conn, wc chan<- struct{}) {
	c.Wait()
	wc <- struct{}{}
}