mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			Added -a authtoken feature for scripted use
This commit is contained in:
		
							parent
							
								
									350f3f375e
								
							
						
					
					
						commit
						c9eb6bcb38
					
				
							
								
								
									
										2
									
								
								TODO.txt
								
								
								
								
							
							
						
						
									
										2
									
								
								TODO.txt
								
								
								
								
							| 
						 | 
					@ -5,6 +5,8 @@ Chaff Improvements
 | 
				
			||||||
- Mimicry of hand-typed traffic for chaff on interactive sessions
 | 
					- Mimicry of hand-typed traffic for chaff on interactive sessions
 | 
				
			||||||
- Client-input chaff file data (ie., Moby Dick)
 | 
					- Client-input chaff file data (ie., Moby Dick)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					KEx: Look at ECIES: https://godoc.org/github.com/bitherhq/go-bither/crypto/ecies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Architecture
 | 
					Architecture
 | 
				
			||||||
(DONE) - Move hkexnet components other than key exchange into a proper hkex package
 | 
					(DONE) - Move hkexnet components other than key exchange into a proper hkex package
 | 
				
			||||||
  (ie., hkexsh imports hkex) - hkex should be usable for other client/svr utils,
 | 
					  (ie., hkexsh imports hkex) - hkex should be usable for other client/svr utils,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								hkexauth.go
								
								
								
								
							
							
						
						
									
										22
									
								
								hkexauth.go
								
								
								
								
							| 
						 | 
					@ -11,15 +11,17 @@ package hkexsh
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
 | 
						"os/user"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/jameskeane/bcrypt"
 | 
						"github.com/jameskeane/bcrypt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func AuthUser(username string, auth string, fname string) (valid bool, allowedCmds string) {
 | 
					func AuthUserByPasswd(username string, auth string, fname string) (valid bool, allowedCmds string) {
 | 
				
			||||||
	b, e := ioutil.ReadFile(fname)
 | 
						b, e := ioutil.ReadFile(fname)
 | 
				
			||||||
	if e != nil {
 | 
						if e != nil {
 | 
				
			||||||
		valid = false
 | 
							valid = false
 | 
				
			||||||
| 
						 | 
					@ -65,3 +67,21 @@ func AuthUser(username string, auth string, fname string) (valid bool, allowedCm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func AuthUserByToken(username string, auth string) (valid bool) {
 | 
				
			||||||
 | 
						u, ue := user.Lookup(username)
 | 
				
			||||||
 | 
						if ue != nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b, e := ioutil.ReadFile(fmt.Sprintf("%s/.hkexsh_id", u.HomeDir))
 | 
				
			||||||
 | 
						if e != nil {
 | 
				
			||||||
 | 
							log.Printf("INFO: Cannot read %s/.hkexsh_id\n", u.HomeDir)
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if string(b) == auth {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -320,6 +320,7 @@ func rejectUserMsg() string {
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	version := "0.2pre (NO WARRANTY)"
 | 
						version := "0.2pre (NO WARRANTY)"
 | 
				
			||||||
	var vopt bool
 | 
						var vopt bool
 | 
				
			||||||
 | 
						var aopt bool
 | 
				
			||||||
	var dbg bool
 | 
						var dbg bool
 | 
				
			||||||
	var shellMode bool // if true act as shell, else file copier
 | 
						var shellMode bool // if true act as shell, else file copier
 | 
				
			||||||
	var cAlg string
 | 
						var cAlg string
 | 
				
			||||||
| 
						 | 
					@ -345,7 +346,7 @@ func main() {
 | 
				
			||||||
	flag.StringVar(&cAlg, "c", "C_AES_256", "`cipher` [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]")
 | 
						flag.StringVar(&cAlg, "c", "C_AES_256", "`cipher` [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]")
 | 
				
			||||||
	flag.StringVar(&hAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\"]")
 | 
						flag.StringVar(&hAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\"]")
 | 
				
			||||||
	flag.UintVar(&port, "p", 2000, "`port`")
 | 
						flag.UintVar(&port, "p", 2000, "`port`")
 | 
				
			||||||
	flag.StringVar(&authCookie, "a", "", "auth cookie")
 | 
						//flag.StringVar(&authCookie, "a", "", "auth cookie")
 | 
				
			||||||
	flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts (default true)")
 | 
						flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts (default true)")
 | 
				
			||||||
	flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt `freq` min (msecs)")
 | 
						flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt `freq` min (msecs)")
 | 
				
			||||||
	flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt `freq` max (msecs)")
 | 
						flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt `freq` max (msecs)")
 | 
				
			||||||
| 
						 | 
					@ -357,6 +358,7 @@ func main() {
 | 
				
			||||||
		// hkexsh accepts a command (-x) but not
 | 
							// hkexsh accepts a command (-x) but not
 | 
				
			||||||
		// a srcpath (-r) or dstpath (-t)
 | 
							// a srcpath (-r) or dstpath (-t)
 | 
				
			||||||
		flag.StringVar(&cmdStr, "x", "", "`command` to run (if not specified run interactive shell)")
 | 
							flag.StringVar(&cmdStr, "x", "", "`command` to run (if not specified run interactive shell)")
 | 
				
			||||||
 | 
							flag.BoolVar(&aopt, "a", false, "return autologin token from server")
 | 
				
			||||||
		shellMode = true
 | 
							shellMode = true
 | 
				
			||||||
		flag.Usage = UsageShell
 | 
							flag.Usage = UsageShell
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -443,10 +445,24 @@ func main() {
 | 
				
			||||||
		log.SetOutput(ioutil.Discard)
 | 
							log.SetOutput(ioutil.Discard)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// See if we can log in via an auth token
 | 
				
			||||||
 | 
						u, _ := user.Current()
 | 
				
			||||||
 | 
						ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.hkexsh_id", u.HomeDir))
 | 
				
			||||||
 | 
						if aerr == nil {
 | 
				
			||||||
 | 
							authCookie = string(ab)
 | 
				
			||||||
 | 
							// Security scrub
 | 
				
			||||||
 | 
							ab = nil
 | 
				
			||||||
 | 
							runtime.GC()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if shellMode {
 | 
						if shellMode {
 | 
				
			||||||
		// We must make the decision about interactivity before Dial()
 | 
							// We must make the decision about interactivity before Dial()
 | 
				
			||||||
		// as it affects chaffing behaviour. 20180805
 | 
							// as it affects chaffing behaviour. 20180805
 | 
				
			||||||
		if len(cmdStr) == 0 {
 | 
							if aopt {
 | 
				
			||||||
 | 
								op = []byte{'A'}
 | 
				
			||||||
 | 
								chaffFreqMin = 2
 | 
				
			||||||
 | 
								chaffFreqMax = 10
 | 
				
			||||||
 | 
							} else if len(cmdStr) == 0 {
 | 
				
			||||||
			op = []byte{'s'}
 | 
								op = []byte{'s'}
 | 
				
			||||||
			isInteractive = true
 | 
								isInteractive = true
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -467,20 +483,20 @@ func main() {
 | 
				
			||||||
			// client->server file copy
 | 
								// client->server file copy
 | 
				
			||||||
			// src file list is in copySrc
 | 
								// src file list is in copySrc
 | 
				
			||||||
			op = []byte{'D'}
 | 
								op = []byte{'D'}
 | 
				
			||||||
			fmt.Println("client->server copy:", string(copySrc), "->", copyDst)
 | 
								//fmt.Println("client->server copy:", string(copySrc), "->", copyDst)
 | 
				
			||||||
			cmdStr = copyDst
 | 
								cmdStr = copyDst
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// server->client file copy
 | 
								// server->client file copy
 | 
				
			||||||
			// remote src file(s) in copyDsr
 | 
								// remote src file(s) in copyDsr
 | 
				
			||||||
			op = []byte{'S'}
 | 
								op = []byte{'S'}
 | 
				
			||||||
			fmt.Println("server->client copy:", string(copySrc), "->", copyDst)
 | 
								//fmt.Println("server->client copy:", string(copySrc), "->", copyDst)
 | 
				
			||||||
			cmdStr = string(copySrc)
 | 
								cmdStr = string(copySrc)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn, err := hkexnet.Dial("tcp", server, /*[kexAlg eg. "KEX_HERRADURA"], */ cAlg, hAlg)
 | 
						conn, err := hkexnet.Dial("tcp", server /*[kexAlg eg. "KEX_HERRADURA"], */, cAlg, hAlg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		fmt.Println("Err!")
 | 
							fmt.Println(err)
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer conn.Close()
 | 
						defer conn.Close()
 | 
				
			||||||
| 
						 | 
					@ -514,9 +530,9 @@ func main() {
 | 
				
			||||||
		ab = nil
 | 
							ab = nil
 | 
				
			||||||
		runtime.GC()
 | 
							runtime.GC()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	// Set up session params and send over to server
 | 
						// Set up session params and send over to server
 | 
				
			||||||
	rec := hkexsh.NewSession(op, []byte(uname), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie),0)
 | 
						rec := hkexsh.NewSession(op, []byte(uname), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie), 0)
 | 
				
			||||||
	_, err = fmt.Fprintf(conn, "%d %d %d %d %d\n",
 | 
						_, err = fmt.Fprintf(conn, "%d %d %d %d %d\n",
 | 
				
			||||||
		len(rec.Op()), len(rec.Who()), len(rec.TermType()), len(rec.Cmd()), len(rec.AuthCookie(true)))
 | 
							len(rec.Op()), len(rec.Who()), len(rec.TermType()), len(rec.Cmd()), len(rec.AuthCookie(true)))
 | 
				
			||||||
	_, err = conn.Write(rec.Op())
 | 
						_, err = conn.Write(rec.Op())
 | 
				
			||||||
| 
						 | 
					@ -544,8 +560,8 @@ func main() {
 | 
				
			||||||
		if shellMode {
 | 
							if shellMode {
 | 
				
			||||||
			doShellMode(isInteractive, conn, oldState, rec)
 | 
								doShellMode(isInteractive, conn, oldState, rec)
 | 
				
			||||||
		} else { // copyMode
 | 
							} else { // copyMode
 | 
				
			||||||
				_, s := doCopyMode(conn, pathIsDest, fileArgs, rec)
 | 
								_, s := doCopyMode(conn, pathIsDest, fileArgs, rec)
 | 
				
			||||||
				rec.SetStatus(s)
 | 
								rec.SetStatus(s)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if rec.Status() != 0 {
 | 
							if rec.Status() != 0 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,9 @@ package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
	"flag"
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
| 
						 | 
					@ -48,6 +50,7 @@ func runClientToServerCopyAs(who, ttype string, conn hkexnet.Conn, fpath string,
 | 
				
			||||||
	os.Clearenv()
 | 
						os.Clearenv()
 | 
				
			||||||
	os.Setenv("HOME", u.HomeDir)
 | 
						os.Setenv("HOME", u.HomeDir)
 | 
				
			||||||
	os.Setenv("TERM", ttype)
 | 
						os.Setenv("TERM", ttype)
 | 
				
			||||||
 | 
						os.Setenv("HKEXSH", "1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var c *exec.Cmd
 | 
						var c *exec.Cmd
 | 
				
			||||||
	cmdName := "/bin/tar"
 | 
						cmdName := "/bin/tar"
 | 
				
			||||||
| 
						 | 
					@ -130,6 +133,7 @@ func runServerToClientCopyAs(who, ttype string, conn hkexnet.Conn, srcPath strin
 | 
				
			||||||
	os.Clearenv()
 | 
						os.Clearenv()
 | 
				
			||||||
	os.Setenv("HOME", u.HomeDir)
 | 
						os.Setenv("HOME", u.HomeDir)
 | 
				
			||||||
	os.Setenv("TERM", ttype)
 | 
						os.Setenv("TERM", ttype)
 | 
				
			||||||
 | 
						os.Setenv("HKEXSH", "1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var c *exec.Cmd
 | 
						var c *exec.Cmd
 | 
				
			||||||
	cmdName := "/bin/tar"
 | 
						cmdName := "/bin/tar"
 | 
				
			||||||
| 
						 | 
					@ -216,7 +220,8 @@ func runShellAs(who, ttype string, cmd string, interactive bool, conn hkexnet.Co
 | 
				
			||||||
	os.Clearenv()
 | 
						os.Clearenv()
 | 
				
			||||||
	os.Setenv("HOME", u.HomeDir)
 | 
						os.Setenv("HOME", u.HomeDir)
 | 
				
			||||||
	os.Setenv("TERM", ttype)
 | 
						os.Setenv("TERM", ttype)
 | 
				
			||||||
 | 
						os.Setenv("HKEXSH", "1")
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	var c *exec.Cmd
 | 
						var c *exec.Cmd
 | 
				
			||||||
	if interactive {
 | 
						if interactive {
 | 
				
			||||||
		c = exec.Command("/bin/bash", "-i", "-l")
 | 
							c = exec.Command("/bin/bash", "-i", "-l")
 | 
				
			||||||
| 
						 | 
					@ -311,6 +316,17 @@ func runShellAs(who, ttype string, cmd string, interactive bool, conn hkexnet.Co
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GenAuthToken(who string) string {
 | 
				
			||||||
 | 
						tokenA, e := os.Hostname()
 | 
				
			||||||
 | 
						if e != nil {
 | 
				
			||||||
 | 
							tokenA = "badhost"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokenB := make([]byte, 64)
 | 
				
			||||||
 | 
						_, _ = rand.Read(tokenB)
 | 
				
			||||||
 | 
						return fmt.Sprintf("%s:%s", tokenA, hex.EncodeToString(tokenB))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Demo of a simple server that listens and spawns goroutines for each
 | 
					// Demo of a simple server that listens and spawns goroutines for each
 | 
				
			||||||
// connecting client. Note this code is identical to standard tcp
 | 
					// connecting client. Note this code is identical to standard tcp
 | 
				
			||||||
// server code, save for declaring 'hkex' rather than 'net'
 | 
					// server code, save for declaring 'hkex' rather than 'net'
 | 
				
			||||||
| 
						 | 
					@ -442,7 +458,13 @@ func main() {
 | 
				
			||||||
				log.Printf("[hkexsh.Session: op:%c who:%s cmd:%s auth:****]\n",
 | 
									log.Printf("[hkexsh.Session: op:%c who:%s cmd:%s auth:****]\n",
 | 
				
			||||||
					rec.Op()[0], string(rec.Who()), string(rec.Cmd()))
 | 
										rec.Op()[0], string(rec.Who()), string(rec.Cmd()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				valid, allowedCmds := hkexsh.AuthUser(string(rec.Who()), string(rec.AuthCookie(true)), "/etc/hkexsh.passwd")
 | 
									var valid bool
 | 
				
			||||||
 | 
									var allowedCmds string // Currently unused
 | 
				
			||||||
 | 
									if hkexsh.AuthUserByToken(string(rec.Who()), string(rec.AuthCookie(true))) {
 | 
				
			||||||
 | 
										valid = true
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										valid, allowedCmds = hkexsh.AuthUserByPasswd(string(rec.Who()), string(rec.AuthCookie(true)), "/etc/hkexsh.passwd")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Security scrub
 | 
									// Security scrub
 | 
				
			||||||
				rec.ClearAuthCookie()
 | 
									rec.ClearAuthCookie()
 | 
				
			||||||
| 
						 | 
					@ -458,7 +480,24 @@ func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				log.Printf("[allowedCmds:%s]\n", allowedCmds)
 | 
									log.Printf("[allowedCmds:%s]\n", allowedCmds)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if rec.Op()[0] == 'c' {
 | 
									if rec.Op()[0] == 'A' {
 | 
				
			||||||
 | 
										// Generate automated login token
 | 
				
			||||||
 | 
										addr := hc.RemoteAddr()
 | 
				
			||||||
 | 
										hname := strings.Split(addr.String(), ":")[0]
 | 
				
			||||||
 | 
										log.Printf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)
 | 
				
			||||||
 | 
										token := GenAuthToken(string(rec.Who()))
 | 
				
			||||||
 | 
										tokenCmd := fmt.Sprintf("echo \"%s\" | tee ~/.hkexsh_id", token)
 | 
				
			||||||
 | 
										runErr, cmdStatus := runShellAs(string(rec.Who()), string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
 | 
				
			||||||
 | 
										// Returned hopefully via an EOF or exit/logout;
 | 
				
			||||||
 | 
										// Clear current op so user can enter next, or EOF
 | 
				
			||||||
 | 
										rec.SetOp([]byte{0})
 | 
				
			||||||
 | 
										if runErr != nil {
 | 
				
			||||||
 | 
											log.Printf("[Error generating autologin token for %s@%s]\n", rec.Who(), hname)
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											log.Printf("[Autologin token generation completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
 | 
				
			||||||
 | 
											hc.SetStatus(cmdStatus)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									} else if rec.Op()[0] == 'c' {
 | 
				
			||||||
					// Non-interactive command
 | 
										// Non-interactive command
 | 
				
			||||||
					addr := hc.RemoteAddr()
 | 
										addr := hc.RemoteAddr()
 | 
				
			||||||
					//hname := goutmp.GetHost(addr.String())
 | 
										//hname := goutmp.GetHost(addr.String())
 | 
				
			||||||
| 
						 | 
					@ -470,9 +509,9 @@ func main() {
 | 
				
			||||||
					// Clear current op so user can enter next, or EOF
 | 
										// Clear current op so user can enter next, or EOF
 | 
				
			||||||
					rec.SetOp([]byte{0})
 | 
										rec.SetOp([]byte{0})
 | 
				
			||||||
					if runErr != nil {
 | 
										if runErr != nil {
 | 
				
			||||||
						log.Printf("[Error spawning cmd for %s@%s]\n", rec.Who, hname)
 | 
											log.Printf("[Error spawning cmd for %s@%s]\n", rec.Who(), hname)
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						log.Printf("[Command completed for %s@%s, status %d]\n", rec.Who, hname, cmdStatus)
 | 
											log.Printf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
 | 
				
			||||||
						hc.SetStatus(cmdStatus)
 | 
											hc.SetStatus(cmdStatus)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else if rec.Op()[0] == 's' {
 | 
									} else if rec.Op()[0] == 's' {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue