At SynerComm's Fall IT Summit 2018 we presented a talk about the top 5 attacks used to compromise a Domain Administrator account. As a short recap, the top five are the following:

  1. Permissive Global Group Access + mimikatz

    This is the classic case where a Domain Administrator logs into a machine where Domain Users group is a local administrator. Any user on the network can then log into the machine and extract the administrator's password from memory.

  2. LLMNR and NBT-NS Poisoning

    LLMNR and NBT-NS can be used to hijack the NTLMv2 hash for users who mistype the name of an SMB share of HTTP address.

  3. SYSVOL Passwords + Leaked AES Keys

    Although this vulnerability came out years ago, many companies still have cpassword fields in their SYSVOL XML files that can be decrypted using the Microsoft leaked AES key.

  4. Kerberoasting

    Due to Microsoft’s implementation of the Kerberos protocol, any domain account can get the krb5tgt hash for a domain user used as a service. Strong passwords must be enforced on these accounts.

  5. DC Backups

    If the backup file of a domain controller is discovered on a share that is not properly secured it is trivial to extract the NTDS.dit database and pull all the NTLM hashes for the domain.

The AssureIT team put together a list of tools to help you check for these vulnerabilities in your network. The presentation file and the self-audit kit can be found here:


On August 15th, 2018 a vulnerability was posted on the OSS-Security list. This post explained that OpenSSH (all versions prior to and including 7.7) is vulnerable to username enumeration by sending a malformed public key authentication request (SSH2_MSG_USERAUTH_REQUEST with type "publickey") to the service. Upon receiving this request, the server would validate the user THEN check if the request was well-formed. As a result, if an invalid user was requested the OpenSSH service would return a SSH2_MSG_USERAUTH_FAILURE indicating the server rejected the request due to an invalid username. However, if a valid user was requested the server would simply close the connection because the request was malformed.

This behavior was caused by the following code:

  87 static int
  88 userauth_pubkey(struct ssh *ssh)
  89 {
 101         if (!authctxt->valid) {
 102                 debug2("%s: disabled because of invalid user", __func__);
 103                 return 0;
 104         }
 105         if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
 106             (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
 107             (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
 108                 fatal("%s: parse request failed: %s", __func__, ssh_err(r));

On lines 101-103 you can see that the program checks to see if the user is valid, and if it is not, returns 0, which gets turned into a SSH2_MSG_USERAUTH_FAILURE. However, per lines 105-108, if the server fails to validate the SSH request it then calls “fatal” and exits the process without responding to the client. This allows us to determine whether a user is valid.

I wrote the following code as a means to exploit the aforementioned vulnerability. The code is roughly based off of my own research into the vuln and the POC provided by Matthew Daley.

There were several challenges while writing this exploit. As demonstrated by Matthew Daley in his POC, the easiest way to corrupt the packet is to override the Paramiko Message object’s add_boolean function. However, once the first request is sent the original status of add_boolean must be returned or else calling Transport.start_client() to initiate another connection will fail. According to some messages I received, that stumped several other exploit developers trying to create a similar exploit.

Another challenge was that the OpenSSH sever would occasionally be overwhelmed by the influx of SSH requests causing it to refuse to negotiate the SSH transport. When this occurs, the exploit automatically attempts to retry to a max number of 3 times.

Justin ( @Rhynorater )

GitHub repo:

└──╼ $python --help
usage: [-h] [--port PORT] [--threads THREADS]
                                 [--outputFile OUTPUTFILE]
                                 [--outputFormat {list,json,csv}]
                                 (--username USERNAME | --userList USERLIST)
positional arguments:
  hostname              The target hostname or ip address
optional arguments:
  -h, --help            show this help message and exit
  --port PORT           The target port
  --threads THREADS     The number of threads to be used
  --outputFile OUTPUTFILE
                        The output file location
  --outputFormat {list,json,csv}
                        The output file location
  --username USERNAME   The single username to validate
  --userList USERLIST   The list of usernames (one per line) to enumerate through
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram