Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MS-NRPC users enumeration module #19205

Merged
merged 11 commits into from
Jun 24, 2024

Conversation

sud0Ru
Copy link
Contributor

@sud0Ru sud0Ru commented May 27, 2024

Adding a new module for enumerating domain users without authentication . The method leverages auth-level = 1 (No authentication) against the MS-NRPC (Netlogon) interface on domain controllers.
The module depends on my last research https://github.com/sud0Ru/Publications/blob/master/Make_Null_Session_Great_Again.pdf

@smcintyre-r7 smcintyre-r7 added module docs rn-modules release notes for new or majorly enhanced modules labels May 29, 2024
@smcintyre-r7 smcintyre-r7 self-assigned this May 29, 2024
)
end

class DsrGetDCNameEx2Request < BinData::Record
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind putting this in rapid7/ruby_smb? We're trying to keep our definitions together so when another module or library needs to make this call, it'll be where we'll look for it. Due to how BinData registers names globally, if someone else were to define their own DsrGetDCNameEx2Request class, there would be a conflict and someone's code wouldn't work.

You can see an example here: https://github.com/rapid7/ruby_smb/blob/master/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb

require 'ruby_smb/dcerpc/ndr'

module RubySMB
  module Dcerpc
    module Netlogon

      # [3.5.4.3.1 DsrGetDcNameEx2 (Opnum 34)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/fb8e1146-a045-4c31-98d1-c68507ad5620)
      class NetrServerAuthenticate3Request < BinData::Record
        attr_reader :opnum

        endian :little

        uint32           :computer_name
        logonsrv_handle  :account_name
        uint32           :allowable_account_control_bits, initial_value: 0x200
        uint32           :domain_name
        uint32           :guid
        uint32           :site_name
        uint32           :flags

        def initialize_instance
          super
          @opnum = DSR_GET_DC_NAME_EX2
        end
      end
    end
  end
end

All of the unit32 fields should be ndr_uint32 fields and I was going to change them, however based on the definition in MSDN, it looks like they are incorrectly defined. My guess is they're working because you're not passing string values, so leaving them as integers represents that they're null. Since you need this request in the module though, it should really be defined correctly.

I'm guessing the computer_name field should be logonsrv_handle while account_name should be ndr_wide_stringz_ptr. You're using logonsrv_handle for account_name right now when it shouldn't be but you can see here that it's actually just NdrWideStringzPtr anyways.

Also note that the DSR_GET_DC_NAME_EX2 constant should be defined in netlogon.rb here.

Loading the changes

Once you've done that, it can be a bit tricky to load your changes into Metasploit. I would submit the PR to rapid7/ruby_smb, then you'd go into your Gemfile and at the very end add the following lines which assume that ruby_smb is cloned next to metasploit-framework.

gem 'ruby_smb', path: '../ruby_smb'

With that in place you can run bundle install and it'll incorporate your changes for testing this PR.

Copy link
Contributor Author

@sud0Ru sud0Ru May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review. Indeed, you are right. I tried to approach it this way from the beginning (defining the call as you suggested), but I had problems with the data types. For example, inside the call that you suggested, according to Microsoft, the ComputerName should be wchar_t*. When I checked the corresponding value in the Metasploit implementation, I found it defined as ndr_conf_var_wide_stringz. When I tried this datatype with my call, it didn't work (the NDR level had a problem with pointing to the actual data). For this reason, I thought there was a problem defining the datatype itself in Metasploit. So, I decided to make the call work inside the module by passing most of the arguments as uint32 because they are NULL.

However, the datatype you mentioned, ndr_wide_stringz_ptr, seems to work well.

I have some questions:

1- Where can I find some documentation about the data types you use for DCERPC? For example, I couldn't find anything related to NULL and GUID*.

2- I believe if we implement the request, we should also implement the response, which requires some work because the return value will be this struct. Is there a way to avoid that (because in my module I'm only getting the last four bytes that represent the flag)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I find some documentation about the data types you use for DCERPC? For example, I couldn't find anything related to NULL and GUID*.

We document most things in YARD, but I'm sure there's many gaps. I don't think we have API docs published but you may be able to build them. I just look through the source when I need to find the types and check the names. Most of the primitives are going to be defined in ndr.rb.

You're right about the types not lining up with the MSDN docs exactly as they're defined. This is a known limitation with the MSDN definitions that I don't know a way around. You'll see in RubySMB, that the requests and responses both refer to a single structure but all the fields labeled [out] are only present in the response. You kind of just have to try different NDR fields until they work.

I believe if we implement the request, we should also implement the response, which requires some work because the return value will be this struct. Is there a way to avoid that (because in my module I'm only getting the last four bytes that represent the flag)?

Having the response would be ideal but as you said because you're only checking the error status I think it's reasonable if you wanted to skip it. The important thing is you're not defining a NetrServerAuthenticate3Response structure that's incorrect or incomplete.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to our decision, I implemented the DCERPC request as we discussed and tried to implement the response, but encountered a problem. I have created a PR for this, aiming to merge the request and discuss the response. However, it has been almost a week, and there is still no feedback on the PR. I wanted to ask if this delay is normal or if there might be an issue.

modules/auxiliary/gather/nrpc_enumusers.rb Outdated Show resolved Hide resolved
documentation/modules/auxiliary/gather/nrpc_enumusers.md Outdated Show resolved Hide resolved
def enumerate_user(username)
response = dsr_get_dc_name_ex2(username)
if response[-4, 4] == "\x00\x00\x00\x00"
print_good("#{username} exists")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should report the username so it's added to the database if the database is connected. I would suggest using something very similar to the smb_enumusers module.

def report_username(domain, username)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is really similar to the auxiliary/scanner/smb/smb_enumusers module, it would make sense to move this to auxiliary/scanner/dcerpc/nrpc_enumusers because they're both scanners and this is using the MS-NRPC interface directly over DCERPC.

@smcintyre-r7
Copy link
Contributor

Alright, now that ruby_smb 3.3.9 has been landed with your new NDR changes you need to bump it here to pull them in. Take a look at this commit which bumps it to 3.3.8. You need that but for 3.3.9. With that in place you should be able to do bundle install and then start to use the definitions that have been added to RubySMB.

Let me know if you have any questions or run into any issues.

@sud0Ru
Copy link
Contributor Author

sud0Ru commented Jun 18, 2024

@smcintyre-r7
I just noticed that there is secret detection? what does that meaning and how can I pass this check?

@adfoster-r7
Copy link
Contributor

That can be ignored 👍

include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::DCERPC
Netlogon = RubySMB::Dcerpc::Netlogon
@@dport = nil
Copy link
Contributor

@smcintyre-r7 smcintyre-r7 Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you changed this from @dport to @@dport, making it a class variable. I'm pretty sure what you want here is an instance variable @dport not a class variable. Making it a class variable would mean that if the module is run multiple times against multiple targets simultaneously, they would share this one value. Using an instance variable would make sure they each have their own value, which is what we want.

Was there an issue with how you had it before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry some typo here while I was trying to replace some strings using some automation. Yeah you are totally right, it should be changed back.

@smcintyre-r7
Copy link
Contributor

it would make sense to move this to auxiliary/scanner/dcerpc/nrpc_enumusers

I see it looks like you filled this request but the old files are still present and should be removed.

It also looks like we bumped RubySMB already in e10d8e2 so this comment should no longer be necessary as long as it's not preventing you from testing your code.

So to get this finished up, I think we just need the extra files removed and the class variable changed back to an instance variable.

@sud0Ru
Copy link
Contributor Author

sud0Ru commented Jun 18, 2024

@smcintyre-r7
I've deleted the old files and changed back the variable, but I did it from the browser because don't have access to my machine at this period of time so hope everything is going okay

@smcintyre-r7
Copy link
Contributor

@msjenkins-r7 test this please.

@smcintyre-r7 smcintyre-r7 force-pushed the add-msnrpc-users-enumeration-module branch from c7a05f9 to 858a2f8 Compare June 24, 2024 22:22
Copy link
Contributor

@smcintyre-r7 smcintyre-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed up two changes to finish this up. The first in commit 3794285 bumps the version of RubySMB to pull in the changes with the new definition, and the second is 858a2f8 to fix the issues that Rubocop had flaggged.

Thank you very much for your work on this, I know the DCERPC definitions aren't the easiest thing to write.

Testing output:

msf6 auxiliary(gather/ldap_query) > use nrpc_enumuser

Matching Modules
================

   #  Name                                     Disclosure Date  Rank    Check  Description
   -  ----                                     ---------------  ----    -----  -----------
   0  auxiliary/scanner/dcerpc/nrpc_enumusers  .                normal  No     MS-NRPC Domain Users Enumeration


Interact with a module by name or index. For example info 0, use 0 or use auxiliary/scanner/dcerpc/nrpc_enumusers

[*] Using auxiliary/scanner/dcerpc/nrpc_enumusers
msf6 auxiliary(scanner/dcerpc/nrpc_enumusers) > show options 

Module options (auxiliary/scanner/dcerpc/nrpc_enumusers):

   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   DB_ALL_USERS  false            no        Add all enumerated usernames to the database
   RHOSTS        3.22.14.197      yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT                          no        The netlogon RPC port (TCP)
   THREADS       1                yes       The number of concurrent threads (max one per host)
   USER_FILE     /tmp/users.txt   yes       Path to the file containing the list of usernames to enumerate


View the full module info with the info, or info -d command.

msf6 auxiliary(scanner/dcerpc/nrpc_enumusers) > run

[*] 3.22.14.197: - Connecting to the endpoint mapper service...
[*] 3.22.14.197: - Binding to 12345678-1234-abcd-ef00-01234567cffb:1.0@ncacn_ip_tcp:3.22.14.197[49664]...
[-] 3.22.14.197: - Jack does not exist
[-] 3.22.14.197: - Spencer does not exist
[+] 3.22.14.197: - aliddle exists -> DC: \\SRV-ADDS01.labs1collabu0.local
[+] 3.22.14.197: - Administrator exists -> DC: \\SRV-ADDS01.labs1collabu0.local
[-] 3.22.14.197: - Jackson does not exist
[-] 3.22.14.197: - Sophie does not exist
[-] 3.22.14.197: - Jake does not exist
[-] 3.22.14.197: - Murrey does not exist
[+] 3.22.14.197: - smcintyre exists -> DC: \\SRV-ADDS01.labs1collabu0.local
[-] 3.22.14.197: - Blythe does not exist
[*] 3.22.14.197: - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/dcerpc/nrpc_enumusers) > 

@smcintyre-r7 smcintyre-r7 merged commit a5afdd6 into rapid7:master Jun 24, 2024
78 checks passed
@smcintyre-r7
Copy link
Contributor

Release Notes

This adds a new module that can enumerate accounts on a target Active Directory Domain Controller without authenticating to it by issuing a DCERPC request and analyzing the returned error status.

@sud0Ru
Copy link
Contributor Author

sud0Ru commented Jun 25, 2024

Thank you for your help also :) it was pleasure to work with u

@adfoster-r7
Copy link
Contributor

Nice work @sud0Ru ! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants