mscdex / ssh2

SSH2 client and server modules written in pure JavaScript for node.js
MIT License
5.52k stars 664 forks source link

Issue with authHandler in keyboard-interactive mode #1076

Closed Kurtas closed 2 years ago

Kurtas commented 3 years ago

Hi @mscdex

we have the multi-vendor environment and we have several PaloAltos there and those devices have configured some statement that has to be confirmed before authentication, see attached screenshot from putty. obrazek

We're not able to log in only with username / password, even we're listening to keyboard-interactive event and sending replies to prompts.

here is a debug log

info: Connecting to 10.241.21.4 by ssh
[2021-10-02T19:14:40.052Z] Custom crypto binding available
[2021-10-02T19:14:40.054Z] Local ident: 'SSH-2.0-ssh2js1.4.0'
[2021-10-02T19:14:40.055Z] Client: Trying 10.241.21.4 on port 22 ...
[2021-10-02T19:14:40.065Z] Socket connected
[2021-10-02T19:14:41.843Z] Remote ident: 'SSH-2.0-OpenSSH_12.1'
[2021-10-02T19:14:41.844Z] Outbound: Sending KEXINIT
[2021-10-02T19:14:41.861Z] Inbound: Handshake in progress
[2021-10-02T19:14:41.861Z] Handshake: (local) KEX method: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
[2021-10-02T19:14:41.861Z] Handshake: (remote) KEX method: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
[2021-10-02T19:14:41.861Z] Handshake: KEX algorithm: ecdh-sha2-nistp256
[2021-10-02T19:14:41.862Z] Handshake: (local) Host key format: ssh-ed25519,ssh-rsa,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-dss
[2021-10-02T19:14:41.862Z] Handshake: (remote) Host key format: ssh-rsa
[2021-10-02T19:14:41.862Z] Handshake: Host key format: ssh-rsa
[2021-10-02T19:14:41.862Z] Handshake: (local) C->S cipher: aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes256-cbc,aes192-cbc,aes128-cbc,blowfish-cbc,3des-cbc,arcfour256,arcfour128,cast128-cbc,arcfour
[2021-10-02T19:14:41.862Z] Handshake: (remote) C->S cipher: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se
[2021-10-02T19:14:41.862Z] Handshake: C->S Cipher: aes128-ctr
[2021-10-02T19:14:41.862Z] Handshake: (local) S->C cipher: aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes256-cbc,aes192-cbc,aes128-cbc,blowfish-cbc,3des-cbc,arcfour256,arcfour128,cast128-cbc,arcfour
[2021-10-02T19:14:41.862Z] Handshake: (remote) S->C cipher: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se
[2021-10-02T19:14:41.862Z] Handshake: S->C cipher: aes128-ctr
[2021-10-02T19:14:41.862Z] Handshake: (local) C->S MAC: hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha2-256-96,hmac-sha2-512-96,hmac-ripemd160,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:14:41.862Z] Handshake: (remote) C->S MAC: hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:14:41.862Z] Handshake: C->S MAC: hmac-sha2-256
[2021-10-02T19:14:41.862Z] Handshake: (local) S->C MAC: hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha2-256-96,hmac-sha2-512-96,hmac-ripemd160,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:14:41.863Z] Handshake: (remote) S->C MAC: hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:14:41.863Z] Handshake: S->C MAC: hmac-sha2-256
[2021-10-02T19:14:41.863Z] Handshake: (local) C->S compression: none,zlib@openssh.com,zlib
[2021-10-02T19:14:41.863Z] Handshake: (remote) C->S compression: none,zlib@openssh.com
[2021-10-02T19:14:41.863Z] Handshake: C->S compression: none
[2021-10-02T19:14:41.863Z] Handshake: (local) S->C compression: none,zlib@openssh.com,zlib
[2021-10-02T19:14:41.863Z] Handshake: (remote) S->C compression: none,zlib@openssh.com
[2021-10-02T19:14:41.863Z] Handshake: S->C compression: none
[2021-10-02T19:14:41.863Z] Outbound: Sending KEXECDH_INIT
[2021-10-02T19:14:41.892Z] Received DH Reply
[2021-10-02T19:14:41.892Z] Host accepted by default (no verification)
[2021-10-02T19:14:41.892Z] Host accepted (verified)
[2021-10-02T19:14:41.892Z] Outbound: Sending NEWKEYS
[2021-10-02T19:14:41.893Z] Inbound: NEWKEYS
[2021-10-02T19:14:41.897Z] Verifying signature ...
[2021-10-02T19:14:41.897Z] Verified signature
[2021-10-02T19:14:41.898Z] Handshake completed
[2021-10-02T19:14:41.899Z] Outbound: Sending SERVICE_REQUEST (ssh-userauth)
[2021-10-02T19:14:41.908Z] Inbound: Received SERVICE_ACCEPT (ssh-userauth)
[2021-10-02T19:14:41.908Z] Outbound: Sending USERAUTH_REQUEST (none)
[2021-10-02T19:14:51.945Z] Inbound: Received USERAUTH_BANNER
[2021-10-02T19:14:51.946Z] Inbound: Received USERAUTH_FAILURE (publickey,password,keyboard-interactive)
[2021-10-02T19:14:51.946Z] Client: none auth failed
[2021-10-02T19:14:51.947Z] Outbound: Sending USERAUTH_REQUEST (password)
[2021-10-02T19:14:51.982Z] Inbound: Received USERAUTH_FAILURE (publickey,password,keyboard-interactive)
[2021-10-02T19:14:51.983Z] Client: password auth failed
[2021-10-02T19:14:51.983Z] Outbound: Sending USERAUTH_REQUEST (keyboard-interactive)
[2021-10-02T19:14:52.007Z] Inbound: Received USERAUTH_INFO_REQUEST
##### Received keyboardInteractiveCallback ##########
Do you accept and acknowledge the statement above ? (yes/no) : 
Seding yes
[2021-10-02T19:14:52.013Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.025Z] Inbound: Received USERAUTH_INFO_REQUEST
##### Received keyboardInteractiveCallback ##########
Password: 
[2021-10-02T19:14:52.025Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.064Z] Inbound: Received USERAUTH_INFO_REQUEST
[2021-10-02T19:14:52.064Z] Client: Sending automatic USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.064Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.072Z] Inbound: Received USERAUTH_SUCCESS
[2021-10-02T19:14:52.074Z] Outbound: Sending CHANNEL_OPEN (r:0, session)
[2021-10-02T19:14:52.075Z] Socket ended
[2021-10-02T19:14:52.077Z] Socket closed

Then I noticed authHandler new options in version v1, I tried to use it in this way

      hostOptions.authHandler = [
        {
          type: 'keyboard-interactive',
          username: hostOptions.username,
          prompt: keyboardInteractiveCallback,
        },
      ];

Where the keyboardInteractiveCallback is the same function what listening on keyboard-interactive event and it works

Debug for that:

info: Connecting to 10.241.21.4 by ssh
[2021-10-02T19:27:45.204Z] Custom crypto binding available
[2021-10-02T19:27:45.206Z] Local ident: 'SSH-2.0-ssh2js1.4.0'
[2021-10-02T19:27:45.207Z] Client: Trying 10.241.21.4 on port 22 ...
[2021-10-02T19:27:45.218Z] Socket connected
[2021-10-02T19:27:47.278Z] Remote ident: 'SSH-2.0-OpenSSH_12.1'
[2021-10-02T19:27:47.278Z] Outbound: Sending KEXINIT
[2021-10-02T19:27:47.285Z] Inbound: Handshake in progress
[2021-10-02T19:27:47.285Z] Handshake: (local) KEX method: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
[2021-10-02T19:27:47.285Z] Handshake: (remote) KEX method: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
[2021-10-02T19:27:47.285Z] Handshake: KEX algorithm: ecdh-sha2-nistp256
[2021-10-02T19:27:47.286Z] Handshake: (local) Host key format: ssh-ed25519,ssh-rsa,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-dss
[2021-10-02T19:27:47.286Z] Handshake: (remote) Host key format: ssh-rsa
[2021-10-02T19:27:47.286Z] Handshake: Host key format: ssh-rsa
[2021-10-02T19:27:47.286Z] Handshake: (local) C->S cipher: aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes256-cbc,aes192-cbc,aes128-cbc,blowfish-cbc,3des-cbc,arcfour256,arcfour128,cast128-cbc,arcfour
[2021-10-02T19:27:47.286Z] Handshake: (remote) C->S cipher: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se
[2021-10-02T19:27:47.286Z] Handshake: C->S Cipher: aes128-ctr
[2021-10-02T19:27:47.286Z] Handshake: (local) S->C cipher: aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes256-cbc,aes192-cbc,aes128-cbc,blowfish-cbc,3des-cbc,arcfour256,arcfour128,cast128-cbc,arcfour
[2021-10-02T19:27:47.286Z] Handshake: (remote) S->C cipher: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se
[2021-10-02T19:27:47.286Z] Handshake: S->C cipher: aes128-ctr
[2021-10-02T19:27:47.286Z] Handshake: (local) C->S MAC: hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha2-256-96,hmac-sha2-512-96,hmac-ripemd160,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:27:47.286Z] Handshake: (remote) C->S MAC: hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:27:47.286Z] Handshake: C->S MAC: hmac-sha2-256
[2021-10-02T19:27:47.286Z] Handshake: (local) S->C MAC: hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha2-256-96,hmac-sha2-512-96,hmac-ripemd160,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:27:47.287Z] Handshake: (remote) S->C MAC: hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96
[2021-10-02T19:27:47.287Z] Handshake: S->C MAC: hmac-sha2-256
[2021-10-02T19:27:47.287Z] Handshake: (local) C->S compression: none,zlib@openssh.com,zlib
[2021-10-02T19:27:47.287Z] Handshake: (remote) C->S compression: none,zlib@openssh.com
[2021-10-02T19:27:47.287Z] Handshake: C->S compression: none
[2021-10-02T19:27:47.287Z] Handshake: (local) S->C compression: none,zlib@openssh.com,zlib
[2021-10-02T19:27:47.287Z] Handshake: (remote) S->C compression: none,zlib@openssh.com
[2021-10-02T19:27:47.287Z] Handshake: S->C compression: none
[2021-10-02T19:27:47.288Z] Outbound: Sending KEXECDH_INIT
[2021-10-02T19:27:47.306Z] Received DH Reply
[2021-10-02T19:27:47.306Z] Host accepted by default (no verification)
[2021-10-02T19:27:47.307Z] Host accepted (verified)
[2021-10-02T19:27:47.307Z] Outbound: Sending NEWKEYS
[2021-10-02T19:27:47.307Z] Inbound: NEWKEYS
[2021-10-02T19:27:47.309Z] Verifying signature ...
[2021-10-02T19:27:47.310Z] Verified signature
[2021-10-02T19:27:47.311Z] Handshake completed
[2021-10-02T19:27:47.311Z] Outbound: Sending SERVICE_REQUEST (ssh-userauth)
[2021-10-02T19:27:47.320Z] Inbound: Received SERVICE_ACCEPT (ssh-userauth)
[2021-10-02T19:27:47.321Z] Outbound: Sending USERAUTH_REQUEST (keyboard-interactive)
[2021-10-02T19:27:57.375Z] Inbound: Received USERAUTH_BANNER
[2021-10-02T19:27:57.376Z] Inbound: Received USERAUTH_INFO_REQUEST
##### Received keyboardInteractiveCallback ##########
Do you accept and acknowledge the statement above ? (yes/no) : 
Sending yes
[2021-10-02T19:27:57.380Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:27:57.388Z] Inbound: Received USERAUTH_INFO_REQUEST
##### Received keyboardInteractiveCallback ##########
Password: 
[2021-10-02T19:27:57.389Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:27:57.426Z] Inbound: Received USERAUTH_INFO_REQUEST
[2021-10-02T19:27:57.426Z] Client: Sending automatic USERAUTH_INFO_RESPONSE
[2021-10-02T19:27:57.426Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:27:57.435Z] Inbound: Received USERAUTH_SUCCESS
[2021-10-02T19:27:57.437Z] Outbound: Sending CHANNEL_OPEN (r:0, session)
[2021-10-02T19:27:57.445Z] Inbound: CHANNEL_OPEN_CONFIRMATION (r:0, s:0)
[2021-10-02T19:27:57.446Z] Outbound: Sending CHANNEL_REQUEST (r:0, pty-req)
[2021-10-02T19:28:07.459Z] Inbound: CHANNEL_SUCCESS (r:0)
[2021-10-02T19:28:07.460Z] Outbound: Sending CHANNEL_REQUEST (r:0, shell)
[2021-10-02T19:28:07.468Z] Inbound: CHANNEL_WINDOW_ADJUST (r:0, 2097152)
[2021-10-02T19:28:07.469Z] Inbound: CHANNEL_SUCCESS (r:0)
[2021-10-02T19:28:07.469Z] Inbound: CHANNEL_DATA (r:0, 55)

