
PowerShell SharePoint 추출 + 감사 도구로, 레드/블루/퍼플 팀을 위한 것입니다. 사용자가 Microsoft Graph를 통해 액세스할 수 있는 모든 SharePoint 사이트/드라이브를 열거하고, 파일을 재귀적으로 다운로드하며, 모든 Graph + SharePoint HTTP 요청을 기록하여 SIEM 상관 관계 분석, 탐지 엔지니어링 및 IR 테스트에 활용합니다.
SharePointDumper는 사용자가 Microsoft Graph를 통해 액세스할 수 있는 SharePoint 사이트를 열거하고 SharePoint를 통해 파일을 다운로드하는 PowerShell 기반 추출 및 감사 유틸리티입니다.
SOC/DLP 테스트, 퍼플 팀 활동, 비정교한 레드팀 평가를 위해 설계되었으며, 따라서 다운로드된 파일 및 SIEM 상관 분석을 위한 모든 HTTP 요청(Graph + SharePoint)을 포함한 상세 보고서를 생성합니다.
이 도구는 인증을 수행하지 않습니다. 대신 적절한 Microsoft Graph 권한(Sites.Read.All 또는 Sites.ReadWrite.All)이 있는 이미 획득한 OAuth2 액세스 토큰이 필요합니다.
이러한 토큰을 얻는 데 도움이 필요하면 EntraTokenAid를 사용할 수 있습니다(아래 예제 포함). 이는 사용 가능한 액세스 토큰을 간편하게 생성합니다.
실행 화면:

CSV API 로그 예시(CSV 또는 JSON 가능):

파일 다운로드 로그 예시(CSV 또는 JSON 가능):

git clone https://github.com/zh54321/SharePointDumper.git
cd SharePointDumper
SharePointDumper는 사이트 및 파일을 열거하기 위해 위임된 권한이 있는 유효한 Microsoft Graph 액세스 토큰이 필요합니다.
Sites.Read.All 또는Sites.ReadWrite.All또한 OAuth 클라이언트가 SharePoint API를 호출할 수 있어야 합니다.
23개 이상의 Microsoft 자사 애플리케이션에 이미 Sites.Read… 권한이 사전 동의되어 있습니다. 이들은 SharePoint에서 파일을 다운로드할 수 있으며 추가 테넌트 구성 없이 유효한 토큰을 얻는 데 사용될 수 있습니다.
가능하면 CAE 지원 액세스 토큰을 사용하세요. 이 토큰은 최대 24시간 동안 유효하며 장기 덤프 중 중단을 줄여줍니다.
EntraTokenAid를 사용하여 PowerShell을 통해 적합한 액세스 토큰을 얻을 수 있습니다(CAE 토큰은 기본적으로 요청됨):
# 모듈 복제
git clone https://github.com/zh54321/EntraTokenAid.git
Import-Module EntraTokenAid/EntraTokenAid.psm1
# 토큰 가져오기
$tokens = Invoke-Auth -ClientID 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob'
# 선택 사항: 아래 예제와 호환되는 변수에 저장
$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
지터 포함:
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -RequestDelaySeconds 2 -Variation 3
.\Invoke-SharePointDumper.ps1 -AccessToken $accesstoken -Resume -OutputFolder .\20251121_1551_MyTenant
재개 모드에서는 -OutputFolder가 이전 실행의 폴더를 가리켜야 합니다.
SharePointDumper는 갱신 토큰과 EntraTokenAid를 사용하여 만료된 액세스 토큰(HTTP 401)을 자동으로 갱신할 수 있습니다.
# 필수: 도구가 Invoke-Refresh 명령을 사용할 수 있도록 모듈을 가져와야 함
Import-Module .\EntraTokenAid\EntraTokenAid.psm1
# 선택 사항: EntraTokenAid를 사용하여 토큰 얻기(다른 방법도 가능)
$tokens = Invoke-Auth -ClientId 'b26aadf8-566f-4478-926f-589f601d9c74' -RedirectUrl 'urn:ietf:wg:oauth:2.0:oob'
# 갱신 지원으로 SharePointDumper 실행
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74'
참고: 토큰 갱신 시도는 API 로그에 기록되지 않습니다.
20261115_MySecureTenant/
├── SharePointDumper_Report_20261115_080333.txt
├── SharePointDumper_ApiLog_20261115_080333.csv
├── SharePointDumper_FileLog_20261115_080333.csv
├── Site A/
│ └── Documents/
│ ├── file1.docx
│ └── file2.pdf
└── Site B/
└── Site Assets/
Report_*.txt)ApiLog_*.csv 또는 .json)SharePointDumper_ReportResume_*SharePointDumper_ApiLogResume_*액세스 토큰이 잘못되었거나 만료되었습니다.
액세스 토큰은 유효하지만 필요한 Microsoft Graph 또는 SharePoint 권한이 없습니다.
SharePointDumper 활동은 다음에 기록됩니다:
/organization, /sites, /drives).UAL 예시:

Graph 활동 로그 예시:

MIT 라이선스에 따라 배포됩니다.
| 앱 이름 | 클라이언트 ID | FOCI | 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' |
| OneDrive iOS App | 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' |
| Office voice transcript generator 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' |
| Azure AI Studio App | 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' |
| Microsoft Loop App | 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' |
| 매개변수 | 필수 | 유형 | 설명 |
|---|
AccessToken | 예 | String | OAuth2 액세스 토큰. 도구 내에서 인증이 수행되지 않음. |
OutputFolder | 아니오 | String | 덤프 디렉터리. 기본값: ".". -Resume 모드에서는 기존 이전 덤프 폴더를 가리켜야 함. |
UserAgent | 아니오 | String | 모든 HTTP 요청에 대한 사용자 지정 UserAgent. 기본값: SharePointDumper |
Proxy | 아니오 | String | 선택적 HTTP 프록시(예: http://127.0.0.1:8080). |
IncludeExtensions | 아니오 | String[] | 이 확장자만 다운로드합니다. |
ExcludeExtensions | 아니오 | String[] | 이 확장자를 건너뜁니다(IncludeExtensions가 사용되면 무시됨). |
IncludeSites | 아니오 | String[] | 이 값과 일치하는 사이트만 처리합니다. |
ExcludeSites | 아니오 | String[] | 이 값과 일치하는 사이트를 건너뜁니다. |
DisableIpLookup | 아니오 | Switch | 공용 IP에 대해 ifconfig.me를 쿼리하지 않습니다. |
RequestDelaySeconds | 아니오 | Double | 각 HTTP 요청 전 기본 지연 시간. |
Variation | 아니오 | Double | 기본 지연 시간에 추가되는 무작위 지터. |
MaxFiles | 아니오 | Int | 다운로드할 최대 파일 수. 기본값: 제한 없음. |
MaxTotalSizeMB | 아니오 | Double | 최대 총 다운로드 크기. 기본값: 제한 없음. |
Resume | 아니오 | Switch | 이미 다운로드된 파일을 건너뜁니다. -OutputFolder가 필요합니다. |
ApiLogFormat | 아니오 | String | Csv(기본값), Json 또는 None. |
ApiLogPath | 아니오 | String | API 로그 파일의 사용자 지정 출력 경로. |
FileLogFormat | 아니오 | String | Csv(기본값), Json 또는 None. |
FileLogPath | 아니오 | String | 파일 로그 파일의 사용자 지정 출력 경로. |
LogDownloadTokens | 아니오 | Switch | tempauth 토큰을 포함한 전체 SharePoint 다운로드 URL을 기록합니다(안전하지 않음). 기본값: 토큰은 편집됩니다. |
RefreshToken | 아니오 | String | HTTP 401 발생 시 자동 액세스 토큰 갱신에 사용되는 OAuth2 갱신 토큰. |
RefreshClientId | 아니오 | String | -RefreshToken과 함께 사용되는 클라이언트 ID. |
RefreshTenant | 아니오 | String | 갱신 엔드포인트의 테넌트 기관(기본값: common). |