# Patching OpenSSH daemon to not allow libssh (patch inside)

## nlindblad

After a few weeks of intensive reading up on the RFC for SSH and various netcat/telnet examples I feel like I've got a bit better understanding about how the SSH protocol works.

I'm running a shell server at home and of course I've got tons of scans like:

```
Feb 25 10:40:39 deschutes sshd[18463]: Invalid user mailtest from 72.3.247.29

Feb 25 10:40:42 deschutes sshd[87]: Invalid user mailtest from 72.3.247.29

Feb 25 10:40:46 deschutes sshd[22163]: Invalid user mailtest from 72.3.247.29

Feb 25 10:40:49 deschutes sshd[9382]: Invalid user mailtest from 72.3.247.29

Feb 25 10:40:52 deschutes sshd[21702]: Invalid user mailtest from 72.3.247.29

Feb 25 10:40:55 deschutes sshd[29898]: Invalid user mailtest from 72.3.247.29

Feb 25 10:40:57 deschutes sshd[26666]: Invalid user testuser from 72.3.247.29
```

Instead of using utilities such as denyhosts I got the idea to kill these sort of things off on such a low level that the system itself doesn't have to process information for /etc/hosts.deny or iptables rules.

Basically, this is how SSH works when a connection is made:

Server sends it's version string to the client

Client respondes with it's own version string

Host keys are transfered

...

I put up a honeypot SSHd on port 22 and looged the client strings the scanners were using and this was the result:

```
February 27 01:19:27 SSH-2.0-libssh-0.1 from 159.226.113.65:57753

February 27 02:12:49 SSH-2.0-libssh-0.1 from 140.109.235.76:51241

February 27 02:47:04 SSH-2.0-libssh-0.1 from 200.38.16.6:55372

February 27 08:08:07 SSH-2.0-libssh-0.1 from 200.38.16.6:53914

February 27 08:10:09 SSH-2.0-libssh-0.1 from 193.144.57.166:42613

February 27 08:33:10 SSH-2.0-libssh-0.1 from 192.188.242.78:44015
```

As you can see all of the scanning tools were using libssh, a library providing an API for scripts and programs to use SSH. Since I only intend to let "real" clients connect, all of which can identify themself with proper client strings like SSH-2.0-PuTTY_Release_0.58 and SSH-2.0-OpenSSH_3.9p1 I came up with the following solution.

Since the client string is recieved so early it would be ideal to simply make the SSHd kill the socket if the client identifies as libssh.

After spending some time looking at the source code for this (sshd.c of openssh-4.2p1 to be more exact) I wrote the following patch.

Don't try this if you're not sure what you're doing. This is just an experiment!

Start of patch:  dont-allow-libssh-openssh-4.2p1.patch

```
Common subdirectories: openssh-4.2p1/contrib and openssh-4.2p1-modified/contrib

Common subdirectories: openssh-4.2p1/openbsd-compat and openssh-4.2p1-modified/openbsd-compat

Common subdirectories: openssh-4.2p1/regress and openssh-4.2p1-modified/regress

Common subdirectories: openssh-4.2p1/scard and openssh-4.2p1-modified/scard

diff openssh-4.2p1/sshd.c openssh-4.2p1-modified/sshd.c

420,423c420,426

<     */

<    

<    /* The if-loop begins, matching client_version_string against the string

<     * libssh. If there's a match we should go on.

---

>    /*

>     

>    /* Note that we use sscanf to verify the string in a proper way. Just

>     * trying to find the characters libssh in the string could lead to problems

>     * if the client identifies itself as something containg those very characters.

>     * For example, a client_version_string valued 'SSH-2.0-notlibssh-0.1' would get

>     * rejected even though it hasn't really identified as 'libssh'.

425a429

>    /* %*d tells sscanf to not bother assigning found ints in the input. Except for int last */

427c431

< 

---

>    int last;

428a433,442

>         if ( sscanf(client_version_string, "SSH-%*d.%*d-libssh-%*d.%*d\n", &last ) == 1) {

>       s = "Client not allowed.\n";

>       (void) atomicio(vwrite, sock_out, s, strlen(s));

>       close(sock_in);

>       close(sock_out);

>       logit("Not allowed client '%.100s' from %s",

>           client_version_string, get_remote_ipaddr());

>       cleanup_exit(255);

>         } 

> 

Only in openssh-4.2p1-modified/: sshd.c.save
```

Probably a lousy idea. But hey, atleast I've tried.

Now I just have to test this darling.

----------

## NeddySeagoon

nlindblad,

How does your patch respond to scp and sftp ?

----------

## nlindblad

 *NeddySeagoon wrote:*   

> nlindblad,
> 
> How does your patch respond to scp and sftp ?

 

Respond? Yeah, I know, it's not close to RFC compatible. Just a weird idea.

----------

## Mad Merlin

I would suggest that instead of immediately closing the connection, appear to behave exactly as if they were using a valid client, but do not bother trying to authenticate their username or password, and then obviously reject the login after they've been supplied. In this way, the attacker doesn't know that they're being rejected based upon the client string they're providing. This works on the same principal as allowing the attacker to enter a password, even if they've used an invalid user, the attacker can't find valid usernames by testing to see which are rejected and which are not. It's trivially easy to spoof the client name, I suggest you not alert the attackers to the potential problem, or they may also adapt.

----------

## nlindblad

 *Mad Merlin wrote:*   

> I would suggest that instead of immediately closing the connection, appear to behave exactly as if they were using a valid client, but do not bother trying to authenticate their username or password, and then obviously reject the login after they've been supplied. In this way, the attacker doesn't know that they're being rejected based upon the client string they're providing. This works on the same principal as allowing the attacker to enter a password, even if they've used an invalid user, the attacker can't find valid usernames by testing to see which are rejected and which are not. It's trivially easy to spoof the client name, I suggest you not alert the attackers to the potential problem, or they may also adapt.

 

Excellent idea!   :Shocked: 

----------

