Category Archives: Security

Phone number used too many times

Recently ran into a new one when setting up MFA for Microsoft 365:

{"Type":6,"VerificationState":0,"Data":null,"VerificationContext":null,"ErrorCode":29,"ErrorType":null}

I can’t prove, but strongly suggest this means the phone number you’re trying to register is in use for too many accounts and/or tenants.

Mass changing link type in Sharepoint or Onedrive

Sharing links in Onedrive/Teams/Sharepoint can be of the View, Edit, Review or No Download type.

There is no official Graph API or PnP module call that can be done to modify a link, it has to be done manually in the GUI as per Microsoft.

That didn’t work for me, as I’m working on some migration scenario’s where all links have to keep working, but should not allow users to edit or download the files.

So I did some digging, turns out there is a ShareLink GetSharingInformation endpoint that can be called for any object.

And with good ‘ol Claude, a script was built and tested in half an hour that iterates over a given sharepoint site(s) or a specific file and adjusts the link. I’ve made it configurable and use certificate based auth, enjoy!

https://github.com/jflieben/assortedFunctionsV2/blob/main/Update-SharingLinks.ps1

Unexpected Onedrive Owners

How do you know who the original owner of a Onedrive site was?

The url says a lot, it’s usually in a username_domain_com format. If you have a fixed naming structure and don’t use _’s or other characters that are translated to _, it can be reversed with reasonable accuracy, right?

But what if you have two people with the same name? Or did some migrations or takeovers? Then your logic breaks 🙁

So reverse engineering the URL won’t work, and if an admin takes ownership or if the user leaves and the manager gets ownership, the Owner/Full Control ACL on the site also won’t tell you who the original owner was because it overwrites the Owner property.

In M365permissions the option to audit ownership of Onedrive is built in, as this is a common question during certain types of audits.

But how did we solve it there?

Well, it turns out that Sharepoint’s own metadata service maintains a pretty good track record of who was ever a user on a site, even after they are deleted from Entra.

Thus by doing a call to /_api/web/siteusers?$orderby=Id, we get a nicely ordered list of all users ever assigned to the site.

Pick the first non-system user, and we have our original user! See above 🙂

Silent provisioning of Fido key to use for headless requests against hidden API’s

So there’s this problem with lots of Microsoft API’s not allowing service principals to call them. I’ve written about this a few times in the past 🙂

These api’s want a user. And a user has to do MFA, right?

Not with this!

When I read Nathan McNulty’s LinkedIn post this morning I got a bit hyped and just HAD to get it working. He has a way to use a stored passkey to log in silently to all admin portals/hidden api’s etc.

The missing part I wanted to solve, is to actually generate that passkey for a given global admin in the tenant.

Took a bit of messing around with how to generate the keys using a virtual authenticator, but it works! Here it is:

https://github.com/jflieben/assortedFunctionsV2/blob/main/New-FidoKey.ps1

So basically:

  1. register app with client id/secret and UserAuthenticationMethod.ReadWrite.All
  2. run New-FidoKey
  3. use the file it outputs with Nathan’s passkey login function

I should also give an honorary mention to Fabian Bader for the work he did to get us here!

disclaimer: don’t store this stuff where anyone can find it!

disclaimer2: you’ll have to set your fido policy to allow not force attestion or key restrictions

Function to Spot ALL All-User and All-Guest Groups in Entra ID

There are probably many scenario’s where you’d like to identify which Entra groups contain ‘all users’, ‘all guests’ or a combination (all members+all guests).

In my case, I want to use this in M365Permissions, but also needed it for a Maester test to be more precise. It had to be language and implementation agnostic.

M365Permissions uses this mainly for reports that look at oversharing (e.g. when securing a tenant or implementing copilot). But this could also be useful for red/blue teams or any other tenant analysis tooling.

In M365Permissions, I initially looked at the dynamic rule itself, but this is unreliable. Dynamic rules can contain many additional components and can be ordered or written in many ways or the group may have been created without a dynamic rule through e.g. automation.

So I decided to use another approach!

Just get all tenant users from Graph (counts per type).

Then for a given group, look if it matches one of those counts and return a type. Of course, casting members to users to avoid counting devices and looking up membership recursively 🙂

Function: https://github.com/jflieben/assortedFunctionsV2/blob/main/Get-EntraDynamicGroupType.ps1