
Strumento PowerShell di estrazione e audit per team red/blue/purple. Enumera tutti i siti/drive di SharePoint a cui un utente può accedere tramite Microsoft Graph, scarica ricorsivamente i file e registra ogni richiesta HTTP di Graph e SharePoint per correlazione SIEM, ingegneria del rilevamento e test IR.
SharePointDumper è un'utilità di estrazione e auditing basata su PowerShell che enumera i siti SharePoint a cui un utente ha accesso tramite Microsoft Graph e scarica i file tramite SharePoint.
È progettato per test SOC/DLP, purple teaming e valutazioni red-team non sofisticate, e pertanto produce report dettagliati che includono i file scaricati e ogni richiesta HTTP (Graph + SharePoint) per la correlazione SIEM.
Lo strumento non esegue l'autenticazione. Richiede invece un token di accesso OAuth2 già ottenuto con le autorizzazioni appropriate di Microsoft Graph (Sites.Read.All o Sites.ReadWrite.All).
Se hai bisogno di aiuto per ottenere tale token, puoi utilizzare EntraTokenAid (esempi inclusi di seguito), che semplifica la generazione di token di accesso utilizzabili.
Esecuzione:

Esempio di registro API CSV (può essere CSV o JSON):

Esempio di registro download file (può essere CSV o JSON)

git clone https://github.com/zh54321/SharePointDumper.git
cd SharePointDumper
SharePointDumper richiede un token di accesso Microsoft Graph valido con autorizzazioni delegate per enumerare siti e file:
Sites.Read.All oppureSites.ReadWrite.AllInoltre, il client OAuth deve essere autorizzato a chiamare l'API SharePoint.
Più di 23 applicazioni Microsoft di prima parte hanno già autorizzazioni Sites.Read… pre-consentite. Possono scaricare file da SharePoint e possono essere utilizzate per ottenere un token valido senza ulteriore configurazione del tenant.
Se possibile, utilizza un token di accesso abilitato per CAE, che rimane valido fino a 24 ore e riduce le interruzioni durante dump di lunga durata.
Puoi utilizzare EntraTokenAid per ottenere un token di accesso adatto tramite PowerShell
(i token CAE sono richiesti per impostazione predefinita):
# Clona il modulo
git clone https://github.com/zh54321/EntraTokenAid.git
Import-Module EntraTokenAid/EntraTokenAid.psm1
# Ottieni i token
$tokens = Invoke-Auth -ClientID 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob'
# Opzionale: salva in una variabile compatibile con gli esempi seguenti
$AccessToken = $tokens.access_token
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -UserAgent "Not SharePointDumper"
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -IncludeSites "Finance","Projects"
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -ExcludeSites "HR","Legal"
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -IncludeExtensions pdf,docx
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -ExcludeExtensions jpg,bmp
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -MaxFiles 500
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -MaxTotalSizeMB 100
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -RequestDelaySeconds 2
Con jitter:
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -RequestDelaySeconds 2 -Variation 3
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -Resume -OutputFolder .\20251121_1551_MyTenant
In modalità ripresa, -OutputFolder deve puntare alla cartella dell'esecuzione precedente.
SharePointDumper può aggiornare automaticamente un token di accesso scaduto (HTTP 401) utilizzando un token di aggiornamento ed EntraTokenAid.
# Obbligatorio: il modulo deve essere importato affinché lo strumento possa utilizzare il comando Invoke-Refresh
Import-Module .\EntraTokenAid\EntraTokenAid.psm1
# Opzionale: ottieni i token utilizzando EntraTokenAid (sono possibili anche altri metodi)
$tokens = Invoke-Auth -ClientId 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob'
# Esegui SharePointDumper con supporto aggiornamento
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74'
Nota: i tentativi di aggiornamento del token NON vengono registrati nel registro API.
20261115_MySecureTenant/
├── SharePointDumper_Report_20261115_080333.txt
├── SharePointDumper_ApiLog_20261115_080333.csv
├── SharePointDumper_FileLog_20261115_080333.csv
├── Sito A/
│ └── Documenti/
│ ├── file1.docx
│ └── file2.pdf
└── Sito B/
└── Risorse del sito/
Report_*.txt)ApiLog_*.csv o .json)SharePointDumper_ReportResume_*SharePointDumper_ApiLogResume_*Il token di accesso non è valido o è scaduto.
Il token di accesso è valido, ma mancano le autorizzazioni Microsoft Graph o SharePoint richieste.
Le attività di SharePointDumper vengono registrate in:
/organization, /sites, /drives).Esempio UAL:

Esempio registro attività Graph:

Rilasciato sotto la Licenza MIT.
| Nome App | ID Client | FOCI | Comando Auth EntraTokenAid |
|---|
| Microsoft Teams | 1fec8e78-bce4-4aaf-ab1b-5451cc387264 | TRUE | $tokens = Invoke-Auth -ClientID '1fec8e78-bce4-4aaf-ab1b-5451cc387264' -RedirectUrl 'https://login.microsoftonline.com/common/oauth2/nativeclient' |
| Outlook Mobile | 27922004-5251-4030-b22d-91ecd9a37ea4 | TRUE | $tokens = Invoke-Auth -ClientID '27922004-5251-4030-b22d-91ecd9a37ea4' -RedirectUrl 'x-msauth-outlook-prod://com.microsoft.Office.Outlook' |
| OneDrive SyncEngine | ab9b8c07-8f02-4f72-87fa-80105867a763 | TRUE | $tokens = Invoke-Auth -ClientID 'ab9b8c07-8f02-4f72-87fa-80105867a763' -RedirectUrl 'https://login.microsoftonline.com/common/oauth2/nativeclient' |
| App iOS OneDrive | af124e86-4e96-495a-b70a-90f90ab96707 | TRUE | $tokens = Invoke-Auth -ClientID 'af124e86-4e96-495a-b70a-90f90ab96707' -RedirectUrl 'ms-onedrive-auth://com.microsoft.skydrive.shareextension' |
| Microsoft Bing Search | cf36b471-5b44-428c-9ce7-313bf84528de | TRUE | $tokens = Invoke-Auth -ClientID 'cf36b471-5b44-428c-9ce7-313bf84528de' -RedirectUrl 'msauth.com.microsoft.bing://auth' |
| OneDrive | b26aadf8-566f-4478-926f-589f601d9c74 | TRUE | $tokens = Invoke-Auth -ClientID 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob' |
| SharePoint | d326c1ce-6cc6-4de2-bebc-4591e5e13ef0 | TRUE | $tokens = Invoke-Auth -ClientID 'd326c1ce-6cc6-4de2-bebc-4591e5e13ef0' -RedirectUrl 'msauth://code/ms-sharepoint-auth%3A%2F%2Fcom.microsoft.sharepoint' |
| SharePoint Android | f05ff7c9-f75a-4acd-a3b5-f4b6a870245d | TRUE | $tokens = Invoke-Auth -ClientID 'f05ff7c9-f75a-4acd-a3b5-f4b6a870245d' -RedirectUrl 'msauth://com.microsoft.sharepoint/gSoqzhbCjkyvI%2Fl7kC7IdG7KbPU%3D' |
| OfficeHome | 4765445b-32c6-49b0-83e6-1d93765276ca | FALSE | $tokens = Invoke-Auth -ClientID '4765445b-32c6-49b0-83e6-1d93765276ca' -RedirectUrl 'https://scuprodprv.www.microsoft365.com/spalanding' -Origin 'https://doesnotmatter' |
| SharePoint Online Web Client Extensibility | 08e18876-6177-487e-b8b5-cf950c1e598c | FALSE | $tokens = Invoke-Auth -ClientID '08e18876-6177-487e-b8b5-cf950c1e598c' -RedirectUrl 'https://onedrive.cloud.microsoft/_forms/spfxsinglesignon.aspx' -Origin 'https://doesnotmatter' |
| Microsoft Teams Web Client | 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 | FALSE | $tokens = Invoke-Auth -ClientID '5e3ce6c0-2b1f-4285-8d4b-75ee78787346' -RedirectUrl 'https://teams.cloud.microsoft/convene/townhall' -Origin 'https://doesnotmatter' |
| Portfolios | f53895d3-095d-408f-8e93-8f94b391404e | FALSE | $tokens = Invoke-Auth -ClientID 'f53895d3-095d-408f-8e93-8f94b391404e' -RedirectUrl 'https://project.microsoft.com/msal-redirect2' -Origin 'https://doesnotmatter' |
| Microsoft Remote Assist | fca5a20d-55aa-4395-9c2f-c6147f3c9ffa | FALSE | $tokens = Invoke-Auth -ClientID 'fca5a20d-55aa-4395-9c2f-c6147f3c9ffa' -RedirectUrl 'http://localhost:13824' |
| ProcessSimpleGCC | 38a893b6-d74c-4786-8fe7-bc3b4318e881 | FALSE | $tokens = Invoke-Auth -ClientID '38a893b6-d74c-4786-8fe7-bc3b4318e881' -RedirectUrl 'https://make.gov.powerautomate.us/auth-redirect.html' -Origin 'https://doesnotmatter' |
| WindowsShareExperienceProd | a8759234-4b8b-4d94-8c0a-ee1ab73af270 | FALSE | $tokens = Invoke-Auth -ClientID 'a8759234-4b8b-4d94-8c0a-ee1ab73af270' -RedirectUrl 'ms-appx-web://Microsoft.AAD.BrokerPlugin/a8759234-4b8b-4d94-8c0a-ee1ab73af270' |
| Generatore trascrizioni vocali Office AAD | d2eb9fef-f34c-40ec-b6a3-4bf524065158 | FALSE | $tokens = Invoke-Auth -ClientID 'd2eb9fef-f34c-40ec-b6a3-4bf524065158' -RedirectUrl 'msauth.com.microsoft.Office.TestVoice.TestVoice2://auth' |
| Azure OpenAI Studio | dc807dec-d211-4b3f-bc8a-43b3443c4874 | FALSE | $tokens = Invoke-Auth -ClientID 'dc807dec-d211-4b3f-bc8a-43b3443c4874' -RedirectUrl 'https://dev.oai.azure.com' -Origin 'https://doesnotmatter' |
| App Azure AI Studio | cb2ff863-7f30-4ced-ab89-a00194bcf6d9 | FALSE | $tokens = Invoke-Auth -ClientID 'cb2ff863-7f30-4ced-ab89-a00194bcf6d9' -RedirectUrl 'https://int.ai.azure.com/agents' -Origin 'https://doesnotmatter' |
| Azure Machine Learning Workbench Web App | d7304df8-741f-47d3-9bc2-df0e24e2071f | FALSE | $tokens = Invoke-Auth -ClientID 'd7304df8-741f-47d3-9bc2-df0e24e2071f' -RedirectUrl 'https://dev.ml.azure.com/redirect' -Origin 'https://doesnotmatter' |
| M365ChatClient | c0ab8ce9-e9a0-42e7-b064-33d422df41f1 | FALSE | $tokens = Invoke-Auth -ClientID 'c0ab8ce9-e9a0-42e7-b064-33d422df41f1' -RedirectUrl 'https://fa000000128.resources.office.net/f7024bdc-7caf-4ca8-807d-2908f09640d6/1.0.2412.19011/en-us_web/login.html' -Origin 'https://doesnotmatter' |
| App Microsoft Loop | a187e399-0c36-4b98-8f04-1edc167a0996 | FALSE | $tokens = Invoke-Auth -ClientID 'a187e399-0c36-4b98-8f04-1edc167a0996' -RedirectUrl 'https://hosted.loop.cloud.dev.microsoft/authLanding.html' -Origin 'https://doesnotmatter' |
| Viva Goals | c8423563-e8f6-49f2-924b-90d9f664378a | FALSE | $tokens = Invoke-Auth -ClientID 'c8423563-e8f6-49f2-924b-90d9f664378a' -RedirectUrl 'https://goals-ppe.microsoft.com/aad/consume' -Origin 'https://doesnotmatter' |
| Microsoft Mesh | eea619ad-603a-4b03-a386-860fcc7410d1 | FALSE | $tokens = Invoke-Auth -ClientID 'eea619ad-603a-4b03-a386-860fcc7410d1' -RedirectUrl 'http://localhost:13824' |
| Parametro | Obbligatorio | Tipo | Descrizione |
|---|
AccessToken | Sì | String | Token di accesso OAuth2. Nessuna autenticazione eseguita all'interno dello strumento. |
OutputFolder | No | String | Directory per il dump. Predefinito: ".". In modalità -Resume, deve puntare a una cartella di dump esistente precedente. |
UserAgent | No | String | UserAgent personalizzato per tutte le richieste HTTP. Predefinito: SharePointDumper |
Proxy | No | String | Proxy HTTP opzionale (es., http://127.0.0.1:8080). |
IncludeExtensions | No | String[] | Scarica solo queste estensioni. |
ExcludeExtensions | No | String[] | Salta queste estensioni (ignorato se viene utilizzato IncludeExtensions). |
IncludeSites | No | String[] | Elabora solo i siti che corrispondono a uno qualsiasi di questi valori. |
ExcludeSites | No | String[] | Salta i siti che corrispondono a uno qualsiasi di questi valori. |
DisableIpLookup | No | Switch | Non interrogare ifconfig.me per l'IP pubblico. |
RequestDelaySeconds | No | Double | Ritardo base prima di ogni richiesta HTTP. |
Variation | No | Double | Jitter casuale aggiunto al ritardo base. |
MaxFiles | No | Int | Numero massimo di file da scaricare. Predefinito: nessun limite. |
MaxTotalSizeMB | No | Double | Dimensione totale massima di download. Predefinito: nessun limite. |
Resume | No | Switch | Salta i file già scaricati. Richiede -OutputFolder. |
ApiLogFormat | No | String | Csv (predefinito), Json, o None. |
ApiLogPath | No | String | Percorso di output personalizzato per il file di registro API. |
FileLogFormat | No | String | Csv (predefinito), Json, o None. |
FileLogPath | No | String | Percorso di output personalizzato per il file di registro download. |
LogDownloadTokens | No | Switch | Registra gli URL di download completi di SharePoint inclusi i token tempauth (non sicuro). Predefinito: i token sono oscurati. |
RefreshToken | No | String | Token di aggiornamento OAuth2 utilizzato per il rinnovo automatico del token di accesso su HTTP 401. |
RefreshClientId | No | String | ID client utilizzato insieme a -RefreshToken. |
RefreshTenant | No | String | Autorità tenant per l'endpoint di aggiornamento (predefinito: common). |