As you mentioned, we're going to talk about hijacking OAuth tokens in Google Cloud. Good thing about Safe Mode this year is if this is the wrong talk, you can quietly leave and I won't even see you. All right, let's get into it here. So, if you need to get hold of me, just DM me at Twitter. You can usually find me on most of the social platforms. What we're going to cover in this talk is hijacking of OAuth tokens, session tokens, for CLI access, API access, and it's really the ease of attack that we're going to focus on. There's additional use cases related to service accounts and compute instances that we'll look at as well. And from a defensive perspective, we're definitely going to drill into some of the challenges in securing the environment. Really, who cares, right? Well, OAuth is fundamental to Google authentication. It's underneath everywhere. There are some nuances depending on if you are authenticating with user accounts versus service accounts, whether your sessions are from browsers versus SDK access, whether you're external to the GCP environment versus internal, say, on a compute VM. And that is part of what leads to a lot of the opportunity from the tech perspective, as well as the challenges from the defensive perspective. Essentially, the session tokens are what the name implies. They're post-authentication representing a valid authentication session. And it's really an opportunity for us to hijack and use them and gain access to existing authenticated sessions. And if I, as an attacker, have access to an endpoint, say a GCP administrator's device, those cached accounts and environments are easily accessible to me. And that's what we're going to go through. At the end of the day, it's all about persistence, as well as evading detection from the attacker's perspective. Now, the defensive side, what is interesting are some of the challenges. Some of the controls such as MFA don't quite help, although you might counterintuitively, you might think they do, right? And we'll go through that. And in terms of securing the environment, there's a lot of options that are confusing, easy to misconfigure, and also easily misunderstood. So at the end of the day, we're talking about how do you handle incident response? What's your playbook for ops? Is it fully up to date with the most optimal measures or controls? So let's start with just a brief overview of OAuth. Okay, just really briefly, there's some verbiage on this slide, but focus on the right hand diagram. At a very high level, there's a simplified flow, no matter how you authenticate. First, you'll request a token, it'll be signed with your credentials, you'll request scopes or permissions. And as a user, you often see this when you first authenticate with gcloud or CLI. By default, a browser is launched, you have to go type in your Google credentials, you also have to approve the actual scopes being requested. And if that goes properly, then what is returned ultimately to the requester, in this case, it'd be the CLI, would be two important things, the access session token, that's an OAuth session token, as well as a refresh token. The access token is good for an hour. By default, you use it directly in API calls, they all take OAuth tokens. After the hour is up, you can refresh and get a new one. So gcloud, gsutil, CLI tools do this automatically, you usually don't see this level of the protocol in the handshake. The local language SDK libraries like Python, etc, also do this transparently. So generally, your code is not at this level. If you do direct REST API calls, you will see this handshake and have to go through two or three back and forths. The other important thing to remember about OAuth, besides this handshake and the access and refresh tokens, is that, well, you don't authenticate every time you use the CLI, right? It's cached. All session tokens almost everywhere in every model and architecture are cached. In this case, it's in the SQLite database and has big implications for this talk. So let's continue on and let's actually start talking about an attack scenario and we'll jump to the command line to demonstrate this. Okay, a bit of a busy diagram. Focus on what we're assuming is we have access to an endpoint device, a client device, where a GCP admin has been using the CLI, gcloud gsutil. What we're going to do is access that. Once we have access, we'll access that and look at the cached accounts, utilize it, access the GCP environment that the admin that user has previously accessed. Then we're going to copy the credentials, move it off board to a different host under my control, me, the attacker, and then we'll show how to access it from there. Okay, so I've got a split screen shell environment. Left is the target host. The right will be an additional attacker host. Let me explain a few things. This is video just recorded in the past day. I have obfuscated host names, IDs, a lot of unique things, but this was run against a live GCP environment. We're going through the attack scenario, but just a few notes on the defensive side, which will come into play in the second half of this presentation. MFA is enabled for the environments that we'll be looking at. Okay, just keep that in mind. And initially, it was a number of weeks since access was initially configured for these environments. So let's jump into it. If I have access to my target host, I can, of course, run gcloud commands as that user. And I can check with auth list what accounts are configured. Two accounts, user dev MFA, admin at prod MFA, named to give us a hint. One's a production environment. Others are dev. Both have MFA enabled. In fact, there's a hardware key on the prod environment. There's software MFA on the dev one. So I've got some comments along the way, but I'm going to highlight the bold white commands. All right, I can switch accounts with gcloud config set account. Let's switch the admin prod account. That's interesting. All right, switch is over. Let's see if I can actually access it. Let me list the projects. Boom. Let me list the buckets in the project. I get a bucket. Let me enumerate the bucket. Okay, let's pause here. Okay, if you're an admin, normally using gcloud, gsutil, this is boring. This is what you do every day. What makes this interesting is the attacker perspective within the context of the actual environments. As I mentioned, the environments have MFA enabled. And as we'll see as we get further along, these accounts were actually configured quite a while ago. The production account was added back in June, maybe six, seven weeks ago, right? So essentially, in this environment, this live environment, I have cached access to a production account. And as an attacker, it was easy, right? Just no authentication required six weeks later, seven weeks later, despite things like MFA. Let's continue on. All right, so what I want to do now is I want to exfiltrate this whole cache, move it off host, right? So what I'm going to do is go to the location of cache. It's in your home directory dot config in a gcloud subdirectory on Unix. Windows has its own corresponding directory. I'm going to tar it up, I'll SCP it off board, and then I'm going to switch to the right side. Okay, so focus on this other host, where I've SCP the tarball. And what I'm going to do is, so far, I'm just checking my environment. I haven't done anything yet. All right. I'm going to show that there's no accounts configured, right? It's empty, no credential accounts. I'm going to take that tarball, unpack it in my own dot config directory. And boom, right off. At least the configuration matches, right? Shows exactly the state. Now, the note to self right here is, that was easy. Way too easy. There's no device-specific encryption, obviously, or any kind of tagging in this data. So it transparently carries over, and I don't have to do anything except place it in the same directory. Let's see if it's actually useful and valid. I can switch accounts. Again, different host, same credential file copied over. I can switch accounts to that prod account. I can list the same production bucket, right? Way too easy, all right? The commands, nothing special in the commands. This is really a lesson in how easy it is to access and exfiltrate and reuse the credentials in bulk for CLI access, which is pretty much gives me everything, all right? So just to deepen our understanding, a variation of this attack actually makes use of the OAuth tokens in the gcloud subdirectory, all right? What we're going to do is go through a flow where we actually extract something from the SQLite databases holding the cached tokens. We're going to use that and perform some of the OAuth flow, which is request a new access token, because most likely that the last access token used has expired. It only lasts an hour. Get a new access token, which gives me another hour, and then start making API calls. Okay, so let's continue on, right? What I'm going to do, and this is going to get a bear with me as we go through this video and I highlight things, all right? In the gcloud subdirectory where my token cache is stored, there are two .db files. They're SQLite database files, unencrypted, nothing special. What I can do is do a SQLite command, all right? I'm not going over the schema particularly. There are sources for that, but there's a simple table that has the last used or last retrieved access token by account. So I'm pulling the one with associated with the production account. There it is, the YA-29. All right, we'll continue on. Now that I have that, I want to look at the other database, which is credentials.db. This has more information in a big JSON blob. I'm also going to look at what's associated with the production admin account here and I have more information. I have a client ID and secret, which is related to OAuth and the protocol, but it's needed if I want to perform the whole OAuth flow myself. I have the refresh token, so that's useful. I need that. Also, I have access token repeated. Just note that this information is from my initial authentication configuration of this production account. So technically, if you take this epoch time with this EXP field, you run it through date and convert it, you'll get a June 17th date. So what I said is this is a live environment configured six, seven weeks ago and I haven't changed it yet and had default security settings and seven weeks later still have access to it easily. All right, so let's move on. Basically, I want to get that refresh token, right? So I just did a little sedgrep foo on that same SQLite entry with the JSON above and pulled out that access token. Now I'm just going to do a little cURL REST API calls to go through the OAuth flow, all right? And the actual cURL command will be shown, but I'm using the refresh token. So let's see if I can pause this. Here's this cURL command right here in the screen. You can see that the client ID and secret and that refresh token are passed in as post parameters. I've got scope permissions I'm requesting. The cloud platform one is key, but some other IAM type scope as well. The endpoint is OAuth. And what I get back is a fresh new access token right here, okay? Now, good for an hour. Now, what can I do with that new access token? I can do real API calls. So let's continue on. I'm going to do another cURL command. Let's pause it once the output comes back. All right, here we go. So what did I do? Here's the cURL command at the top, right, with that fresh new access token. I happen to choose a fairly easy API, the storage API, and I'm using the same requesting listing of the same bucket that I had done in the first scenario. And the JSON that's returned shows that I'm accessing it, right? Same pass, credit card, sensitive bucket, so on. So all in all, it just shows that I can do a variation at a deeper level, actually perform the OAuth flow. And although functionally, this is, in terms of an ATT&CK perspective, it's not that different from the CLI since they're pretty much equivalent to doing direct API calls. This is more flexible in that I can spin up my own script and code and have somewhat tighter ATT&CK opportunities here. So the lesson from this is, either way, it's really easy to access the token cache and make use of it, and in a lot of cases, generate new tokens and access what environments have been cached. So if that's all there were to this, that might be more limiting. And really, though, there's some related areas with service accounts and compute instances that I want to talk about, right? More opportunities on the ATT&CK side, more hassle from the defensive viewpoint. We've been talking a lot about user accounts in the cache, and one might normally think that service accounts wouldn't really be that valuable to look at on a compromised host. Why? Because if the target host is external to GCP, most likely what's happened is a service account key file has been generated when you generated a key, and that's been downloaded. And that JSON file can then be used within API code, but it can also be used within the CLI. We can activate and add that to our gcloud config and then switch to it as an account and start executing commands as that service account. But because a key file is very likely still on that client, that's a better target for me as an attacker, right? Because it's a full-blown credential and I can do anything with that, as opposed to having a temporary OAuth token that expires in an hour. However, as we'll see later on the defensive side, it is useful to grab this whole cache, including what would be the OAuth session tokens for the service accounts, if they've been configured, because it gives us persistence. We'll find that a lot of remediation commands that we try with service accounts disable the service account, but they leave the tokens valid, meaning it's a way to have additional access, even though the defender is remediating and revoking the service account access. All right, so for that reason alone, there's this variation where OAuth tokens for service accounts on an external client are still valuable to grab from an attack perspective. Speaking of service accounts, well, if they, you know, compute instances run as a service account, to be more secure, there's no key file there if you want to run code on that VM as that service account. What you do is you query the metadata service and you get an OAuth token that your scripts or code can use, and that way you have no key file that's lying around to be compromised. So that's an easy REST call. The URL is internal, resolves to a non-routable local IP. What we get back is an access token at which we can use in a second API call, as an example of a storage call again. What does that look like? Sorry, it's weird. Okay, sorry, getting a little click problems here. What does that look like? Well, you can see the curl command, okay? What it returns is this access token highlighted in blue, looking at the right side, right? The expiration date is a little bit less than an hour, basically. I'm sort of midstream, 400 or so seconds, and I'm getting the cache token. But at the end of the hour, it automatically refreshes and I can query it again and get a new token. I can then use that token in a second API call in the storage bucket, boom, it lists it, okay? So I don't even have to worry about caches, etc. I can always access the service account OAuth token if I have compromised the compute instance. And this is really common, right? Compute instances are targets. Once you have access, this is one of the first things that we should look at as attackers and worry about as defenders. Speaking of compute instances, if you have your own compute instances inside the GCP environment, and you install Google Cloud SDK there, everything we've talked about applies there, right? Makes perfect sense. Because you have cached tokens as well. So that becomes a target on the tech side. But what's maybe not so obvious is that our GCP-managed compute instances, if you run Cloud Shell, the whole purpose of that is sort of ease of use. You don't have to worry about a VM or the SDK. Well, the SDK, the latest version is always installed for you. You now have a nice up-to-date environment to do your CLI commands and manage your environment as a defender. Well, from an attacker perspective, that becomes a target as well, because the SDK is installed. There's been some good work, and I recommend if you're interested in this particular area, read Juan Berner's post a year and some ago on backdoors with Google Cloud Shell. Basically, you can install a backdoor shell, you know, one-liner, you can exfiltrate the token cache automatically. So every time someone starts up the Cloud Shell, you get the fresh sort of token dump. And you can move on your merry way. One note about Cloud Shell. Well, how do you access that? You can do it through the Google console, but you can also do it through a gcloud command, right? So you can think that this could be a chain command. If I compromise your endpoint, that's my target outside of GCP, and you use Cloud Shell, I may be able to get into your Cloud Shell environment, install a backdoor, and then continue to have access from this compute instance sort of environment. So this complicates things, right? These are all sort of variations. We're not just talking about your endpoint where you normally do Google Cloud Admin. All right, we're about halfway through. Let's focus to the defensive side. We have a lot to talk about here. Basically, from a prevention viewpoint, put on your blue hats. There are three basic things that I think will help. It is hard, right, to prevent credential compromise. You really can't. How do you know it's compromised versus the normal user? But we can mitigate it. So the number one thing to do is expiration time. IP whitelisting, if you can manage that, is helpful, as well as MFA. And there are some additional topics regarding IP whitelisting that we need to touch base on. Okay, so let's talk about cloud session duration. On the G Suite admin side, which is, you know, the flag already. Anytime I say G Suite admin, and you're a GCP admin, your ear should sort of perk up. It's a different console. If you're a bigger organization, that may be a different team. If you have access to it as a GCP admin, great. This will be familiar to you. But it's a beta feature, about a year old, if I'm correct on that. So people may not know about it. This is one of the most useful things. By default, sessions for SDK access do not expire, never expires. In fact, in the earlier attack scenario, in the prod environment we went into, guess what the default was set to? The default was never expires. It was never changed. You can set it to one to 24 hours. Recommend really short, like one hour for prod environments, maybe eight plus hours for your dev environments, right? When it expires, all access, both console and programmatic, all those sessions are revoked, and anyone accessing the environment has to actually re-authenticate, all right? So this shrinks the window during which you can be compromised. Now, there is a re-authentication method. You have two choices. When they're re-authenticating after the expiration, a password or security key. This is hardware security key. The only thing to note here is if you use something in the middle, like a software MFA, which I have on one of my dev environments, you have to pick a lesser, a less strong method, which is password. Just a note, it means your re-authentication is less secure because it's no longer MFA, and opens up to keyboard logging and losing a password credential. Let's talk about IP whitelisting, the second thing on my list, all right? So still a relatively new feature, but you can do VPC service controls to implement IP whitelist. In the Access Context Manager in Google Cloud, you create a whitelist, specify a bunch of ciders and set up a policy. Please don't be thrown that there's a 1918 address in here. That's my obfuscation in play. This is normally your public IP or cider that you want in your whitelist. Switching over to the VPC service control section, you can specify the APIs and services, everything as an example, attach and reference the actual access level with the whitelist IPs, put it in place. And the next time that someone tries to do a command to the resources inside that perimeter, VPC perimeter, they'll get an error, right? So a different host, different IP, it's not in the whitelist. All good, right? Really good. What's of interest to note is you get sort of a verbose message. Not sure what I think about that from a defensive side, sort of unsettles me, but it's clear that it works. There is more complication when you think about IP whitelisting. It's not just users and what devices they're coming from or what IPs rather. You can manage that, try to enforce VPNs, space that you know, proxies, but you also have to worry about VM instances. And here's where it's harder lifting. Essentially, if you go IP whitelisting, you want to make sure that your VM IPs are also whitelisted so that any API calls that they do are allowed, right? And so there's a couple things to worry about here. It's just the maintenance issue. You could hook into the startup and provisioning of your VMs to make sure that the VMs IP addresses are included automatically in your IP list, especially if you have a lot of VMs or dynamic IPs. Detection, it's not prevention, but a side note, could be done based on logs instead of an explicit whitelist, right? And some of the references below sort of talk about that as a technique, right? So IP whitelisting sort of alternatives are cull from logs, the IPs of VMs that have been started and see if there's anything abnormal in it compared to a whitelist or instead of a whitelist. You can hook in and put in place a man-in-the-middle proxy for metadata, a metadata service, which would give you visibility to anyone querying it for OAuth tokens. And that might be useful to track and determine and see if that's worth monitoring and learning on. Okay, so this is also a bit of a detection piece. But the main point here from a prevention perspective is you have to think about VM instances and ensure that they are whitelisted properly if you go down that route. So there is some work to be done, but if you can accomplish it, then IP whitelisting is very effective at helping you mitigate the issues with any kind of compromised credentials. And I'm going to do a little shout out to the Netflix security team, and I have some references there. And they've blogged quite a while about the work they've done in AWS. A lot of their concepts apply over to GCP and are worth thinking about as we go. Once you have the whitelist in place, of course, you have to make sure it's enforced. So you can do a little CLI foo. And on the right, you can see the definitions of your access levels and policies and check the IPs and make sure they're the right ones. You can check the VPC service parameters and make sure that they're accessing access levels as well. So it's all well and good to have a whitelist, just make sure it's actually enforced and put in place. Let's move to the third area of prevention, MFA. On the G Suite admin side, yellow flag, if you don't have access, is where MFA is controlled. Set it as much and enforce it with your admin users. It'll help mitigate that compromise of credentials during any re-authentication. Okay, let's move to detection. This is a shorter discussion, unfortunately. Behavioral detection is really the problem for compromised credentials. It's difficult, discern differences from valid user actions and behavior unless they do something egregious, like exfiltrate some terabytes. I'm not going to talk about that. I want to talk about if you do or are able to implement IP whitelisting effectively, effectively with low false positives, detecting failed authentications is worth doing, right? And Stackdriver on the right will get a nice entry that we can key off of and monitor. And if we have low enough false positives and it's maintained, it's a good way to get a heads up that there may be a compromised credential being used from an IP. This would cover the scenario where I exfiltrate credentials or tokens and try to use this from an IP that I control, right? The old style way of tacking would be to always do that. If people focus on whitelisting from a defensive viewpoint, it would be interesting to see if, from a tech perspective, we did more follow-up work from the compromised host, because that would still be allowed in this scenario. So we're not dealing with perfection. We're just trying to improve our ability to detect. Okay, we've got to spend some time on remediation, okay? This is complicated. Let me see if I can get through this. There's a basically remediation. I think there's two major things we have to worry about. How do we lock out the account, prevent future access? How do we revoke current access, the current sessions, which are the OAuth access tokens and refresh tokens? User and service accounts are different. So here are some of the commonly available or known options. Let's go through them one by one. It's going to be a little bit of remediation bingo, all right? As we go through this, see if you can pick out or suggest the best option, and I'll tell you mine. All right, user accounts. How do we lock out user accounts? Well, G Suite Admin, okay, G Suite Admin, we can reset password, suspend the user, and reactivate it later, delete the user. They're all effective. They all lock out the user or attacker. We'll pick the lowest impact one. Resetting password, pretty common, works. That's the answer. How about service accounts? Similar, parallel set of options. I can delete the key here. I'm in Google Cloud Console for service accounts, right? G Suite Admin for user accounts, Google Cloud for service accounts. I can disable the service account itself, and I can delete the service account. Which one? They all work. We'll pick the lowest one. Rotate, right? Now, let's get to the tough part. The tough part is revoking current access, and that's the topic of this talk, right? So, let's see of these six suggested options, the last three are the lockout account measures. The first three are potentially common ones that people try or think about. Let's go through them one by one. In G Suite Admin, for a particular user, their security section, there is a sign-in cookies and a reset action. What does this do? It revokes all web sessions immediately. This includes Google Cloud Console. It would also include G Suite, okay? This works. This is good. Include any Google app and service. This is great, except it doesn't do anything about SDK sessions. So, actually, it's only half of a solution. So, we lose. Let's keep going. There's an interesting G Cloud CLI command that you have probably seen or used, auth revoke. It takes an account name, and it will revoke both the access and refresh tokens associated for that user account. It, underneath, calls an API call with this endpoint to revoke the specific token. That also works if you want to call it directly. Sounds great, doesn't it? But it's in the middle of my list, so you know that it actually doesn't work. Here's the problem. It can only be run on the G Cloud client machine. Why? Because you pass in an account name, and it looks in the SQLite database cache to find the token. And that is easily manipulated by the attacker, at a minimum, deleted, right? So, it can't be run anywhere else. Frankly, I don't think any incident responder would trust a compromised client machine for anything, right? Similarly, calling the API itself doesn't help. Why? You need to pass in an OAuth access token or revoke, sorry, refresh token. Those are not logged. They're not accessible. They don't exist anywhere except on the client machine, which is compromised, which is easily manipulated by the attacker. So, it's useless. These are for self-help, for you to clean up your cache and config, nothing else. A one side note, which is a diversion, but the call to revoke token doesn't require authentication. You just pass in this long access and refresh token. It's long enough that you probably can't brute force it, but it's an interesting note that you don't need OAuth to call. Okay, let's cover that lockout service account, sorry, user lockout options, all right? Changing the user password. These all don't work. They don't revoke SDK sessions. There's a narrow case where if you have requested scope for Gmail, then resetting the password would work, but that doesn't apply to us. We would have requested scope probably for just gcloud or SDK access. Suspending user account works temporarily. While the user account is suspended, the tokens will not work. Once, though, it's re-enabled, the tokens will start working again, assuming they have not expired. So, that's not a great solution. Unless you suspend the account for an hour, that would work. Sorry, let me backtrack on that. Deleting user account works, but has high impact, okay? So, these options aren't great. So, this is all yellow. The question is, what's our best option? So, one thing I did not list in the table was there's actually the best option that works and is low impact is to delete the connected application. This is the connected OAuth application in the G Suite admin side. Basically, every time you authenticate and request access, the OAuth application, in this case, we're talking about the Google Cloud SDK, is listed here, as well as this access level, and you can delete it. And deleting it has no big ramifications. It just means next time someone accesses Google Cloud SDK, like through CLI, they're forced to re-authenticate. But once you delete it, at that point in time, all session tokens are revoked. So, it's the answer. That's the bingo. That's the bonus right there, okay? And if you haven't worked with G Suite admin, you wouldn't know about it, or maybe think about it, or if you're not an OAuth jockey, right? In OAuth land, this is pretty common to think about these connections. It just means it's trusted. And once you delete it, it revokes the sessions. All right. Let's talk about the service account. How do we revoke that? Well, do we revoke it? Do we do some of these other lockout measures? Let's jump into it. Well, you might have guessed that the revoke CLI and the API call won't work, because we just went through it for the user account. It definitely doesn't work. You actually get errors here, right, when you try to do the CLI or the API. Outright errors. It just says it doesn't apply. But what's of note is, look in the error, sorry for the verbiage, but look at the error you get back from the CLI from gcloud. It actually hints in the last sentence that there's hope. If you revoke the parent service account, it's supposed to revoke the session, the actual sessions. What does that mean? Well, if you suspend it or delete it, that's true. But the suspend is sort of a half answer, because once you re-enable it, the tokens actually still work. What about the service account key? Revoke it? What's that mean? Well, it means delete the API key. That definitely doesn't work. That's a bug. Bug has been filed. Don't believe it, right? We've already gone through this. This doesn't work. How about the measures to rotate and delete the API key? Look, if you rotate, delete the API key, you can still use OAuth tokens and still access the service login and do actions as the service account. If you disable it, at that point in time, the tokens don't work, but they still exist. So once you re-enable, reactivate the service account, they'll work again. So the solution there is you could suspend for an hour, then re-enable it, because in that hour, tokens will expire. How about deleting service account? Works, just like deleting user account, high impact. So the summary is actually disable for an hour or delete and reprovision. You will choose whichever you're more comfortable with. Whichever gets you back up and running quicker, that you can perform with confidence, without making errors. This isn't great, but there are ways forward, right? And the main thing of this whole slide and the time spent on all the paths that weren't great paths or were dead ends is to make sure we don't waste time on that, especially in the middle of an incident, right? Is to feed this and review our operations playbooks and make sure that we have the right actions for remediation for the different types of accounts. So to wrap up in the next minute or so and at the end, we went over a bunch of attack scenarios, right? Definitely user accounts and the cache on an external client. That's really what we focused on. But don't forget that service accounts also cache the access token and that an attacker would want to grab that because it helps them maintain persistence in the light of all those remediation actions that don't quite work. But it's not just external clients. If you switch to a Compute Engine environment and you've installed SDK, all the same things apply. And it's not just things that you explicitly start. Remember to think about Cloud Shell, which starts up a VM in the back with the latest SDK installed, right? These are all having the same cache token kinds of exposure and opportunity. And fifth, last but not least, the fifth area is even if SDK is not installed, right? Compute Engine compromise, OAuth tokens for that service account are easily queried from the metadata service and can allow the attacker access as well as persistence for that access. And from a defensive measure, real quick summary after that long sort of part of the presentation, do three things on the prevention side. The no-brainer is set your session timeout in G Suite. If you can, implement IP whitelisting with service controls and set your MFA so that these all mitigate credential compromise in some way. And if you do do that IP whitelisting, then you can improve your detection by detecting the failed authorizations. From a remediation perspective for user accounts, reset the password to lock it out and delete the OAuth connected app in G Suite. That's the key one that may not be obvious to everyone. For service accounts, pick your poison. One of two, disable reactivate within our time period or delete, recreate, reprovision. If you have that automated, just make sure and want to get up and running faster. Just have to worry about VMs, compute instances, anything using those service accounts. So that is the end and I will sort of ask Jaron to see if we have any time for questions. Otherwise, you can always reach me directly as well. Yeah, we have one question from Eric. Do you know of any blogs or white papers that people can use to replicate the OAuth token hijacking that you showed earlier? Yes, so there are some resources for sure. We will be blogging over the next week or two a lot of the details from this presentation. So you'll actually be able to recreate what's seen in the video with actual commands. But there's been prior work as well. So if you search on G Cloud, I want to say if I have the name right, I didn't reference in the presentation, I'll have to add that later. But John Haney has, I believe I have his name right, has done some early work on just peeling apart the SQL databases and some of the REST API calls. And that's a useful resource. It's not documented well, particularly, but it's also not hard to delve into it. So both our blogs should be released in part, I think today, as well as over the next two weeks, as well as there's some prior work if you search on some of the keywords like the G Cloud, the dot config, the SQL light database names.