Pennyw0rth / NetExec

The Network Execution Tool
https://netexec.wiki/
BSD 2-Clause "Simplified" License
3.29k stars 361 forks source link

SSH Module exception: "q must be exactly 160, 224, or 256 bits long" when authenticated with privatekey #410

Open nikaiw opened 2 months ago

nikaiw commented 2 months ago

Describe the bug when connecting with a publickey paramiko may trigger an exception. It seems that it try to parse a key as DSA when it fail to use it as RSA. The exception is not catched by netexec

To Reproduce netexec ssh host -u user --key-file private.key -p ''

[18:01:30] ERROR    q must be exactly 160, 224, or 256 bits long                                                                                                                                                                   ssh.py:238
                    ╭──────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────────────────────────────╮           
                    │ /home/user/.local/lib/python3.10/site-packages/nxc/protocols/ssh.py:192 in plaintext_login                                                                                                                 │           
                    │                                                                                                                                                                                                            │           
                    │   189 │   │   │   if self.args.key_file or private_key:                                                                                                                                                    │           
                    │   190 │   │   │   │   self.logger.debug(f"Logging {self.host} with username: {username},                                                                                                                   │           
                    │       keyfile: {self.args.key_file}")                                                                                                                                                                      │           
                    │   191 │   │   │   │                                                                                                                                                                                        │           
                    │ ❱ 192 │   │   │   │   self.conn.connect(                                                                                                                                                                   │           
                    │   193 │   │   │   │   │   self.host,                                                                                                                                                                       │           
                    │   194 │   │   │   │   │   port=self.port,                                                                                                                                                                  │           
                    │   195 │   │   │   │   │   username=username,                                                                                                                                                               │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/client.py:485 in connect                                                                                                                           │           
                    │                                                                                                                                                                                                            │           
                    │   482 │   │   else:                                                                                                                                                                                        │           
                    │   483 │   │   │   key_filenames = key_filename                                                                                                                                                             │           
                    │   484 │   │                                                                                                                                                                                                │           
                    │ ❱ 485 │   │   self._auth(                                                                                                                                                                                  │           
                    │   486 │   │   │   username,                                                                                                                                                                                │           
                    │   487 │   │   │   password,                                                                                                                                                                                │           
                    │   488 │   │   │   pkey,                                                                                                                                                                                    │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/client.py:734 in _auth                                                                                                                             │           
                    │                                                                                                                                                                                                            │           
                    │   731 │   │   │   │   │   │   │   key_filename, pkey_class, passphrase                                                                                                                                     │           
                    │   732 │   │   │   │   │   │   )                                                                                                                                                                            │           
                    │   733 │   │   │   │   │   │   allowed_types = set(                                                                                                                                                         │           
                    │ ❱ 734 │   │   │   │   │   │   │   self._transport.auth_publickey(username, key)                                                                                                                            │           
                    │   735 │   │   │   │   │   │   )                                                                                                                                                                            │           
                    │   736 │   │   │   │   │   │   two_factor = allowed_types & two_factor_types                                                                                                                                │           
                    │   737 │   │   │   │   │   │   if not two_factor:                                                                                                                                                           │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/transport.py:1674 in auth_publickey                                                                                                                │           
                    │                                                                                                                                                                                                            │           
                    │   1671 │   │   if event is not None:                                                                                                                                                                       │           
                    │   1672 │   │   │   # caller wants to wait for event themselves                                                                                                                                             │           
                    │   1673 │   │   │   return []                                                                                                                                                                               │           
                    │ ❱ 1674 │   │   return self.auth_handler.wait_for_response(my_event)                                                                                                                                        │           
                    │   1675 │                                                                                                                                                                                                   │           
                    │   1676 │   def auth_interactive(self, username, handler, submethods=""):                                                                                                                                   │           
                    │   1677 │   │   """                                                                                                                                                                                         │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/auth_handler.py:248 in wait_for_response                                                                                                           │           
                    │                                                                                                                                                                                                            │           
                    │    245 │   │   │   │   │   e = AuthenticationException(                                                                                                                                                    │           
                    │    246 │   │   │   │   │   │   "Authentication failed: transport shut down or saw EOF"                                                                                                                     │           
                    │    247 │   │   │   │   │   )                                                                                                                                                                               │           
                    │ ❱  248 │   │   │   │   raise e                                                                                                                                                                             │           
                    │    249 │   │   │   if event.is_set():                                                                                                                                                                      │           
                    │    250 │   │   │   │   break                                                                                                                                                                               │           
                    │    251 │   │   │   if max_ts is not None and max_ts <= time.time():                                                                                                                                        │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/transport.py:2220 in run                                                                                                                           │           
                    │                                                                                                                                                                                                            │           
                    │   2217 │   │   │   │   │   │   and ptype in self.auth_handler._handler_table                                                                                                                               │           
                    │   2218 │   │   │   │   │   ):                                                                                                                                                                              │           
                    │   2219 │   │   │   │   │   │   handler = self.auth_handler._handler_table[ptype]                                                                                                                           │           
                    │ ❱ 2220 │   │   │   │   │   │   handler(m)                                                                                                                                                                  │           
                    │   2221 │   │   │   │   │   │   if len(self._expected_packet) > 0:                                                                                                                                          │           
                    │   2222 │   │   │   │   │   │   │   continue                                                                                                                                                                │           
                    │   2223 │   │   │   │   │   else:                                                                                                                                                                           │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/auth_handler.py:404 in _parse_service_accept                                                                                                       │           
                    │                                                                                                                                                                                                            │           
                    │    401 │   │   │   │   │   self.username,                                                                                                                                                                  │           
                    │    402 │   │   │   │   │   algorithm,                                                                                                                                                                      │           
                    │    403 │   │   │   │   )                                                                                                                                                                                   │           
                    │ ❱  404 │   │   │   │   sig = self.private_key.sign_ssh_data(blob, algorithm)                                                                                                                               │           
                    │    405 │   │   │   │   m.add_string(sig)                                                                                                                                                                   │           
                    │    406 │   │   │   elif self.auth_method == "keyboard-interactive":                                                                                                                                        │           
                    │    407 │   │   │   │   m.add_string("")                                                                                                                                                                    │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/paramiko/dsskey.py:112 in sign_ssh_data                                                                                                                     │           
                    │                                                                                                                                                                                                            │           
                    │   109 │   │   return self.x is not None                                                                                                                                                                    │           
                    │   110 │                                                                                                                                                                                                    │           
                    │   111 │   def sign_ssh_data(self, data, algorithm=None):                                                                                                                                                   │           
                    │ ❱ 112 │   │   key = dsa.DSAPrivateNumbers(                                                                                                                                                                 │           
                    │   113 │   │   │   x=self.x,                                                                                                                                                                                │           
                    │   114 │   │   │   public_numbers=dsa.DSAPublicNumbers(                                                                                                                                                     │           
                    │   115 │   │   │   │   y=self.y,                                                                                                                                                                            │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py:242 in private_key                                                                                         │           
                    │                                                                                                                                                                                                            │           
                    │   239 │   │   │   backend as ossl,                                                                                                                                                                         │           
                    │   240 │   │   )                                                                                                                                                                                            │           
                    │   241 │   │                                                                                                                                                                                                │           
                    │ ❱ 242 │   │   return ossl.load_dsa_private_numbers(self)                                                                                                                                                   │           
                    │   243 │                                                                                                                                                                                                    │           
                    │   244 │   def __eq__(self, other: object) -> bool:                                                                                                                                                         │           
                    │   245 │   │   if not isinstance(other, DSAPrivateNumbers):                                                                                                                                                 │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/backend.py:876 in load_dsa_private_numbers                                                                             │           
                    │                                                                                                                                                                                                            │           
                    │    873 │   def load_dsa_private_numbers(                                                                                                                                                                   │           
                    │    874 │   │   self, numbers: dsa.DSAPrivateNumbers                                                                                                                                                        │           
                    │    875 │   ) -> dsa.DSAPrivateKey:                                                                                                                                                                         │           
                    │ ❱  876 │   │   dsa._check_dsa_private_numbers(numbers)                                                                                                                                                     │           
                    │    877 │   │   parameter_numbers = numbers.public_numbers.parameter_numbers                                                                                                                                │           
                    │    878 │   │                                                                                                                                                                                               │           
                    │    879 │   │   dsa_cdata = self._lib.DSA_new()                                                                                                                                                             │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py:283 in _check_dsa_private_numbers                                                                          │           
                    │                                                                                                                                                                                                            │           
                    │   280                                                                                                                                                                                                      │           
                    │   281 def _check_dsa_private_numbers(numbers: DSAPrivateNumbers) -> None:                                                                                                                                  │           
                    │   282 │   parameters = numbers.public_numbers.parameter_numbers                                                                                                                                            │           
                    │ ❱ 283 │   _check_dsa_parameters(parameters)                                                                                                                                                                │           
                    │   284 │   if numbers.x <= 0 or numbers.x >= parameters.q:                                                                                                                                                  │           
                    │   285 │   │   raise ValueError("x must be > 0 and < q.")                                                                                                                                                   │           
                    │   286                                                                                                                                                                                                      │           
                    │                                                                                                                                                                                                            │           
                    │ /home/user/.local/lib/python3.10/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py:275 in _check_dsa_parameters                                                                               │           
                    │                                                                                                                                                                                                            │           
                    │   272 │   │   │   "p must be exactly 1024, 2048, 3072, or 4096 bits long"                                                                                                                                  │           
                    │   273 │   │   )                                                                                                                                                                                            │           
                    │   274 │   if parameters.q.bit_length() not in [160, 224, 256]:                                                                                                                                             │           
                    │ ❱ 275 │   │   raise ValueError("q must be exactly 160, 224, or 256 bits long")                                                                                                                             │           
                    │   276 │                                                                                                                                                                                                    │           
                    │   277 │   if not (1 < parameters.g < parameters.p):                                                                                                                                                        │           
                    │   278 │   │   raise ValueError("g, p don't satisfy 1 < g < p.")                                                                                                                                            │           
                    ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯           
                    ValueError: q must be exactly 160, 224, or 256 bits long         
...

Expected behavior Exception catched and a warning/or error displayed

Screenshots image

NeffIsBack commented 2 months ago

Duplicates: https://github.com/byt3bl33d3r/CrackMapExec/issues/454 https://github.com/paramiko/paramiko/issues/2048 https://github.com/fabric/fabric/issues/2182 https://github.com/fabric/fabric/issues/2140