-
Notifications
You must be signed in to change notification settings - Fork 13.9k
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
Add MS-NRPC users enumeration module #19205
Conversation
) | ||
end | ||
|
||
class DsrGetDCNameEx2Request < BinData::Record |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
def enumerate_user(username) | ||
response = dsr_get_dc_name_ex2(username) | ||
if response[-4, 4] == "\x00\x00\x00\x00" | ||
print_good("#{username} exists") |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
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 Let me know if you have any questions or run into any issues. |
Co-authored-by: Spencer McIntyre <58950994+smcintyre-r7@users.noreply.github.com>
@smcintyre-r7 |
That can be ignored 👍 |
include Msf::Auxiliary::Scanner | ||
include Msf::Exploit::Remote::DCERPC | ||
Netlogon = RubySMB::Dcerpc::Netlogon | ||
@@dport = nil |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
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. |
@smcintyre-r7 |
@msjenkins-r7 test this please. |
c7a05f9
to
858a2f8
Compare
There was a problem hiding this 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) >
Release NotesThis 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. |
Thank you for your help also :) it was pleasure to work with u |
Nice work @sud0Ru ! 🎉 |
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