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 Group Policy Preferences (creds) support to db_import #10507

Merged
merged 5 commits into from
Aug 28, 2018

Conversation

wvu
Copy link
Contributor

@wvu wvu commented Aug 22, 2018

And take the Jaden Smith approach, as @busterb quipped to me. :)

This one's a little weird, since you normally import scans into Metasploit, but now that creds are first-class in the database, it makes more sense to be able to import them.

Currently, your alternatives are post/windows/gather/credentials/gpp, which requires a session, and auxiliary/scanner/smb/smb_enum_gpp, which requires a network scan.

msf5 > db_import Groups.xml
[*] Importing 'Group Policy Preferences Credentials' data
[*] Successfully imported /Users/wvu/metasploit-framework/Groups.xml
msf5 > creds
Credentials
===========

host  origin  service  public   private  realm  private_type
----  ------  -------  ------   -------  -----  ------------
                       DbAdmin  demo            Password

msf5 > loot

Loot
====

host  service  type                   name        content   info                                                                                                   path
----  -------  ----                   ----        -------   ----                                                                                                   ----
               microsoft.windows.gpp  Groups.xml  text/xml  [{:USER=>"DbAdmin", :PASS=>"demo", :CHANGED=>"2007-07-06 20:45:20", :NEVER_EXPIRES=>0, :DISABLED=>1}]  /Users/wvu/metasploit-framework/Groups.xml

msf5 >

https://msdn.microsoft.com/en-us/library/cc232652.aspx

wvu@kharak:~$ echo -n demo | iconv -t UTF-16LE | openssl enc -aes-256-cbc -a -p -iv "" -K 4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b -nosalt
key=4E9906E8FCB66CC9FAF49310620FFEE8F496E806CC057990209B09A433B66C1B
iv =00000000000000000000000000000000
kHB0+HMUTs/6ySSZ8usxXg==
wvu@kharak:~$ openssl enc -aes-256-cbc -d -a -p -iv "" -K 4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b -nosalt <<<kHB0+HMUTs/6ySSZ8usxXg==
key=4E9906E8FCB66CC9FAF49310620FFEE8F496E806CC057990209B09A433B66C1B
iv =00000000000000000000000000000000
demowvu@kharak:~$
<?xml version="1.0" encoding="utf-8"?>
 <Groups   clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"
           disabled="1">
   <User   clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}"
           name="DbAdmin"
           image="2"
           changed="2007-07-06 20:45:20"
           uid="{253F4D90-150A-4EFB-BCC8-6E894A9105F7}">
     <Properties
           action="U"
           newName=""
           fullName="Database Admin"
           description="Local Database Admin"
           cpassword="kHB0+HMUTs/6ySSZ8usxXg=="
           changeLogon="0"
           noChange="0"
           neverExpires="0"
           acctDisabled="1"
           userName="DbAdmin"/>
   </User>
   <Group  clsid="{6D4A79E4-529C-4481-ABD0-F5BD7EA93BA7}"
           name="Database Admins"
           image="2"
           changed="2007-07-06 20:46:21"
           uid="{C5FB3901-508A-4A9E-9171-60D4FC2B404B}">
     <Properties
           action="U"
           newName=""
           description="Local Database Admins"
           userAction="REMOVE"
           deleteAllUsers="1"
           deleteAllGroups="1"
           removeAccounts="0"
           groupName="Database Admins">
       <Members>
         <Member
           name="domain\sampleuser"
           action="ADD"
           sid=""/>
       </Members>
     </Properties>
   </Group>
 </Groups>

And take the Jaden Smith approach, as @busterb quipped to me. :)

This one's a little weird, since you normally import scans into
Metasploit, but now that creds are first-class in the database, it makes
more sense to be able to import them.

Currently, your alternatives are post/windows/gather/credentials/gpp,
which requires a session, and auxiliary/scanner/smb/smb_enum_gpp, which
requires a network scan.
@jmartin-tech
Copy link
Contributor

jmartin-tech commented Aug 22, 2018

I get that this imports creds that happen to be provided by group policy but the naming here infers it would import so much more. Consider things like password policy, and default softwares installed would also have value from a reconnaissance view. While framework does not really take advantage of theses items yet it could be a future goal of this importer.

If we think those are not viable options for expansion here, then I would suggest that something like Group Policy Credentials or GPO Creds as the import type to be clear the purpose of the importer. May be a good idea be explicit on the current scope and generalize the name if/when more things are parsed from the objects.

return unless wspace && wspace.respond_to?(:id)

gpp.each do |p|
create_credential(
Copy link
Contributor

Choose a reason for hiding this comment

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

The end result is still the same, but I think it's interesting that you used the Auxiliary::Report methods here instead of the DbManager methods directly since you're already in DbManager

Copy link
Contributor Author

@wvu wvu Aug 22, 2018

Choose a reason for hiding this comment

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

Probably habit. Misread, sleepy brain. I explicitly did not include the Msf::Auxiliary::Report mixin. Wrong context for that, IMHO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though I do remember checking this and thought they were coming from DBManager:

def create_credential(opts={})
if active_db?
framework.db.create_credential(opts)
elsif !db_warning_given?
vprint_warning('No active DB -- Credential data will not be saved!')
end
end

[1] pry(#<Msf::DBManager>)> method(:create_credential)
=> #<Method: Msf::DBManager(Metasploit::Credential::Creation)#create_credential>
[2] pry(#<Msf::DBManager>)>

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh yeah, I see it now. I guess I should parse all of the search results instead of just the ones that confirm my suspicions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same reason I used report_loot below instead of store_loot from Msf::Auxiliary::Report:

[2] pry(#<Msf::DBManager>)> method(:report_loot)
=> #<Method: Msf::DBManager(Msf::DBManager::Loot)#report_loot>
[3] pry(#<Msf::DBManager>)>

Also, the file to be imported still exists on disk, and its data is stored in the database all the same. It would be helpful to be able to retrieve that data and write it to a file. That's been a long-standing complaint I've had with the loot command.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Appreciate the review! Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

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

So you actually can retrieve the data and write it to a file with the REST API. If you request the loot from there it returns a data field with the file contents base64 encoded.

It's actually stored in the database as well, there's just no easy way to get access to it from msfconsole without dropping to irb. Definitely something we can add in the future, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, most of us use the console. I've been getting the data via pry or irb, but it's less than ideal. The REST API is nice for programmatic interaction, but I don't see us running curl commands every time we want to retrieve loot data.

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 think it's good we're moving away from the "expert user" experience. I can't reasonably tell someone they should be writing Ruby to retrieve data for a pentest.

Copy link
Contributor Author

@wvu wvu Aug 22, 2018

Choose a reason for hiding this comment

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

Sample file moved to PR description.

@wvu
Copy link
Contributor Author

wvu commented Aug 22, 2018

Solid point, @jmartin-r7. I'd love to expand this to fill what's expected from a db_import importer. Since this was a first pass with creds, I'll rename the type to reflect that. Thanks! I was already storing metadata in loot, so that should be enough. The parser is insufficient to keep the name.

workspace_id: wspace.id,
origin_type: :import,
filename: args[:filename],
username: p[:USER],
Copy link
Contributor Author

@wvu wvu Aug 22, 2018

Choose a reason for hiding this comment

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

While we're at it, these values should be checked for existence each loop. Done.

And refactor slightly.
A bit of misunderstanding. We're in agreement that loot was enough.
Since the parser is focused on creds.
@wvu wvu changed the title Add Group Policy Preferences support to db_import Add Group Policy Preferences (creds) support to db_import Aug 22, 2018
@wvu
Copy link
Contributor Author

wvu commented Aug 22, 2018

I've updated the import type to suggest that the focus is on creds. We can flesh out the parser and update the type later. Thanks, @jmartin-r7.

report_loot(
workspace: wspace,
path: args[:filename],
name: File.basename(args[:filename]),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure I see the point of this if it's just the basename. But it fills in a column.

@wvu
Copy link
Contributor Author

wvu commented Aug 22, 2018

All right, I think this is ready to go.

@@ -0,0 +1,41 @@
require 'rex/parser/group_policy_preferences'

module Msf::DBManager::Import::GPP
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'm leaving the name as GPP for future expansion... and I'm more liable to screw up the rename now.

@busterb busterb assigned busterb and unassigned busterb Aug 24, 2018
@wvu
Copy link
Contributor Author

wvu commented Aug 28, 2018

Handling this myself, since there are no takers. It's been okayed by a couple folks.

@wvu wvu merged commit 9b3e0d8 into rapid7:master Aug 28, 2018
wvu added a commit that referenced this pull request Aug 28, 2018
@wvu
Copy link
Contributor Author

wvu commented Aug 28, 2018

Release Notes

Database import (creds and loot) of Group Policy Preferences credentials via the db_import command has been added.

@wvu wvu deleted the feature/gpp branch August 28, 2018 17:01
msjenkins-r7 pushed a commit that referenced this pull request Aug 28, 2018
@tdoan-r7 tdoan-r7 added the rn-enhancement release notes enhancement label Sep 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants