Jul 8, 2014 - 2 minutes

Go-lang compare *ssh.Request.Type against a string

I was working on the agent for SSH Pot and ran into something interesting last night. A lot of the brute force attempts attempt to run a command like this:

ssh [email protected] 'uname'

This is different than:

ssh [email protected]
$ uname

The first command is executing a command then exiting, the second is actually logging in and giving the user a shell. The first requests a exec subsystem and the second requests a shell subsystem - so there are two ways to handle it.

 1 func HandleShellRequest(channel ssh.Channel, in <-chan *ssh.Request) {
 2 	for req := range in {
 3 		ok := true
 4 		logfile.Println("[request " + req.Type + "]: " + string(req.Payload))
 5 		switch req.Type {
 6 		case "shell":
 7 			req.Reply(ok, nil)
 8 		case "exec":
 9 			if string(req.Payload) == string("uname") {
10 				channel.Write([]byte("\n\rLinux\n\r"))
11 			}
12 
13 			channel.Close()
14 		}
15 	}
16 }

When logging in my logfile it would show something like:

[request exec]: uname

And even when comparing the two side by side with something like this:

1 logfile.Println("["+string(req.Payload)+"]:["+"uname"+"]")

I would get this output:

[uname]:[uname]

Yet the comparison on line 9 would not get hit. After sitting and thinking about it for a while I decided to print the bytes out:

INFO: 2014/07/07 23:15:18 sshd.go:157: [0 0 0 5 117 110 97 109 101]
INFO: 2014/07/07 23:15:18 sshd.go:158: [117 110 97 109 101]

Aha! So for some reason req.Payload is padded with 3 null bytes and a ENQ byte (hex 5).

Here is the corrected version removing the correct bytes - now the string comparison works:

 1 func HandleShellRequest(channel ssh.Channel, in <-chan *ssh.Request) {
 2 	for req := range in {
 3 		ok := true
 4 		logfile.Println("[request " + req.Type + "]: " + string(req.Payload))
 5 		switch req.Type {
 6 		case "shell":
 7 			req.Reply(ok, nil)
 8 		case "exec":
 9 			if string(req.Payload[4:]) == string("uname") {
10 				channel.Write([]byte("\n\rLinux\n\r"))
11 			}
12 
13 			channel.Close()
14 		}
15 	}
16 }
comments powered by Disqus