But if we start to use authHandler where we prefer keyboard-interactive then we're facing to a problem that we can't log in into some other vendors like Cisco IOS-XR or HP Comware. As you can see from the attached putty screenshot XR has some banner after username and it's stuck in keyboard-interactive callback, on the end it's disconnected on timetout. The keyboard-interactive callback never get any data.

obrazek

HP Comware doesn't have any banner and it's immediately disconnect because of password auth failed but it also never get any data to keyboard-interactive callback

I also attached debugs from XR and Comware, both has log where authHandler was enabled and next is without authHandler

HpComwareWithAuthHandlerDisabled.txt IosXrWithAuthHandlerDisabled.txt IosXrWithAuthHandlerEnabled.txt HpComwareWithAuthHandlerEnabled.txt

mscdex commented 3 years ago

I don't understand the problem. Why not just duplicate what PuTTY is doing with regard to authentication method order, since that seems to be working for you?

Kurtas commented 3 years ago

The problem is that I don't know in advance where I'm connecting to. If it is PaloAlto or Cisco or any other specific vendor. So I need to have one setting for all connections.

If I set keyboard-interactive in authHandler for PaloAlto then it breaks the connection to Cisco IOS-XR, HP Comware.

Maybe you can somehow change the default order for authHandler, detect that there will be needed interactivity then set keyboard-interactive before password?

I don't have any idea how putty handle/detect this but there you have to set a username after that confirm statement Do you accept and acknowledge the statement above ? (yes/no) : and then you have to provide password.

But ssh2 library in default doing "full authentication" it means sends username and password, but it fails because the statement wasn't confirmed. The statement is received after that but it is too late.

[2021-10-02T19:14:51.945Z] Inbound: Received USERAUTH_BANNER
[2021-10-02T19:14:51.946Z] Inbound: Received USERAUTH_FAILURE (publickey,password,keyboard-interactive)
[2021-10-02T19:14:51.946Z] Client: none auth failed
[2021-10-02T19:14:51.947Z] Outbound: Sending USERAUTH_REQUEST (password)
[2021-10-02T19:14:51.982Z] Inbound: Received USERAUTH_FAILURE (publickey,password,keyboard-interactive)
### Password authentication before statement confirmation ####
[2021-10-02T19:14:51.983Z] Client: password auth failed    
[2021-10-02T19:14:51.983Z] Outbound: Sending USERAUTH_REQUEST (keyboard-interactive)
[2021-10-02T19:14:52.007Z] Inbound: Received USERAUTH_INFO_REQUEST
##### Received keyboardInteractiveCallback ##########
Do you accept and acknowledge the statement above ? (yes/no) : 
Seding yes
[2021-10-02T19:14:52.013Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.025Z] Inbound: Received USERAUTH_INFO_REQUEST
##### Received keyboardInteractiveCallback ##########
Password: 
[2021-10-02T19:14:52.025Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.064Z] Inbound: Received USERAUTH_INFO_REQUEST
[2021-10-02T19:14:52.064Z] Client: Sending automatic USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.064Z] Outbound: Sending USERAUTH_INFO_RESPONSE
[2021-10-02T19:14:52.072Z] Inbound: Received USERAUTH_SUCCESS
[2021-10-02T19:14:52.074Z] Outbound: Sending CHANNEL_OPEN (r:0, session)
[2021-10-02T19:14:52.075Z] Socket ended
[2021-10-02T19:14:52.077Z] Socket closed

I hope that it is clear now, but I'm not sure if you can do something with that.

mscdex commented 2 years ago

There isn't anything here that can be solved by ssh2. I suggest using a function for authHandler if you want to handle authentication dynamically. Perhaps you might listen for the 'banner' event and look for familiar keywords do detect which kind of system you're on if you want to go that route. Otherwise you will just need to get more information in one way or another about the destination server in order to properly authenticate the way it expects.