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 definitions for three new EFS RPC requests and responses #248

Merged
merged 5 commits into from
Mar 9, 2023

Conversation

zeroSteiner
Copy link
Contributor

This adds definitions for the following three EFS RPC methods. They'll be required by updates to the petitpotam module I will submit to Metasploit soon.

The easiest way to test this will be with the new petitpotam module changes which will add each of these in as a new method that can be selected. More detailed steps will be posted in that PR.

@cdelafuente-r7 cdelafuente-r7 self-assigned this Mar 8, 2023
Copy link
Contributor

@cdelafuente-r7 cdelafuente-r7 left a comment

Choose a reason for hiding this comment

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

Thanks for adding these structures @zeroSteiner ! I just left one comment about a possible mismatch between a pointer to a conformant array and a varying array field. Other than that, it looks good to me.

default_parameter byte_align: 4

uint32 :ncert_hash
ndr_var_array :users, type: :encryption_certificate_hash_ptr
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the specs, this fields seems to be a pointer:

A pointer to an array of pointers to ENCRYPTION_CERTIFICATE_HASH (2.2.10) structures.

I think this field is a pointer to a conformant array instead of a varying array. This is usually the case when the MIDL definition uses the size_is() attribute:

   [size_is(nCert_Hash,)] ENCRYPTION_CERTIFICATE_HASH** Users;

This attribute controls the amount of memory allocated for the data, which correspond to the NDR conformant array max_count value.

I believe using a varying array here still works since he number of bytes is equal in both cases:

  • pointer to conformant array: [ uint32 ref_id ] [ uint32 max_count ] [ element 1 ] [ ... ]
  • varying array: [ uint32 offset ] [ uint32 actual_count ] [ element 1 ] [ ... ]

I haven't tested it yet, but one way to make sure my assumption is correct, is to inspect a packet that comes from a proper Windows host, which contains this structure. The second uint32 will always be the size of the array wether it is conformant or a varying. However, the first uint32 is usually 0x00000000 in case of a varying array (offset) and a correct ref_id for a pointer to a conformant array (usually 0x0002000, 0x0002004, 0x0002008, etc.).

Note that a pointer to a conformant array have specific sets of rules defined by the NDR syntax, which are different than a simple varying array when they are inserted in other constructed types like structures or arrays. It is not the case here, but if we want to reuse it, this can have some unwanted side effects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, yeah I think you're right. Nice catch I'll get this switched over.

For reference, I was using this script for test parsing an empty and populated response:

test_efs.rb
#!/usr/bin/ruby

# This script tests a full Authentication/Session Setup cycle
# including protocol negotiation and authentication.

require 'bundler/setup'
require 'ruby_smb'

empty = "\x00\x00\x00\x005\x00\x00\x00".b
# file_name: "\\\\localhost\\C$\\Users\\smcintyre\\Desktop\\Encrypted\\hello world.txt"
populated =  "\x00\x00\x02\x00".b
populated << "\x01\x00\x00\x00".b
populated << "\x04\x00\x02\x00\x01\x00\x00\x00\b\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\f\x00\x02\x00\x14\x00\x02\x00\x14\x00\x00\x00\x10\x00\x02\x00\x14\x00\x00\x00\x15\xC9\xADB\x8A\x8Au\x10Lk\xDC}7v\n\xA1\xBD{\x00/\"\x00\x00\x00\x00\x00\x00\x00\"\x00\x00\x00s\x00m\x00c\x00i\x00n\x00t\x00y\x00r\x00e\x00(\x00s\x00m\x00c\x00i\x00n\x00t\x00y\x00r\x00e\x00@\x00m\x00s\x00f\x00l\x00a\x00b\x00.\x00l\x00o\x00c\x00a\x00l\x00)\x00\x00\x00\x00\x00\x00\x00".b

$stderr.puts 'empty:'
BinData::trace_reading do
    empty = RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcQueryRecoveryAgentsResponse.read(empty)
end
$stderr.puts empty.inspect

$stderr.puts 'populated:'
BinData::trace_reading do
    populated = RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcQueryRecoveryAgentsResponse.read(populated)
end
$stderr.puts populated.inspect

With your changes implemented, the output does make more sense:

...
populated:
obj.recover_agents.ref_id => 131072
obj.recover_agents.ncert_hash => 1
obj.recover_agents.users.ref_id => 131076
obj.recover_agents.users.max_count => 1
obj.recover_agents.users[0].ref_id => 131080
obj.recover_agents.users[0].cb_total_length => 32
obj.recover_agents.users[0].user_sid.ref_id => 0
obj.recover_agents.users[0].certificate_hash.ref_id => 131084
...

vs this with the offset field that was confusing me.

...
populated:
obj.recover_agents.ref_id => 131072
obj.recover_agents.ncert_hash => 1
obj.recover_agents.users.offset => 131076
obj.recover_agents.users.actual_count => 1
obj.recover_agents.users[0].ref_id => 131080
obj.recover_agents.users[0].cb_total_length => 32
obj.recover_agents.users[0].user_sid.ref_id => 0
obj.recover_agents.users[0].certificate_hash.ref_id => 131084
...

Copy link
Contributor

Choose a reason for hiding this comment

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

Absolutely, it makes sense. The pointer's ref_id's now follow the expected pattern: 131072, 131076, 131080 and 131084 (in hex: 0x00020000, 0x00020004, 0x00020008, 0x0002000C). Thanks for looking into this.

@cdelafuente-r7
Copy link
Contributor

Thanks for updating this. I tested using the new PetitPotam module changes and everything looks good. I'll go ahead and land it.

@cdelafuente-r7 cdelafuente-r7 merged commit e4851df into rapid7:master Mar 9, 2023
@cdelafuente-r7
Copy link
Contributor

cdelafuente-r7 commented Mar 9, 2023

Release Notes

This adds definitions for the EfsRpcDecryptFileSrv, EfsRpcQueryRecoveryAgents and EfsQueryUsersOnFile` EFS RPC methods. They'll be required by the Metasploit PetitPotam module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DCERPC DCERPC related enhancement
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants