Internal Network Pentest and IR Reference: azure access and token

# Azure AD - Access and Tokens

## Connection

When you authenticate to the Microsoft Graph API in PowerShell/CLI, you will be using an application from a Microsoft's tenant.

* [Microsoft Applications ID](https://learn.microsoft.com/fr-fr/troubleshoot/azure/active-directory/verify-first-party-apps-sign-in)
* [Entra ID First Party Apps & Scope Browser](https://entrascopes.com/)

| Name                       | Application ID                       |
|----------------------------|--------------------------------------|
| Microsoft Azure PowerShell | 1950a258-227b-4e31-a9cf-717495945fc2 |
| Microsoft Azure CLI        | 04b07795-8ddb-461a-bbee-02f9e1bf7b46 |
| Portail Azure              | c44b4083-3bb0-49c1-b47d-974e53cbdf3c |

After a successfull authentication, you will get an access token.

### az cli

* Login with credentials

    ```ps1
    az login -u <username> -p <password>
    az login --service-principal -u <app-id> -p <password> --tenant <tenant-id>
    ```

* Get token

    ```ps1
    az account get-access-token
    az account get-access-token --resource-type aad-graph
    ```

Whoami equivalent: `az ad signed-in-user show`

### Azure AD Powershell

* Login with credentials

    ```ps1
    $[CREDENTIAL_REDACTED]-SecureString "<PASSWORD>" -AsPlainText -Force
    $creds = New-Object System.Management.Automation.PSCredential("test@<TENANT NAME>.onmicrosoft.com", $passwd)
    Connect-AzureAD -Credential $creds
    ```

### Az Powershell

* Login with credentials

    ```ps1
    $[CREDENTIAL_REDACTED]-SecureString "<PASSWORD>" -AsPlainText -Force
    $creds = New-Object System.Management.Automation.PSCredential ("<USERNAME>@<TENANT NAME>.onmicrosoft.com", $passwd)
    Connect-AzAccount -Credential $creds
    ```

* Login with service principal secret

    ```ps1
    $[CREDENTIAL_REDACTED]-SecureString '<SECRET>' -AsPlainText -Force
    $creds = New-Object System.Management.Automation.PSCredential('<APP-ID>', $password)
    Connect-AzAccount -ServicePrincipal -Credential $creds -Tenant 29sd87e56-a192-a934-bca3-0398471ab4e7d

    ```

* Get token

    ```ps1
    (Get-AzAccessToken -ResourceUrl https://graph.microsoft.com).Token
    Get-AzAccessToken -ResourceTypeName MSGraph
    ```

### Microsoft Graph Powershell

* Login with credentials

    ```ps1
    Connect-MgGraph
    Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All"
    ```

* Login with device code flow

    ```ps1
    Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -UseDeviceAuthentication
    ```

Whoami equivalent: `Get-MgContext`

### External HTTP API

* Login with credentials

    ```ps1
    # TODO
    ```

#### Device Code

Request a device code

```ps1
$body = @{
    "client_id" =     "1950a258-227b-4e31-a9cf-717495945fc2"
    "resource" =      "https://graph.microsoft.com"
}
$UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
$Headers=@{}
$Headers["User-Agent"] = $UserAgent
$authResponse = Invoke-RestMethod `
    -UseBasicParsing `
    -Method Post `
    -Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" `
    -Headers $Headers `
    -Body $body
$authResponse
```

Go to device login [microsoft.com/devicelogin](https://login.microsoftonline.com/common/oauth2/deviceauth) and input the device code. Then ask for an access token.

```ps1
$body=@{
    "client_id" =  "1950a258-227b-4e31-a9cf-717495945fc2"
    "grant_type" = "urn:ietf:params:oauth:grant-type:device_code"
    "code" =       $authResponse.device_code
}
$Tokens = Invoke-RestMethod `
    -UseBasicParsing `
    -Method Post `
    -Uri "https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0" `
    -Headers $Headers `
    -Body $body
$Tokens
```

#### Service Principal

* Request an access token using a **service principal password**

    ```ps1
    curl --location --request POST 'https://login.microsoftonline.com/<tenant-name>/oauth2/v2.0/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id=<client-id>' \
    --data-urlencode 'scope=https://graph.microsoft.com/.default' \
    --data-urlencode 'client_secret=<client-secret>' \
    --data-urlencode 'grant_type=client_credentials'
    ```

#### App Secret

An App Secret (also called a client secret) is a string used for securing communication between an application and Azure Active Directory (Azure AD). It is a credential that the application uses along with its client ID to authenticate itself when accessing Azure resources, such as APIs or other services, on behalf of a user or a system.

```ps1
$appid = '<app-id>'
$tenantid = '<tenant-id>'
$secret = '<app-secret>'
 
$body =  @{
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    Client_Id     = $appid
    Client_Secret = $secret
}
 
$connection = Invoke-RestMethod `
    -Uri https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token `
    -Method POST `
    -Body $body

Connect-MgGraph -AccessToken $connection.access_token
```

### Internal HTTP API

> **MSI_ENDPOINT** is an alias for **IDENTITY_ENDPOINT**, and **MSI_SECRET** is an alias for **IDENTITY_HEADER**.

Find `IDENTITY_HEADER` and `IDENTITY_ENDPOINT` from the environment variables: `env`

Most of the time, you want a token for one of these resources:

* <https://graph.microsoft.com>
* <https://management.azure.com>
* <https://storage.azure.com>
* <https://vault.azure.net>

* PowerShell

    ```ps1
    curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
    curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
    ```

* Azure Function (Python)

    ```py
    import logging, os
    import azure.functions as func

    def main(req: func.HttpRequest) -> func.HttpResponse:
        logging.info('Python HTTP trigger function processed a request.')
        IDENTITY_ENDPOINT = os.environ['IDENTITY_ENDPOINT']
        IDENTITY_HEADER = os.environ['IDENTITY_HEADER']
        cmd = 'curl "%s?resource=https://management.azure.com&apiversion=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)
        val = os.popen(cmd).read()
        return func.HttpResponse(val, status_code=200)
    ```

## Access Token

An access token is a type of security token issued by Azure Active Directory (Azure AD) that grants a user or application permission to access resources. These resources could be anything from APIs, web applications, data stored in Azure, or other services that are integrated with Azure AD for authentication and authorization.

Decode access tokens: [jwt.ms](https://jwt.ms/)

* Use the access token with **MgGraph**

    ```ps1
    # use the jwt
    $token = "eyJ0eXAiO..."
    $secure = $token | ConvertTo-SecureString -AsPlainText -Force
    Connect-MgGraph -AccessToken $secure
    ```

* Use the access token with **AzureAD