Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Get the "Authentication Error" as soon as possbile #290

Answered by Eathan2311
Eathan2311 asked this question in Q&A
Discussion options

Hi,
I want to develop an SSH-weak-password detect tool.
There are about 100K servers to be detected, so, when I try to loggin an SSH host I want to get the result (success or fail) as soon as posssible.
When I use the corrent username and pwd (root/root), the response time consumption is about 10ms:

start = time.time()
try:
 client = SSHClient('192.168.1.5',
 user='root',
 password='root',
 num_retries=0,
 timeout=0
 )
except pssh.exceptions.AuthenticationError as AE:
 print(AE)
print(time.time() - start)

or

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('192.168.1.5', 22))
s = Session()
s.handshake(sock)
start_time = time.time()
try:
 s.userauth_password('msfadmin', 'msfadmin')
except:
 pass
print(time.time() - start_time)

But when I try the incorrect usernames&passwords (root/r00t, admin/admin, root/root1, ...), it would use about 2s to respond an AuthenticationError. It's too slow to scan over 100K servers.
Can you tell me how to solve this: when the username or password is wrong, how I can get the Error response (or I can know the username&password is wrong) immediately and I can try the next username and password suite.
Thank you very much.

You must be logged in to vote

@pkittenis, Can you help me, pls?
Thank you.

Replies: 2 comments 2 replies

Comment options

@pkittenis, Can you help me, pls?
Thank you.

You must be logged in to vote
1 reply
Comment options

Hi there,

Thanks for the interest. Couple things:

  • Use the parallel client for doing things on multiple hosts
  • Disable authentication methods not needed
  • Timeout 0 means no timeout. Use a low value.
from pssh.clients import ParallelSSHClient
client = ParallelSSHClient(['192.168.1.5', <..>],
 user='root',
 password='root',
 num_retries=1,
 timeout=1,
 identity_auth=False,
 agent_auth=False,
 )
out = client.run_command('echo me', stop_on_errors=False)
for host_out in out:
 if host_out.exception is not None:
 print(host_out.host, host_out.exception)

It will still be slower than just opening the socket. Servers need to respond to the auth requests.

See also ParallelSSHClient.connect_auth.

Answer selected by pkittenis
Comment options

Thank you for the reply. @pkittenis

I'm trying to find a way to let the client know that it has used the wrong username/password as soon as posssible.

As we know, the SSH connection steps are as follows:

1, Client: creates a TCP socket (denoted by TCP-S) connected to Server on port 22;
Server: blahblah ...
Client: blahblah ...

Then, they exchange and share a session key (denoted by SK) to each other.

2, Client: encryptes "root/root" (or encryptes "root/r00t") with SK, and sends the cyphertext to Server.

3, Server: decryptes the cyphertext with SK, verifies the plaintext, and then tells Client: "yes, root/root is correct and you can access me", or "root/r00t is wrong ...".

4, Client: knows root/root is correct (or root/r00t is wrong).

5, Some followup steps ...

Is there a method satisfied that: when the client knows root/r00t is wrong, it will do nothing with the followup steps but continues to use TCP-S to loggin with "root/123456", "root/1111111", "admin/admin", and so on?

1, Clients: TCP-S = socket(host = 192.168.1.5, port = 22)
2, Server: blahblah ...
Client: blahblah ...
Server & Client: share the SK (session key)
3, Client: loggin the Server with "root/root" (of course, "root/root" is encrypted with SK), or with "root/r00t".
4. Client: recv_from(TCP-S), and knows "root/root" is right (or knows "root/r00t" is wrong).
5. Client: (1)Break, because it knows that the root/root is right, (2)Continues to try admin/admin with TCP-S (avoid another new TCP connection), and goes on.

Thank you so much.

You must be logged in to vote
1 reply
Comment options

For the parallel client can use HostConfig to provide per-host authentication and check successful hosts, eg something like:

configs = [HostConfig(user="root", password="r00t"), HostConfig(user="root", password="r00t")]
client = ParallelSSHClient(['192.168.1.5', <..>],
 num_retries=1,
 timeout=1,
 identity_auth=False,
 agent_auth=False,
 host_config=configs,
 )
success_clients = joinall(client.connect_auth())
success_hosts = [cl.host for cl in success_clients]
failed_hosts_i = [host_i for host_i, host in enumerate(client.hosts) 
 if host not in success_hosts]
for host_i in failed_hosts_i:
 configs[host_i] = HostConfig(user="my new user", password="my new pass")
success_clients = joinall(client.connect_auth())
<check again for failed hosts>

configs[host_i] is always the config for client.hosts[host_i].

This will keep connection to successful hosts and only create new connections and retry auth on failed hosts.

It is not possible via public parallel client API to maintain the same socket connection on failed hosts and retry authentication. Servers lock clients out after X failed attempts, this would not work well.

You could use the single host SSHClient and do all the parallel stuff manually via spawn and etc if you really want to do that. Can then keep retrying with SSHClient.auth directly on each failure.

See also Per-host Configuration documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /