Added chaff cmdline options to client & server

This commit is contained in:
Russ Magee 2018-05-06 17:41:09 -07:00
parent 64e511c3c5
commit a1f4e0342a
3 changed files with 45 additions and 24 deletions

View file

@ -44,6 +44,13 @@ type WinSize struct {
Cols uint16 Cols uint16
} }
type ChaffConfig struct {
enabled bool
msecsMin uint //msecs min interval
msecsMax uint //msecs max interval
szMax uint // max size in bytes
}
// Conn is a HKex connection - a drop-in replacement for net.Conn // Conn is a HKex connection - a drop-in replacement for net.Conn
type Conn struct { type Conn struct {
m *sync.Mutex m *sync.Mutex
@ -55,9 +62,7 @@ type Conn struct {
Rows uint16 Rows uint16
Cols uint16 Cols uint16
chaff bool chaff ChaffConfig
chaffMsecsMin int //msecs min interval
chaffMsecsMax int //msecs max interval
r cipher.Stream //read cipherStream r cipher.Stream //read cipherStream
rm hash.Hash rm hash.Hash
@ -498,30 +503,32 @@ func (c Conn) WritePacket(b []byte, op byte) (n int, err error) {
return return
} }
func (c *Conn) Chaff(enable bool, msecsMin int, msecsMax int, szMax int) { func (c *Conn) EnableChaff() {
c.chaff = enable c.chaff.enabled = true
c.chaffMsecsMin = msecsMin //move these to params of chaffHelper() ? log.Println("Chaffing ENABLED")
c.chaffMsecsMax = msecsMax c.chaffHelper()
}
if enable { func (c *Conn) Chaff(msecsMin uint, msecsMax uint, szMax uint) {
log.Println("Chaffing ENABLED") c.chaff.msecsMin = msecsMin //move these to params of chaffHelper() ?
c.chaffHelper(szMax) c.chaff.msecsMax = msecsMax
} c.chaff.szMax = szMax
} }
// Helper routine to spawn a chaffing goroutine for each Conn // Helper routine to spawn a chaffing goroutine for each Conn
func (c *Conn) chaffHelper(szMax int) { func (c *Conn) chaffHelper() {
go func() { go func() {
for { for {
var nextDuration int var nextDuration int
if c.chaff { if c.chaff.enabled {
chaff := make([]byte, rand.Intn(szMax)) bufTmp := make([]byte, rand.Intn(int(c.chaff.szMax)))
min := c.chaffMsecsMin min := int(c.chaff.msecsMin)
nextDuration = rand.Intn(c.chaffMsecsMax-min) + min nextDuration = rand.Intn(int(c.chaff.msecsMax)-min) + min
_, _ = rand.Read(chaff) _, _ = rand.Read(bufTmp)
_, err := c.WritePacket(chaff, CSOChaff) _, err := c.WritePacket(bufTmp, CSOChaff)
if err != nil { if err != nil {
log.Println("[ *** error - chaffHelper quitting *** ]") log.Println("[ *** error - chaffHelper quitting *** ]")
c.chaff.enabled = false
break break
} }
} }

View file

@ -73,6 +73,10 @@ func main() {
var cmdStr string var cmdStr string
var altUser string var altUser string
var authCookie string var authCookie string
var chaffFreqMin uint
var chaffFreqMax uint
var chaffBytesMax uint
isInteractive := false isInteractive := false
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\"]")
@ -81,6 +85,9 @@ func main() {
flag.StringVar(&cmdStr, "x", "", "command to run (default empty - interactive shell)") flag.StringVar(&cmdStr, "x", "", "command to run (default empty - interactive shell)")
flag.StringVar(&altUser, "u", "", "specify alternate user") flag.StringVar(&altUser, "u", "", "specify alternate user")
flag.StringVar(&authCookie, "a", "", "auth cookie") flag.StringVar(&authCookie, "a", "", "auth cookie")
flag.UintVar(&chaffFreqMin, "cfm", 100, "chaff pkt freq min (msecs)")
flag.UintVar(&chaffFreqMax, "cfM", 5000, "chaff pkt freq max (msecs)")
flag.UintVar(&chaffBytesMax, "cbM", 64, "chaff pkt size max (bytes)")
flag.BoolVar(&dbg, "d", false, "debug logging") flag.BoolVar(&dbg, "d", false, "debug logging")
flag.Parse() flag.Parse()
@ -228,7 +235,8 @@ func main() {
// Copy() expects EOF so this will // Copy() expects EOF so this will
// exit with outerr == nil // exit with outerr == nil
//!_, outerr := io.Copy(conn, os.Stdin) //!_, outerr := io.Copy(conn, os.Stdin)
conn.Chaff(true, 100, 500, 32) // enable client->server chaffing conn.Chaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing
conn.EnableChaff()
_, outerr := func(conn *hkexsh.Conn, r io.Reader) (w int64, e error) { _, outerr := func(conn *hkexsh.Conn, r io.Reader) (w int64, e error) {
return io.Copy(conn, r) return io.Copy(conn, r)
}(conn, os.Stdin) }(conn, os.Stdin)

View file

@ -134,12 +134,9 @@ func runShellAs(who string, cmd string, interactive bool, conn hkexsh.Conn) (err
_, _ = io.Copy(ptmx, conn) _, _ = io.Copy(ptmx, conn)
}() }()
conn.EnableChaff()
// ..and the pty to stdout. // ..and the pty to stdout.
// --(FIXME: server->client chaffing can't work here as-is, since we
// --pty.Start()ed the command above, and that command has no
// --knowledge of another thread which would do chaffing.
// --Modify pty somehow to slave the command through hkexsh.Copy() ?
conn.Chaff(true, 100, 500, 32)
_, _ = io.Copy(conn, ptmx) _, _ = io.Copy(conn, ptmx)
//err = c.Run() // returns when c finishes. //err = c.Run() // returns when c finishes.
@ -161,10 +158,16 @@ func rejectUserMsg() string {
// Listener and Conns. The KEx and encrypt/decrypt is done within the type. // Listener and Conns. The KEx and encrypt/decrypt is done within the type.
// Compare to 'serverp.go' in this directory to see the equivalence. // Compare to 'serverp.go' in this directory to see the equivalence.
func main() { func main() {
var chaffFreqMin uint
var chaffFreqMax uint
var chaffBytesMax uint
var dbg bool var dbg bool
var laddr string var laddr string
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen")
flag.UintVar(&chaffFreqMin, "cfm", 100, "chaff pkt freq min (msecs)")
flag.UintVar(&chaffFreqMax, "cfM", 5000, "chaff pkt freq max (msecs)")
flag.UintVar(&chaffBytesMax, "cbM", 64, "chaff pkt size max (bytes)")
flag.BoolVar(&dbg, "d", false, "debug logging") flag.BoolVar(&dbg, "d", false, "debug logging")
flag.Parse() flag.Parse()
@ -193,6 +196,9 @@ func main() {
} else { } else {
log.Println("Accepted client") log.Println("Accepted client")
// Set up chaffing to client
conn.Chaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing
// Handle the connection in a new goroutine. // Handle the connection in a new goroutine.
// The loop then returns to accepting, so that // The loop then returns to accepting, so that
// multiple connections may be served concurrently. // multiple connections may be served concurrently.