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